mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
Compare commits
No files matched your search
@@ -13,13 +13,14 @@ env:
|
||||
BUILD_TYPE: Release
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
FEX_FORCE32BITALLOCATOR: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.arch }}
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [[self-hosted, x64], [self-hosted, ARMv8.0], [self-hosted, ARMv8.2]]
|
||||
arch: [[self-hosted, x64], [self-hosted, ARMv8.0], [self-hosted, ARMv8.2], [self-hosted, ARMv8.4]]
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
@@ -116,6 +117,18 @@ jobs:
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC64.log || true
|
||||
|
||||
- name: gcc target tests 32
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the gvisor tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target gcc_target_tests_32
|
||||
|
||||
- name: GCC32 Test Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC32.log || true
|
||||
|
||||
- name: Struct verifier tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
|
||||
@@ -30,3 +30,6 @@
|
||||
shallow = true
|
||||
path = External/fex-gcc-target-tests-bins
|
||||
url = https://github.com/FEX-Emu/fex-gcc-target-tests-bins.git
|
||||
[submodule "External/jemalloc"]
|
||||
path = External/jemalloc
|
||||
url = https://github.com/FEX-Emu/jemalloc.git
|
||||
+26
-12
@@ -61,8 +61,8 @@ endif()
|
||||
|
||||
if (ENABLE_ASAN)
|
||||
add_definitions(-DENABLE_ASAN=1)
|
||||
add_compile_options(-fno-omit-frame-pointer -fsanitize=address)
|
||||
link_libraries(-fno-omit-frame-pointer -fsanitize=address)
|
||||
add_compile_options(-fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope)
|
||||
link_libraries(-fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope)
|
||||
endif()
|
||||
|
||||
if (ENABLE_TSAN)
|
||||
@@ -103,11 +103,16 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
message(FATAL_ERROR "FEX doesn't support getting compiled with GCC!")
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Python 3.0 REQUIRED COMPONENTS Interpreter)
|
||||
pkg_check_modules(XXHASH libxxhash REQUIRED)
|
||||
|
||||
add_definitions(-Wno-trigraphs)
|
||||
add_definitions(-DGLOBAL_DATA_DIRECTORY="${DATA_DIRECTORY}/")
|
||||
|
||||
add_subdirectory(External/jemalloc/)
|
||||
include_directories(External/jemalloc/pregen/include/)
|
||||
|
||||
add_subdirectory(External/cpp-optparse/)
|
||||
include_directories(External/cpp-optparse/)
|
||||
|
||||
@@ -158,18 +163,27 @@ if(ENABLE_WERROR OR ENABLE_STRICT_WERROR)
|
||||
endif()
|
||||
|
||||
if(_M_ARM_64)
|
||||
# Due to an oversight in llvm, it declares any reasonably new Kryo CPU to only be ARMv8.0
|
||||
# Manually detect newer CPU revisions until clang and llvm fixes their bug
|
||||
# This script will either provide a supported CPU or 'native'
|
||||
# Additionally -march doesn't work under AArch64+Clang, so you have to use -mcpu or -mtune
|
||||
execute_process(COMMAND python3 "${PROJECT_SOURCE_DIR}/Scripts/aarch64_fit_native.py" "/proc/cpuinfo"
|
||||
OUTPUT_VARIABLE AARCH64_CPU)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 999999.0)
|
||||
# Clang 12.0 fixed the -mcpu=native bug with mixed big.little implementers
|
||||
# Clang can not currently check for native Apple M1 type in hypervisor. Currently disabled
|
||||
check_cxx_compiler_flag("-mcpu=native" COMPILER_SUPPORTS_CPU_TYPE)
|
||||
if(COMPILER_SUPPORTS_CPU_TYPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
|
||||
endif()
|
||||
else()
|
||||
# Due to an oversight in llvm, it declares any reasonably new Kryo CPU to only be ARMv8.0
|
||||
# Manually detect newer CPU revisions until clang and llvm fixes their bug
|
||||
# This script will either provide a supported CPU or 'native'
|
||||
# Additionally -march doesn't work under AArch64+Clang, so you have to use -mcpu or -mtune
|
||||
execute_process(COMMAND python3 "${PROJECT_SOURCE_DIR}/Scripts/aarch64_fit_native.py" "/proc/cpuinfo" "${CMAKE_CXX_COMPILER_VERSION}"
|
||||
OUTPUT_VARIABLE AARCH64_CPU)
|
||||
|
||||
string(STRIP ${AARCH64_CPU} AARCH64_CPU)
|
||||
string(STRIP ${AARCH64_CPU} AARCH64_CPU)
|
||||
|
||||
check_cxx_compiler_flag("-mcpu=${AARCH64_CPU}" COMPILER_SUPPORTS_CPU_TYPE)
|
||||
if(COMPILER_SUPPORTS_CPU_TYPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=${AARCH64_CPU}")
|
||||
check_cxx_compiler_flag("-mcpu=${AARCH64_CPU}" COMPILER_SUPPORTS_CPU_TYPE)
|
||||
if(COMPILER_SUPPORTS_CPU_TYPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=${AARCH64_CPU}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
+35
@@ -159,7 +159,42 @@ def print_man_environment(options):
|
||||
default
|
||||
)
|
||||
|
||||
print_man_environment_tail()
|
||||
output_man.write(".El\n")
|
||||
|
||||
def print_man_environment_tail():
|
||||
|
||||
# Additional environment variables that live outside of the normal loop
|
||||
print_man_env_option(
|
||||
"FEX_APP_CONFIG_LOCATION",
|
||||
[
|
||||
"Allows the user to override where FEX looks for configuration files",
|
||||
"By default FEX will look in {$HOME, $XDG_CONFIG_HOME}/.fex-emu/",
|
||||
"This will override the full path",
|
||||
],
|
||||
"''")
|
||||
|
||||
print_man_env_option(
|
||||
"FEX_APP_CONFIG",
|
||||
[
|
||||
"Allows the user to override where FEX looks for only the application config file",
|
||||
"By default FEX will look in {$HOME, $XDG_CONFIG_HOME}/.fex-emu/Config.json",
|
||||
"This will override this file location",
|
||||
"One must be careful with this option as it will override any applications that load with execve as well"
|
||||
"If you need to support applications that execve then use FEX_APP_CONFIG_LOCATION instead"
|
||||
],
|
||||
"''")
|
||||
|
||||
print_man_env_option(
|
||||
"FEX_APP_DATA_LOCATION",
|
||||
[
|
||||
"Allows the user to override where FEX looks for data files",
|
||||
"By default FEX will look in {$HOME, $XDG_DATA_HOME}/.fex-emu/",
|
||||
"This will override the full path",
|
||||
"This is the folder where FEX stores generated files like IR cache"
|
||||
],
|
||||
"''")
|
||||
|
||||
def print_man_header():
|
||||
header ='''.Dd {0}
|
||||
.Dt FEX
|
||||
|
||||
+25
-19
@@ -108,10 +108,10 @@ def print_ir_sizes(ops, defines):
|
||||
|
||||
output_file.write("[[maybe_unused]] static size_t GetSize(IROps Op) { return IRSizes[Op]; }\n\n")
|
||||
|
||||
output_file.write("std::string_view const& GetName(IROps Op);\n")
|
||||
output_file.write("uint8_t GetArgs(IROps Op);\n")
|
||||
output_file.write("FEXCore::IR::RegisterClassType GetRegClass(IROps Op);\n\n")
|
||||
output_file.write("bool HasSideEffects(IROps Op);\n")
|
||||
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) std::string_view const& GetName(IROps Op);\n")
|
||||
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) uint8_t GetArgs(IROps Op);\n")
|
||||
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) FEXCore::IR::RegisterClassType GetRegClass(IROps Op);\n\n")
|
||||
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) bool HasSideEffects(IROps Op);\n")
|
||||
|
||||
output_file.write("#undef IROP_SIZES\n")
|
||||
output_file.write("#endif\n\n")
|
||||
@@ -277,7 +277,7 @@ def print_ir_allocator_helpers(ops, defines):
|
||||
output_file.write("\tusing IRPair = Wrapper<T>;\n\n")
|
||||
|
||||
output_file.write("\tIRPair<IROp_Header> AllocateRawOp(size_t HeaderSize) {\n")
|
||||
output_file.write("\t\tauto Op = reinterpret_cast<IROp_Header*>(Data.Allocate(HeaderSize));\n")
|
||||
output_file.write("\t\tauto Op = reinterpret_cast<IROp_Header*>(DualListData.DataAllocate(HeaderSize));\n")
|
||||
output_file.write("\t\tmemset(Op, 0, HeaderSize);\n")
|
||||
output_file.write("\t\tOp->Op = IROps::OP_DUMMY;\n")
|
||||
output_file.write("\t\treturn IRPair<IROp_Header>{Op, CreateNode(Op)};\n")
|
||||
@@ -286,7 +286,7 @@ def print_ir_allocator_helpers(ops, defines):
|
||||
output_file.write("\ttemplate<class T, IROps T2>\n")
|
||||
output_file.write("\tT *AllocateOrphanOp() {\n")
|
||||
output_file.write("\t\tsize_t Size = FEXCore::IR::GetSize(T2);\n")
|
||||
output_file.write("\t\tauto Op = reinterpret_cast<T*>(Data.Allocate(Size));\n")
|
||||
output_file.write("\t\tauto Op = reinterpret_cast<T*>(DualListData.DataAllocate(Size));\n")
|
||||
output_file.write("\t\tmemset(Op, 0, Size);\n")
|
||||
output_file.write("\t\tOp->Header.Op = T2;\n")
|
||||
output_file.write("\t\treturn Op;\n")
|
||||
@@ -295,25 +295,25 @@ def print_ir_allocator_helpers(ops, defines):
|
||||
output_file.write("\ttemplate<class T, IROps T2>\n")
|
||||
output_file.write("\tIRPair<T> AllocateOp() {\n")
|
||||
output_file.write("\t\tsize_t Size = FEXCore::IR::GetSize(T2);\n")
|
||||
output_file.write("\t\tauto Op = reinterpret_cast<T*>(Data.Allocate(Size));\n")
|
||||
output_file.write("\t\tauto Op = reinterpret_cast<T*>(DualListData.DataAllocate(Size));\n")
|
||||
output_file.write("\t\tmemset(Op, 0, Size);\n")
|
||||
output_file.write("\t\tOp->Header.Op = T2;\n")
|
||||
output_file.write("\t\treturn IRPair<T>{Op, CreateNode(&Op->Header)};\n")
|
||||
output_file.write("\t}\n\n")
|
||||
|
||||
output_file.write("\tuint8_t GetOpSize(OrderedNode *Op) const {\n")
|
||||
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n")
|
||||
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(DualListData.DataBegin());\n")
|
||||
output_file.write("\t\treturn HeaderOp->Size;\n")
|
||||
output_file.write("\t}\n\n")
|
||||
|
||||
output_file.write("\tuint8_t GetOpElements(OrderedNode *Op) const {\n")
|
||||
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n")
|
||||
output_file.write("\t\tLogMan::Throw::A(HeaderOp->HasDest, \"Op %s has no dest\\n\", GetName(HeaderOp->Op));\n")
|
||||
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(DualListData.DataBegin());\n")
|
||||
output_file.write("\t\tLOGMAN_THROW_A(HeaderOp->HasDest, \"Op %s has no dest\\n\", GetName(HeaderOp->Op));\n")
|
||||
output_file.write("\t\treturn HeaderOp->Size / HeaderOp->ElementSize;\n")
|
||||
output_file.write("\t}\n\n")
|
||||
|
||||
output_file.write("\tbool OpHasDest(OrderedNode *Op) const {\n")
|
||||
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n")
|
||||
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(DualListData.DataBegin());\n")
|
||||
output_file.write("\t\treturn HeaderOp->HasDest;\n")
|
||||
output_file.write("\t}\n\n")
|
||||
|
||||
@@ -387,11 +387,14 @@ def print_ir_allocator_helpers(ops, defines):
|
||||
output_file.write(") {\n")
|
||||
|
||||
output_file.write("\t\tauto Op = AllocateOp<IROp_%s, IROps::OP_%s>();\n" % (op_key, op_key.upper()))
|
||||
output_file.write("\t\tOp.first->Header.NumArgs = %d;\n" % (SSAArgs))
|
||||
|
||||
if (SSAArgs != 0):
|
||||
output_file.write("\t\tauto ListDataBegin = DualListData.ListBegin();\n")
|
||||
for i in range(0, SSAArgs):
|
||||
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(ListDataBegin);\n" % (i, i))
|
||||
|
||||
if (SSAArgs != 0):
|
||||
for i in range(0, SSAArgs):
|
||||
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(ListData.Begin());\n" % (i, i))
|
||||
output_file.write("\t\tssa%d->AddUse();\n" % (i))
|
||||
|
||||
if (HasArgs):
|
||||
@@ -399,11 +402,6 @@ def print_ir_allocator_helpers(ops, defines):
|
||||
data_name = op_vals["Args"][i]
|
||||
output_file.write("\t\tOp.first->%s = %s;\n" % (data_name, data_name))
|
||||
|
||||
if (HasFixedDestSize):
|
||||
output_file.write("\t\tOp.first->Header.Size = %d;\n" % FixedDestSize)
|
||||
if (HasDestSize):
|
||||
output_file.write("\t\tOp.first->Header.Size = %s;\n" % DestSize)
|
||||
|
||||
if (HasDest):
|
||||
# We can only infer a size if we have arguments
|
||||
if not (HasFixedDestSize or HasDestSize):
|
||||
@@ -412,10 +410,18 @@ def print_ir_allocator_helpers(ops, defines):
|
||||
if (SSAArgs != 0):
|
||||
for i in range(0, SSAArgs):
|
||||
output_file.write("\t\tuint8_t Size%d = GetOpSize(ssa%s);\n" % (i, i))
|
||||
for i in range(0, SSAArgs):
|
||||
output_file.write("\t\tInferSize = std::max(InferSize, Size%d);\n" % (i))
|
||||
|
||||
output_file.write("\t\tOp.first->Header.Size = InferSize;\n")
|
||||
|
||||
output_file.write("\t\tOp.first->Header.NumArgs = %d;\n" % (SSAArgs))
|
||||
|
||||
if (HasFixedDestSize):
|
||||
output_file.write("\t\tOp.first->Header.Size = %d;\n" % FixedDestSize)
|
||||
if (HasDestSize):
|
||||
output_file.write("\t\tOp.first->Header.Size = %s;\n" % DestSize)
|
||||
|
||||
output_file.write("\t\tOp.first->Header.ElementSize = Op.first->Header.Size / (%s);\n" % NumElements)
|
||||
|
||||
if (HasDest):
|
||||
@@ -499,7 +505,7 @@ def print_ir_parser_allocator_helpers(ops, defines):
|
||||
|
||||
if (SSAArgs != 0):
|
||||
for i in range(0, SSAArgs):
|
||||
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(ListData.Begin());\n" % (i, i))
|
||||
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(DualListData.ListBegin());\n" % (i, i))
|
||||
output_file.write("\t\tssa%d->AddUse();\n" % (i))
|
||||
|
||||
if (HasArgs):
|
||||
|
||||
+22
-3
@@ -114,6 +114,7 @@ set (SRCS
|
||||
Interface/IR/Passes/DeadContextStoreElimination.cpp
|
||||
Interface/IR/Passes/IRCompaction.cpp
|
||||
Interface/IR/Passes/IRValidation.cpp
|
||||
Interface/IR/Passes/LongDivideRemovalPass.cpp
|
||||
Interface/IR/Passes/ValueDominanceValidation.cpp
|
||||
Interface/IR/Passes/PhiValidation.cpp
|
||||
Interface/IR/Passes/RedundantFlagCalculationElimination.cpp
|
||||
@@ -121,7 +122,9 @@ set (SRCS
|
||||
Interface/IR/Passes/StaticRegisterAllocationPass.cpp
|
||||
Interface/IR/Passes/RegisterAllocationPass.cpp
|
||||
Interface/IR/Passes/SyscallOptimization.cpp
|
||||
Utils/ELFLoader.cpp
|
||||
Utils/Allocator.cpp
|
||||
Utils/Allocator/64BitAllocator.cpp
|
||||
Utils/ELFContainer.cpp
|
||||
Utils/ELFSymbolDatabase.cpp
|
||||
Utils/LogManager.cpp
|
||||
Utils/Threads.cpp
|
||||
@@ -264,8 +267,11 @@ function(AddObject Name Type)
|
||||
add_dependencies(${Name} IR_INC)
|
||||
add_dependencies(${Name} CONFIG_INC)
|
||||
|
||||
target_link_libraries(${Name} pthread rt vixl ${LINUX_LIBS} dl)
|
||||
target_link_libraries(${Name} pthread vixl dl xxhash FEX_jemalloc)
|
||||
set_target_properties(${Name} PROPERTIES OUTPUT_NAME FEXCore)
|
||||
set_target_properties(${Name} PROPERTIES C_VISIBILITY_PRESET hidden)
|
||||
set_target_properties(${Name} PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
set_target_properties(${Name} PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
|
||||
target_include_directories(${Name} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
@@ -283,6 +289,7 @@ function(AddObject Name Type)
|
||||
-Werror=implicit-fallthrough
|
||||
|
||||
-Wno-trigraphs
|
||||
-ffunction-sections
|
||||
)
|
||||
|
||||
if (GCC_COLOR)
|
||||
@@ -299,12 +306,24 @@ endfunction()
|
||||
|
||||
function(AddLibrary Name Type)
|
||||
add_library(${Name} ${Type} $<TARGET_OBJECTS:${PROJECT_NAME}_object>)
|
||||
target_link_libraries(${Name} pthread rt vixl ${LINUX_LIBS} dl)
|
||||
target_link_libraries(${Name} pthread vixl dl xxhash FEX_jemalloc)
|
||||
set_target_properties(${Name} PROPERTIES OUTPUT_NAME FEXCore)
|
||||
set_target_properties(${Name} PROPERTIES C_VISIBILITY_PRESET hidden)
|
||||
set_target_properties(${Name} PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
set_target_properties(${Name} PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
|
||||
target_include_directories(${Name} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
target_include_directories(${Name} PUBLIC "${PROJECT_SOURCE_DIR}/include/")
|
||||
target_include_directories(${Name} PUBLIC "${CMAKE_BINARY_DIR}/include/")
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES "RELEASE")
|
||||
target_link_options(${Name}
|
||||
PRIVATE
|
||||
"LINKER:--gc-sections"
|
||||
"LINKER:--strip-all"
|
||||
"LINKER:--as-needed"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
AddObject(${PROJECT_NAME}_object OBJECT)
|
||||
|
||||
+7
-6
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "Common/MathUtils.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
#include <cstring>
|
||||
@@ -16,16 +17,16 @@ struct BitSet final {
|
||||
ElementType *Memory;
|
||||
void Allocate(size_t Elements) {
|
||||
size_t AllocateSize = AlignUp(Elements, MinimumSizeBits) / MinimumSize;
|
||||
LogMan::Throw::A((AllocateSize * MinimumSize) >= Elements, "Fail");
|
||||
Memory = static_cast<ElementType*>(malloc(AllocateSize));
|
||||
LOGMAN_THROW_A((AllocateSize * MinimumSize) >= Elements, "Fail");
|
||||
Memory = static_cast<ElementType*>(FEXCore::Allocator::malloc(AllocateSize));
|
||||
}
|
||||
void Realloc(size_t Elements) {
|
||||
size_t AllocateSize = AlignUp(Elements, MinimumSizeBits) / MinimumSize;
|
||||
LogMan::Throw::A((AllocateSize * MinimumSize) >= Elements, "Fail");
|
||||
Memory = static_cast<ElementType*>(realloc(Memory, AllocateSize));
|
||||
LOGMAN_THROW_A((AllocateSize * MinimumSize) >= Elements, "Fail");
|
||||
Memory = static_cast<ElementType*>(FEXCore::Allocator::realloc(Memory, AllocateSize));
|
||||
}
|
||||
void Free() {
|
||||
free(Memory);
|
||||
FEXCore::Allocator::free(Memory);
|
||||
Memory = nullptr;
|
||||
}
|
||||
bool Get(T Element) {
|
||||
@@ -60,7 +61,7 @@ struct BitSetView final {
|
||||
ElementType *Memory;
|
||||
|
||||
void GetView(BitSet<T> &Set, uint64_t ElementOffset) {
|
||||
LogMan::Throw::A((ElementOffset % MinimumSize) == 0,
|
||||
LOGMAN_THROW_A((ElementOffset % MinimumSize) == 0,
|
||||
"Bitset view offset needs to be aligned to size of backing element");
|
||||
Memory = &Set.Memory[ElementOffset / MinimumSizeBits];
|
||||
}
|
||||
|
||||
+32
-5
@@ -48,8 +48,15 @@ namespace FEXCore::Config {
|
||||
else {
|
||||
char const *HomeDir = GetHomeDirectory();
|
||||
char const *ConfigXDG = getenv("XDG_CONFIG_HOME");
|
||||
ConfigDir = ConfigXDG ? ConfigXDG : HomeDir;
|
||||
ConfigDir += "/.fex-emu/";
|
||||
char const *ConfigOverride = getenv("FEX_APP_CONFIG_LOCATION");
|
||||
if (ConfigOverride) {
|
||||
// Config override completely overrides the config directory
|
||||
ConfigDir = ConfigOverride;
|
||||
}
|
||||
else {
|
||||
ConfigDir = ConfigXDG ? ConfigXDG : HomeDir;
|
||||
ConfigDir += "/.fex-emu/";
|
||||
}
|
||||
|
||||
// Ensure the folder structure is created for our configuration
|
||||
if (!std::filesystem::exists(ConfigDir) &&
|
||||
@@ -64,7 +71,15 @@ namespace FEXCore::Config {
|
||||
}
|
||||
|
||||
std::string GetConfigFileLocation() {
|
||||
std::string ConfigFile = GetConfigDirectory(false) + "Config.json";
|
||||
std::string ConfigFile{};
|
||||
const char *AppConfig = getenv("FEX_APP_CONFIG");
|
||||
if (AppConfig) {
|
||||
// App config environment variable overwrites only the config file
|
||||
ConfigFile = AppConfig;
|
||||
}
|
||||
else {
|
||||
ConfigFile = GetConfigDirectory(false) + "Config.json";
|
||||
}
|
||||
return ConfigFile;
|
||||
}
|
||||
|
||||
@@ -87,8 +102,15 @@ namespace FEXCore::Config {
|
||||
|
||||
char const *HomeDir = GetHomeDirectory();
|
||||
char const *DataXDG = getenv("XDG_DATA_HOME");
|
||||
DataDir = DataXDG ?: HomeDir;
|
||||
DataDir += "/.fex-emu/";
|
||||
char const *DataOverride = getenv("FEX_APP_DATA_LOCATION");
|
||||
if (DataOverride) {
|
||||
// Data override will override the complete directory
|
||||
DataDir = DataOverride;
|
||||
}
|
||||
else {
|
||||
DataDir = DataXDG ?: HomeDir;
|
||||
DataDir += "/.fex-emu/";
|
||||
}
|
||||
return DataDir;
|
||||
}
|
||||
|
||||
@@ -326,6 +348,10 @@ namespace FEXCore::Config {
|
||||
Meta->Set(Option, Data);
|
||||
}
|
||||
|
||||
void Erase(ConfigOption Option) {
|
||||
Meta->Erase(Option);
|
||||
}
|
||||
|
||||
void EraseSet(ConfigOption Option, std::string Data) {
|
||||
Meta->EraseSet(Option, Data);
|
||||
}
|
||||
@@ -389,5 +415,6 @@ namespace FEXCore::Config {
|
||||
*List = **Value;
|
||||
}
|
||||
}
|
||||
template void Value<std::string>::GetListIfExists(FEXCore::Config::ConfigOption Option, std::list<std::string> *List);
|
||||
}
|
||||
|
||||
+28
-1
@@ -129,7 +129,18 @@
|
||||
"Desc": [
|
||||
"Disables optimizations passes for debugging."
|
||||
]
|
||||
},
|
||||
"Force32BitAllocator": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
"Desc": [
|
||||
"Forces use of the 32-bit allocator on 32-bit applications",
|
||||
"Used to work around ulimit problems of CI runner",
|
||||
"Potentially useful for debugging memory problems",
|
||||
"32-bit allocator is always used if your host kernel is older than 4.17"
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
"Logging": {
|
||||
"SilentLog": {
|
||||
@@ -142,7 +153,7 @@
|
||||
},
|
||||
"OutputLog": {
|
||||
"Type": "str",
|
||||
"Default": "stdout",
|
||||
"Default": "stderr",
|
||||
"ShortArg": "o",
|
||||
"Desc": [
|
||||
"File to write FEX output to.",
|
||||
@@ -188,6 +199,14 @@
|
||||
"Removes the calculation of the parity flag from GPR instructions.",
|
||||
"Assuming no uses rely on it"
|
||||
]
|
||||
},
|
||||
"ParanoidTSO": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
"Desc": [
|
||||
"Makes TSO operations even more strict.",
|
||||
"Forces vector loadstores to also become atomic."
|
||||
]
|
||||
}
|
||||
},
|
||||
"Misc": {
|
||||
@@ -199,6 +218,14 @@
|
||||
"Captures both the loaded executable and libraries it loads."
|
||||
]
|
||||
},
|
||||
"AOTIRGenerate": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
"Desc": [
|
||||
"Scans file for executable code and generates an AOT IR cache.",
|
||||
"Does not run the executable."
|
||||
]
|
||||
},
|
||||
"AOTIRLoad": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
|
||||
+8
-1
@@ -50,6 +50,9 @@ namespace FEXCore::Context {
|
||||
CTX->Step();
|
||||
}
|
||||
|
||||
void CompileRIP(FEXCore::Context::Context *CTX, uint64_t GuestRIP) {
|
||||
CTX->CompileBlock(CTX->ParentThread->CurrentFrame, GuestRIP);
|
||||
}
|
||||
|
||||
FEXCore::Context::ExitReason RunUntilExit(FEXCore::Context::Context *CTX) {
|
||||
return CTX->RunUntilExit();
|
||||
@@ -142,7 +145,7 @@ namespace FEXCore::Context {
|
||||
return CTX->CPUID.RunFunction(Function, Leaf);
|
||||
}
|
||||
|
||||
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader) {
|
||||
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<int(const std::string&)> CacheReader) {
|
||||
CTX->AOTIRLoader = CacheReader;
|
||||
}
|
||||
|
||||
@@ -150,6 +153,10 @@ namespace FEXCore::Context {
|
||||
return CTX->WriteAOTIRCache(CacheWriter);
|
||||
}
|
||||
|
||||
void WriteFilesWithCode(FEXCore::Context::Context *CTX, std::function<void(const std::string& fileid, const std::string& filename)> Writer) {
|
||||
CTX->WriteFilesWithCode(Writer);
|
||||
}
|
||||
|
||||
void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name) {
|
||||
return CTX->AddNamedRegion(Base, Length, Offset, Name);
|
||||
}
|
||||
|
||||
+49
-19
@@ -52,6 +52,39 @@ namespace FEXCore::Context {
|
||||
MODE_SINGLESTEP = 1,
|
||||
};
|
||||
|
||||
struct AOTIRCaptureCacheEntry {
|
||||
uint64_t start;
|
||||
uint64_t len;
|
||||
uint64_t crc;
|
||||
IR::IRListView *IR;
|
||||
IR::RegisterAllocationData *RAData;
|
||||
};
|
||||
|
||||
struct AOTIRInlineEntry {
|
||||
uint64_t GuestHash;
|
||||
uint64_t GuestLength;
|
||||
|
||||
/* RAData followed by IRData */
|
||||
uint8_t InlineData[0];
|
||||
|
||||
IR::RegisterAllocationData *GetRAData();
|
||||
IR::IRListView *GetIRData();
|
||||
};
|
||||
|
||||
struct AOTIRInlineIndexEntry {
|
||||
uint64_t GuestStart;
|
||||
uint64_t DataOffset;
|
||||
};
|
||||
|
||||
struct AOTIRInlineIndex {
|
||||
uint64_t Count;
|
||||
uint64_t DataBase;
|
||||
AOTIRInlineIndexEntry Entries[0];
|
||||
|
||||
AOTIRInlineEntry *Find(uint64_t GuestStart);
|
||||
AOTIRInlineEntry *GetInlineEntry(uint64_t DataOffset);
|
||||
};
|
||||
|
||||
struct Context {
|
||||
friend class FEXCore::HLE::SyscallHandler;
|
||||
#ifdef JIT_ARM64
|
||||
@@ -78,6 +111,7 @@ namespace FEXCore::Context {
|
||||
FEX_CONFIG_OPT(ABILocalFlags, ABILOCALFLAGS);
|
||||
FEX_CONFIG_OPT(ABINoPF, ABINOPF);
|
||||
FEX_CONFIG_OPT(AOTIRCapture, AOTIRCAPTURE);
|
||||
FEX_CONFIG_OPT(AOTIRGenerate, AOTIRGENERATE);
|
||||
FEX_CONFIG_OPT(AOTIRLoad, AOTIRLOAD);
|
||||
FEX_CONFIG_OPT(SMCChecks, SMCCHECKS);
|
||||
FEX_CONFIG_OPT(Core, CORE);
|
||||
@@ -113,26 +147,27 @@ namespace FEXCore::Context {
|
||||
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
|
||||
|
||||
struct AOTIRCacheEntry {
|
||||
uint64_t start;
|
||||
uint64_t len;
|
||||
uint64_t crc;
|
||||
IR::IRListView *IR;
|
||||
IR::RegisterAllocationData *RAData;
|
||||
AOTIRInlineIndex *Array;
|
||||
void *mapping;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
std::function<std::unique_ptr<std::istream>(const std::string&)> AOTIRLoader;
|
||||
std::unordered_map<std::string, std::map<uint64_t, AOTIRCacheEntry>> AOTIRCache;
|
||||
std::unordered_map<std::string, AOTIRCacheEntry> AOTIRCache;
|
||||
std::function<int(const std::string&)> AOTIRLoader;
|
||||
std::unordered_map<std::string, std::map<uint64_t, AOTIRCaptureCacheEntry>> AOTIRCaptureCache;
|
||||
|
||||
struct AddrToFileEntry {
|
||||
uint64_t Start;
|
||||
uint64_t Len;
|
||||
uint64_t Offset;
|
||||
std::string fileid;
|
||||
std::string filename;
|
||||
void *CachedFileEntry;
|
||||
bool ContainsCode;
|
||||
};
|
||||
|
||||
std::map<uint64_t, AddrToFileEntry> AddrToFile;
|
||||
|
||||
std::map<std::string, std::string> FilesWithCode;
|
||||
|
||||
#ifdef BLOCKSTATS
|
||||
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
|
||||
@@ -178,18 +213,18 @@ namespace FEXCore::Context {
|
||||
bool GetDebugDataForRIP(uint64_t RIP, FEXCore::Core::DebugData *Data);
|
||||
bool FindHostCodeForRIP(uint64_t RIP, uint8_t **Code);
|
||||
|
||||
// XXX:
|
||||
// bool FindIRForRIP(uint64_t RIP, FEXCore::IR::IntrusiveIRList **ir);
|
||||
// void SetIRForRIP(uint64_t RIP, FEXCore::IR::IntrusiveIRList *const ir);
|
||||
void LoadEntryList();
|
||||
|
||||
std::tuple<FEXCore::IR::IRListView *, FEXCore::IR::RegisterAllocationData *, uint64_t, uint64_t, uint64_t, uint64_t> GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
|
||||
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool, uint64_t, uint64_t> CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
uintptr_t CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP);
|
||||
|
||||
// same as CompileBlock, but aborts on failure
|
||||
void CompileBlockJit(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP);
|
||||
|
||||
bool LoadAOTIRCache(std::istream &stream);
|
||||
bool LoadAOTIRCache(int streamfd);
|
||||
bool WriteAOTIRCache(std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
|
||||
void WriteFilesWithCode(std::function<void(const std::string& fileid, const std::string& filename)> Writer);
|
||||
|
||||
// Used for thread creation from syscalls
|
||||
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
|
||||
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
|
||||
@@ -226,11 +261,6 @@ namespace FEXCore::Context {
|
||||
FEXCore::CodeLoader *LocalLoader{};
|
||||
|
||||
// Entry Cache
|
||||
std::optional<std::string> GetFilenameHash(std::string const &Filename) const;
|
||||
void AddThreadRIPsToEntryList(FEXCore::Core::InternalThreadState *Thread);
|
||||
void SaveEntryList();
|
||||
std::set<uint64_t> EntryList;
|
||||
std::vector<uint64_t> InitLocations;
|
||||
uint64_t StartingRIP;
|
||||
std::mutex ExitMutex;
|
||||
std::unique_ptr<GdbServer> DebugServer;
|
||||
|
||||
@@ -12,6 +12,12 @@ namespace FEXCore::ArchHelpers::Arm64 {
|
||||
constexpr uint32_t ATOMIC_MEM_MASK = 0x3B200C00;
|
||||
constexpr uint32_t ATOMIC_MEM_INST = 0x38200000;
|
||||
|
||||
constexpr uint32_t LDAXP_MASK = 0xBF'FF'80'00;
|
||||
constexpr uint32_t LDAXP_INST = 0x88'7F'80'00;
|
||||
|
||||
constexpr uint32_t STLXP_MASK = 0xBF'E0'80'00;
|
||||
constexpr uint32_t STLXP_INST = 0x88'20'80'00;
|
||||
|
||||
// Load ops are 4 bits
|
||||
// Acquire and release bits are independent on the instruction
|
||||
constexpr uint32_t ATOMIC_ADD_OP = 0b0000;
|
||||
|
||||
@@ -29,6 +29,17 @@ Arm64Emitter::Arm64Emitter(size_t size) : vixl::aarch64::Assembler(size, vixl::a
|
||||
if (!SupportsAtomics) {
|
||||
WARN_ONCE("Host CPU doesn't support atomics. Expect bad performance");
|
||||
}
|
||||
|
||||
#ifdef _M_ARM_64
|
||||
// We need to get the CPU's cache line size
|
||||
// We expect sane targets that have correct cacheline sizes across clusters
|
||||
uint64_t CTR;
|
||||
__asm volatile ("mrs %[ctr], ctr_el0"
|
||||
: [ctr] "=r"(CTR));
|
||||
|
||||
DCacheLineSize = 4 << ((CTR >> 16) & 0xF);
|
||||
ICacheLineSize = 4 << (CTR & 0xF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arm64Emitter::LoadConstant(vixl::aarch64::Register Reg, uint64_t Constant) {
|
||||
|
||||
@@ -69,6 +69,9 @@ protected:
|
||||
void Align16B();
|
||||
|
||||
uint32_t SpillSlots{};
|
||||
|
||||
uint32_t DCacheLineSize{};
|
||||
uint32_t ICacheLineSize{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -111,7 +111,7 @@ static inline void BackupContext(void* ucontext, T *Backup) {
|
||||
|
||||
// Host FPR state starts at _mcontext->reserved[0];
|
||||
HostFPRState *HostState = reinterpret_cast<HostFPRState*>(&_mcontext->__reserved[0]);
|
||||
LogMan::Throw::A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
|
||||
LOGMAN_THROW_A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
|
||||
Backup->FPSR = HostState->FPSR;
|
||||
Backup->FPCR = HostState->FPCR;
|
||||
memcpy(&Backup->FPRs[0], &HostState->FPRs[0], 32 * sizeof(__uint128_t));
|
||||
@@ -126,7 +126,7 @@ static inline void RestoreContext(void* ucontext, T *Backup) {
|
||||
auto _mcontext = GetMContext(ucontext);
|
||||
|
||||
HostFPRState *HostState = reinterpret_cast<HostFPRState*>(&_mcontext->__reserved[0]);
|
||||
LogMan::Throw::A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
|
||||
LOGMAN_THROW_A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
|
||||
memcpy(&HostState->FPRs[0], &Backup->FPRs[0], 32 * sizeof(__uint128_t));
|
||||
HostState->FPCR = Backup->FPCR;
|
||||
HostState->FPSR = Backup->FPSR;
|
||||
|
||||
+49
-4
@@ -124,7 +124,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_01h() {
|
||||
(1 << 16) | // Page Attribute Table
|
||||
(1 << 17) | // 36bit page size extension
|
||||
(0 << 18) | // Processor serial number
|
||||
(0 << 19) | // CLFLUSH
|
||||
(1 << 19) | // CLFLUSH
|
||||
(0 << 20) | // Reserved
|
||||
(0 << 21) | // Debug store
|
||||
(0 << 22) | // Thermal monitor and software controled clock
|
||||
@@ -496,6 +496,45 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0007h() {
|
||||
return Res;
|
||||
}
|
||||
|
||||
// Virtual and physical address sizes
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0008h() {
|
||||
FEXCore::CPUID::FunctionResults Res{};
|
||||
Res.eax =
|
||||
(48 << 0) | // PhysAddrSize = 48-bit
|
||||
(48 << 8) | // LinAddrSize = 48-bit
|
||||
(0 << 16); // GuestPhysAddrSize == PhysAddrSize
|
||||
|
||||
Res.ebx =
|
||||
(0 << 2) | // XSaveErPtr: Saving and restoring error pointers
|
||||
(0 << 1) | // IRPerf: Instructions retired count support
|
||||
(0 << 0); // CLZERO support
|
||||
|
||||
uint32_t CoreCount = Cores() - 1;
|
||||
Res.ecx =
|
||||
(0 << 16) | // PerfTscSize: Performance timestamp count size
|
||||
(0 << 12) | // ApicIdSize: Number of bits in ApicID
|
||||
(CoreCount << 0); // Count count subtract one
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
// TLB 1GB page identifiers
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0019h() {
|
||||
FEXCore::CPUID::FunctionResults Res{};
|
||||
Res.eax =
|
||||
(0xF << 28) | // L1 DTLB associativity for 1GB pages
|
||||
(64 << 16) | // L1 DTLB entry count for 1GB pages
|
||||
(0xF << 12) | // L1 ITLB associativity for 1GB pages
|
||||
(64 << 0); // L1 ITLB entry count for 1GB pages
|
||||
|
||||
Res.ebx =
|
||||
(0 << 28) | // L2 DTLB associativity for 1GB pages
|
||||
(0 << 16) | // L2 DTLB entry count for 1GB pages
|
||||
(0 << 12) | // L2 ITLB associativity for 1GB pages
|
||||
(0 << 0); // L2 ITLB entry count for 1GB pages
|
||||
return Res;
|
||||
}
|
||||
|
||||
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_Reserved() {
|
||||
FEXCore::CPUID::FunctionResults Res{};
|
||||
return Res;
|
||||
@@ -542,16 +581,22 @@ void CPUIDEmu::Init(FEXCore::Context::Context *ctx) {
|
||||
RegisterFunction(0x8000'0004, std::bind(&CPUIDEmu::Function_8000_0004h, this));
|
||||
// 0x8000'0005: L1 Cache and TLB identifiers
|
||||
#ifdef CPUID_AMD
|
||||
// This is full reserved on Intel platforms
|
||||
RegisterFunction(0x8000'0005, std::bind(&CPUIDEmu::Function_8000_0005h, this));
|
||||
#else
|
||||
// This is full reserved on Intel platforms
|
||||
RegisterFunction(0x8000'0005, std::bind(&CPUIDEmu::Function_Reserved, this));
|
||||
#endif
|
||||
// 0x8000'0006: L2 Cache identifiers
|
||||
RegisterFunction(0x8000'0006, std::bind(&CPUIDEmu::Function_8000_0006h, this));
|
||||
// Advanced power management information
|
||||
RegisterFunction(0x8000'0007, std::bind(&CPUIDEmu::Function_8000_0007h, this));
|
||||
// 0x8000'0008: Virtual and physical address sizes
|
||||
// Virtual and physical address sizes
|
||||
RegisterFunction(0x8000'0008, std::bind(&CPUIDEmu::Function_8000_0008h, this));
|
||||
|
||||
// 0x8000'000A: SVM Revision
|
||||
// 0x8000'0019: TLB 1GB page identifiers
|
||||
// TLB 1GB page identifiers
|
||||
RegisterFunction(0x8000'0019, std::bind(&CPUIDEmu::Function_8000_0019h, this));
|
||||
|
||||
// 0x8000'001A: Performance optimization identifiers
|
||||
// 0x8000'001B: Instruction based sampling identifiers
|
||||
// 0x8000'001C: Lightweight profiling capabilities
|
||||
|
||||
+5
-1
@@ -3,6 +3,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include <FEXCore/Core/CPUID.h>
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
namespace FEXCore {
|
||||
@@ -37,6 +38,7 @@ public:
|
||||
}
|
||||
private:
|
||||
FEXCore::Context::Context *CTX;
|
||||
FEX_CONFIG_OPT(Cores, THREADS);
|
||||
|
||||
using FunctionHandler = std::function<FEXCore::CPUID::FunctionResults()>;
|
||||
void RegisterFunction(uint32_t Function, FunctionHandler Handler) {
|
||||
@@ -60,7 +62,9 @@ private:
|
||||
FEXCore::CPUID::FunctionResults Function_8000_0005h();
|
||||
FEXCore::CPUID::FunctionResults Function_8000_0006h();
|
||||
FEXCore::CPUID::FunctionResults Function_8000_0007h();
|
||||
|
||||
FEXCore::CPUID::FunctionResults Function_8000_0008h();
|
||||
FEXCore::CPUID::FunctionResults Function_8000_0009h();
|
||||
FEXCore::CPUID::FunctionResults Function_8000_0019h();
|
||||
FEXCore::CPUID::FunctionResults Function_Reserved();
|
||||
};
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace FEXCore {
|
||||
}
|
||||
}
|
||||
|
||||
LogMan::Throw::A(CompileThreadData->LocalIRCache.size() == 0, "Compile service must never have LocalIRCache");
|
||||
LOGMAN_THROW_A(CompileThreadData->LocalIRCache.size() == 0, "Compile service must never have LocalIRCache");
|
||||
|
||||
CompileMutex.unlock();
|
||||
}
|
||||
@@ -124,7 +124,7 @@ namespace FEXCore {
|
||||
// If we had a work item then work on it
|
||||
if (Item) {
|
||||
// Make sure it's not in lookup cache by accident
|
||||
LogMan::Throw::A(CompileThreadData->LookupCache->FindBlock(Item->RIP) == 0, "Compile Service must never have entries in the LookupCache");
|
||||
LOGMAN_THROW_A(CompileThreadData->LookupCache->FindBlock(Item->RIP) == 0, "Compile Service must never have entries in the LookupCache");
|
||||
|
||||
// Code isn't in cache, compile now
|
||||
// Set our thread state's RIP
|
||||
@@ -132,7 +132,7 @@ namespace FEXCore {
|
||||
|
||||
auto [CodePtr, IRList, DebugData, RAData, Generated, StartAddr, Length] = CTX->CompileCode(CompileThreadData.get(), Item->RIP);
|
||||
|
||||
LogMan::Throw::A(Generated == true, "Compile Service doesn't have IR Cache");
|
||||
LOGMAN_THROW_A(Generated == true, "Compile Service doesn't have IR Cache");
|
||||
|
||||
if (!CodePtr) {
|
||||
// XXX: We currently have the expectation that compile service code will be significantly smaller than regular thread's code
|
||||
|
||||
+215
-254
@@ -28,59 +28,22 @@ $end_info$
|
||||
#include <FEXCore/Core/CPUBackend.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
#include "FEXCore/Utils/Allocator.h"
|
||||
|
||||
#include <xxh3.h>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Interface/Core/GdbServer.h"
|
||||
|
||||
namespace {
|
||||
// Compression function for Merkle-Damgard construction.
|
||||
// This function is generated using the framework provided.
|
||||
#define mix(h) ({ \
|
||||
(h) ^= (h) >> 23; \
|
||||
(h) *= 0x2127599bf4325c37ULL; \
|
||||
(h) ^= (h) >> 47; })
|
||||
|
||||
static uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
|
||||
{
|
||||
const uint64_t m = 0x880355f21e6d1965ULL;
|
||||
const uint64_t *pos = (const uint64_t *)buf;
|
||||
const uint64_t *end = pos + (len / 8);
|
||||
const unsigned char *pos2;
|
||||
uint64_t h = seed ^ (len * m);
|
||||
uint64_t v;
|
||||
|
||||
while (pos != end) {
|
||||
v = *pos++;
|
||||
h ^= mix(v);
|
||||
h *= m;
|
||||
}
|
||||
|
||||
pos2 = (const unsigned char*)pos;
|
||||
v = 0;
|
||||
|
||||
switch (len & 7) {
|
||||
case 7: v ^= (uint64_t)pos2[6] << 48; [[fallthrough]];
|
||||
case 6: v ^= (uint64_t)pos2[5] << 40; [[fallthrough]];
|
||||
case 5: v ^= (uint64_t)pos2[4] << 32; [[fallthrough]];
|
||||
case 4: v ^= (uint64_t)pos2[3] << 24; [[fallthrough]];
|
||||
case 3: v ^= (uint64_t)pos2[2] << 16; [[fallthrough]];
|
||||
case 2: v ^= (uint64_t)pos2[1] << 8; [[fallthrough]];
|
||||
case 1: v ^= (uint64_t)pos2[0];
|
||||
h ^= mix(v);
|
||||
h *= m;
|
||||
}
|
||||
|
||||
return mix(h);
|
||||
}
|
||||
#undef mix
|
||||
}
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
bool CreateCPUCore(FEXCore::Context::Context *CTX) {
|
||||
// This should be used for generating things that are shared between threads
|
||||
@@ -167,7 +130,7 @@ namespace DefaultFallbackCore {
|
||||
void Initialize() override {}
|
||||
bool NeedsOpDispatch() override { return false; }
|
||||
|
||||
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override {
|
||||
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override {
|
||||
LogMan::Msg::E("Fell back to default code handler at RIP: 0x%lx", ThreadState->CurrentFrame->State.rip);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -196,77 +159,6 @@ namespace FEXCore::Context {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> Context::GetFilenameHash(std::string const &Filename) const {
|
||||
// Calculate a hash for the input file
|
||||
std::ifstream Input(Filename, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if (!Input) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto Size = static_cast<size_t>(Input.tellg());
|
||||
Input.seekg(0, std::ios::beg);
|
||||
std::string Data(Size, '\0');
|
||||
Input.read(Data.data(), Size);
|
||||
Input.close();
|
||||
|
||||
std::hash<std::string> string_hash;
|
||||
return std::to_string(string_hash(Data));
|
||||
}
|
||||
|
||||
void Context::AddThreadRIPsToEntryList(FEXCore::Core::InternalThreadState *Thread) {
|
||||
for (auto &IR : Thread->LocalIRCache) {
|
||||
EntryList.insert(IR.first);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::SaveEntryList() {
|
||||
std::string const &Filename = AppFilename();
|
||||
|
||||
if (auto const hash = GetFilenameHash(Filename)) {
|
||||
auto DataPath = FEXCore::Paths::GetEntryCachePath();
|
||||
DataPath += "Entries_" + *hash;
|
||||
|
||||
std::ofstream Output(DataPath, std::ios::out | std::ios::binary);
|
||||
if (!Output) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto Entry : EntryList) {
|
||||
Output.write(reinterpret_cast<char const*>(&Entry), sizeof(Entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::LoadEntryList() {
|
||||
std::string const &Filename = AppFilename();
|
||||
|
||||
if (auto const hash = GetFilenameHash(Filename)) {
|
||||
auto DataPath = FEXCore::Paths::GetEntryCachePath();
|
||||
DataPath += "Entries_" + *hash;
|
||||
|
||||
std::ifstream Input(DataPath, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if (!Input) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto const Size = static_cast<size_t>(Input.tellg());
|
||||
Input.seekg(0, std::ios::beg);
|
||||
std::string Data(Size, '\0');
|
||||
if (!Input.read(Data.data(), Size)) {
|
||||
return;
|
||||
}
|
||||
Input.close();
|
||||
|
||||
size_t const EntryCount = Size / sizeof(uint64_t);
|
||||
|
||||
for (size_t i = 0; i < EntryCount; ++i) {
|
||||
uint64_t Entry = 0;
|
||||
std::memcpy(&Entry, &Data[i * sizeof(Entry)], sizeof(Entry));
|
||||
EntryList.insert(Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context() {
|
||||
{
|
||||
for (auto &Thread : Threads) {
|
||||
@@ -275,10 +167,6 @@ namespace FEXCore::Context {
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &Thread : Threads) {
|
||||
AddThreadRIPsToEntryList(Thread);
|
||||
}
|
||||
|
||||
for (auto &Thread : Threads) {
|
||||
|
||||
if (Thread->CompileService) {
|
||||
@@ -289,15 +177,17 @@ namespace FEXCore::Context {
|
||||
Threads.clear();
|
||||
}
|
||||
|
||||
SaveEntryList();
|
||||
|
||||
// AOTIRCache needs manual clear
|
||||
for (auto &Mod: AOTIRCache) {
|
||||
// AOTIRCaptureCache needs manual clear
|
||||
for (auto &Mod: AOTIRCaptureCache) {
|
||||
for (auto &Entry: Mod.second) {
|
||||
delete Entry.second.IR;
|
||||
free(Entry.second.RAData);
|
||||
FEXCore::Allocator::free(Entry.second.RAData);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &Mod: AOTIRCache) {
|
||||
FEXCore::Allocator::munmap(Mod.second.mapping, Mod.second.size);
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::InitCore(FEXCore::CodeLoader *Loader) {
|
||||
@@ -327,12 +217,7 @@ namespace FEXCore::Context {
|
||||
// We are the parent thread
|
||||
ParentThread = Thread;
|
||||
|
||||
Loader->MapMemoryRegion();
|
||||
|
||||
Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = Loader->SetupStack();
|
||||
|
||||
Loader->LoadMemory();
|
||||
Loader->GetInitLocations(&InitLocations);
|
||||
Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = Loader->GetStackPointer();
|
||||
|
||||
Thread->CurrentFrame->State.rip = StartingRIP = Loader->DefaultRIP();
|
||||
|
||||
@@ -542,12 +427,6 @@ namespace FEXCore::Context {
|
||||
|
||||
LocalLoader->AddIR(IRHandler);
|
||||
|
||||
// Compile all of our cached entries
|
||||
LogMan::Msg::D("Precompiling: %ld blocks...", EntryList.size());
|
||||
for (auto Entry : EntryList) {
|
||||
CompileRIP(Thread, Entry);
|
||||
}
|
||||
LogMan::Msg::D("Done", EntryList.size());
|
||||
}
|
||||
|
||||
struct ExecutionThreadHandler {
|
||||
@@ -558,7 +437,7 @@ namespace FEXCore::Context {
|
||||
static void *ThreadHandler(void* Data) {
|
||||
ExecutionThreadHandler *Handler = reinterpret_cast<ExecutionThreadHandler*>(Data);
|
||||
Handler->This->ExecutionThread(Handler->Thread);
|
||||
free(Handler);
|
||||
FEXCore::Allocator::free(Handler);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -566,7 +445,7 @@ namespace FEXCore::Context {
|
||||
InitializeThreadData(Thread);
|
||||
|
||||
// This will create the execution thread but it won't actually start executing
|
||||
ExecutionThreadHandler *Arg = reinterpret_cast<ExecutionThreadHandler*>(malloc(sizeof(ExecutionThreadHandler)));
|
||||
ExecutionThreadHandler *Arg = reinterpret_cast<ExecutionThreadHandler*>(FEXCore::Allocator::malloc(sizeof(ExecutionThreadHandler)));
|
||||
Arg->This = this;
|
||||
Arg->Thread = Thread;
|
||||
Thread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg);
|
||||
@@ -653,7 +532,7 @@ namespace FEXCore::Context {
|
||||
std::lock_guard<std::mutex> lk(ThreadCreationMutex);
|
||||
|
||||
auto It = std::find(Threads.begin(), Threads.end(), Thread);
|
||||
LogMan::Throw::A(It != Threads.end(), "Thread wasn't in Threads");
|
||||
LOGMAN_THROW_A(It != Threads.end(), "Thread wasn't in Threads");
|
||||
|
||||
Threads.erase(It);
|
||||
}
|
||||
@@ -735,6 +614,8 @@ namespace FEXCore::Context {
|
||||
|
||||
Thread->OpDispatcher->BeginFunction(GuestRIP, CodeBlocks);
|
||||
|
||||
uint8_t GPRSize = Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
for (size_t j = 0; j < CodeBlocks->size(); ++j) {
|
||||
FEXCore::Frontend::Decoder::DecodedBlocks const &Block = CodeBlocks->at(j);
|
||||
// Set the block entry point
|
||||
@@ -749,8 +630,7 @@ namespace FEXCore::Context {
|
||||
uint64_t InstsInBlock = Block.NumInstructions;
|
||||
|
||||
if (Block.HasInvalidInstruction) {
|
||||
uint8_t GPRSize = Config.Is64BitMode ? 8 : 4;
|
||||
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_Constant(GPRSize * 8, Block.Entry));
|
||||
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(Block.Entry - GuestRIP, GPRSize));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -775,7 +655,7 @@ namespace FEXCore::Context {
|
||||
|
||||
Thread->OpDispatcher->SetCurrentCodeBlock(CodeWasChangedBlock);
|
||||
Thread->OpDispatcher->_RemoveCodeEntry();
|
||||
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_Constant(Block.Entry + BlockInstructionsLength));
|
||||
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(Block.Entry + BlockInstructionsLength - GuestRIP, GPRSize));
|
||||
|
||||
auto NextOpBlock = Thread->OpDispatcher->CreateNewCodeBlockAfter(CurrentBlock);
|
||||
|
||||
@@ -786,12 +666,16 @@ namespace FEXCore::Context {
|
||||
if (TableInfo->OpcodeDispatcher) {
|
||||
auto Fn = TableInfo->OpcodeDispatcher;
|
||||
Thread->OpDispatcher->HandledLock = false;
|
||||
Thread->OpDispatcher->ResetDecodeFailure();
|
||||
std::invoke(Fn, Thread->OpDispatcher, DecodedInfo);
|
||||
if (Thread->OpDispatcher->HadDecodeFailure()) {
|
||||
HadDispatchError = true;
|
||||
}
|
||||
else {
|
||||
LogMan::Throw::A(Thread->OpDispatcher->HandledLock == IsLocked, "Missing LOCK HANDLER at 0x%lx{'%s'}\n", Block.Entry + BlockInstructionsLength, TableInfo->Name);
|
||||
if (Thread->OpDispatcher->HandledLock != IsLocked) {
|
||||
HadDispatchError = true;
|
||||
LogMan::Msg::E("Missing LOCK HANDLER at 0x%lx{'%s'}", Block.Entry + BlockInstructionsLength, TableInfo->Name);
|
||||
}
|
||||
BlockInstructionsLength += DecodedInfo->InstSize;
|
||||
TotalInstructionsLength += DecodedInfo->InstSize;
|
||||
++TotalInstructions;
|
||||
@@ -807,13 +691,13 @@ namespace FEXCore::Context {
|
||||
if (TotalInstructions == 0) {
|
||||
// Couldn't handle any instruction in op dispatcher
|
||||
Thread->OpDispatcher->ResetWorkingList();
|
||||
return { nullptr, nullptr, 0, 0, 0, 0};
|
||||
return { nullptr, nullptr, 0, 0, 0, 0 };
|
||||
}
|
||||
else {
|
||||
uint8_t GPRSize = Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
// We had some instructions. Early exit
|
||||
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_Constant(GPRSize * 8, Block.Entry + BlockInstructionsLength));
|
||||
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(Block.Entry + BlockInstructionsLength - GuestRIP, GPRSize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -870,7 +754,7 @@ namespace FEXCore::Context {
|
||||
out.seekg(0);
|
||||
auto reparsed = IR::Parse(&out);
|
||||
if (reparsed == nullptr) {
|
||||
LogMan::Msg::A("Failed to parse ir\n");
|
||||
LOGMAN_MSG_A("Failed to parse ir\n");
|
||||
} else {
|
||||
std::stringstream out2;
|
||||
auto NewIR2 = reparsed->ViewIR();
|
||||
@@ -878,7 +762,7 @@ namespace FEXCore::Context {
|
||||
if (out.str() != out2.str()) {
|
||||
LogMan::Msg::I("one:\n %s", out.str().c_str());
|
||||
LogMan::Msg::I("two:\n %s", out2.str().c_str());
|
||||
LogMan::Msg::A("Parsed ir doesn't match\n");
|
||||
LOGMAN_MSG_A("Parsed ir doesn't match\n");
|
||||
}
|
||||
delete reparsed;
|
||||
}
|
||||
@@ -905,6 +789,41 @@ namespace FEXCore::Context {
|
||||
return {IRList, RAData.release(), TotalInstructions, TotalInstructionsLength, Thread->FrontendDecoder->DecodedMinAddress, Thread->FrontendDecoder->DecodedMaxAddress - Thread->FrontendDecoder->DecodedMinAddress };
|
||||
}
|
||||
|
||||
AOTIRInlineEntry *AOTIRInlineIndex::GetInlineEntry(uint64_t DataOffset) {
|
||||
uintptr_t This = (uintptr_t)this;
|
||||
|
||||
return (AOTIRInlineEntry*)(This + DataBase + DataOffset);
|
||||
}
|
||||
|
||||
AOTIRInlineEntry *AOTIRInlineIndex::Find(uint64_t GuestStart) {
|
||||
ssize_t l = 0;
|
||||
ssize_t r = Count - 1;
|
||||
|
||||
while (l <= r) {
|
||||
size_t m = l + (r - l) / 2;
|
||||
|
||||
if (Entries[m].GuestStart == GuestStart)
|
||||
return GetInlineEntry(Entries[m].DataOffset);
|
||||
else if (Entries[m].GuestStart < GuestStart)
|
||||
l = m + 1;
|
||||
else
|
||||
r = m - 1;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IR::RegisterAllocationData *AOTIRInlineEntry::GetRAData() {
|
||||
return (IR::RegisterAllocationData *)InlineData;
|
||||
}
|
||||
|
||||
IR::IRListView *AOTIRInlineEntry::GetIRData() {
|
||||
auto RAData = GetRAData();
|
||||
auto Offset = RAData->Size(RAData->MapCount);
|
||||
|
||||
return (IR::IRListView *)&InlineData[Offset];
|
||||
}
|
||||
|
||||
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool, uint64_t, uint64_t> Context::CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||
FEXCore::IR::IRListView *IRList {};
|
||||
FEXCore::Core::DebugData *DebugData {};
|
||||
@@ -928,35 +847,53 @@ namespace FEXCore::Context {
|
||||
GeneratedIR = false;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
auto file = AddrToFile.lower_bound(GuestRIP);
|
||||
if (file != AddrToFile.begin()) {
|
||||
--file;
|
||||
if (!file->second.ContainsCode) {
|
||||
file->second.ContainsCode = true;
|
||||
FilesWithCode[file->second.fileid] = file->second.filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IRList == nullptr && Config.AOTIRLoad) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
auto file = AddrToFile.lower_bound(GuestRIP);
|
||||
if (file != AddrToFile.begin()) {
|
||||
--file;
|
||||
auto Mod = (decltype(AOTIRCache)::value_type::second_type*) file->second.CachedFileEntry;
|
||||
auto Mod = (AOTIRInlineIndex*)file->second.CachedFileEntry;
|
||||
|
||||
if (Mod == nullptr) {
|
||||
file->second.CachedFileEntry = Mod = &AOTIRCache[file->second.fileid];
|
||||
file->second.CachedFileEntry = Mod = AOTIRCache[file->second.fileid].Array;
|
||||
}
|
||||
|
||||
auto AOTEntry = Mod->find(GuestRIP - file->second.Start + file->second.Offset);
|
||||
if (Mod != nullptr)
|
||||
{
|
||||
auto AOTEntry = Mod->Find(GuestRIP - file->second.Start + file->second.Offset);
|
||||
|
||||
if (AOTEntry != Mod->end()) {
|
||||
// verify hash
|
||||
auto MappedStart = AOTEntry->second.start + file->second.Start - file->second.Offset;
|
||||
auto hash = fasthash64((void*)MappedStart, AOTEntry->second.len, 0);
|
||||
if (hash == AOTEntry->second.crc) {
|
||||
IRList = AOTEntry->second.IR;
|
||||
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
|
||||
// relocate
|
||||
IRList->GetHeader()->Entry = GuestRIP;
|
||||
if (AOTEntry) {
|
||||
// verify hash
|
||||
auto MappedStart = GuestRIP;
|
||||
auto hash = XXH3_64bits((void*)MappedStart, AOTEntry->GuestLength);
|
||||
if (hash == AOTEntry->GuestHash) {
|
||||
IRList = AOTEntry->GetIRData();
|
||||
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
|
||||
|
||||
RAData = AOTEntry->second.RAData;
|
||||
DebugData = new FEXCore::Core::DebugData();
|
||||
StartAddr = MappedStart;
|
||||
Length = AOTEntry->second.len;
|
||||
|
||||
GeneratedIR = true;
|
||||
RAData = AOTEntry->GetRAData();;
|
||||
DebugData = new FEXCore::Core::DebugData();
|
||||
StartAddr = MappedStart;
|
||||
Length = AOTEntry->GuestLength;
|
||||
|
||||
GeneratedIR = true;
|
||||
} else {
|
||||
LogMan::Msg::I("AOTIR: hash check failed %lx\n", MappedStart);
|
||||
}
|
||||
} else {
|
||||
//LogMan::Msg::I("AOTIR: Failed to find %lx, %lx, %s\n", GuestRIP, GuestRIP - file->second.Start + file->second.Offset, file->second.fileid.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -984,91 +921,63 @@ namespace FEXCore::Context {
|
||||
GeneratedIR = true;
|
||||
}
|
||||
|
||||
if (IRList == nullptr) {
|
||||
return { nullptr, nullptr, nullptr, nullptr, false, 0, 0 };
|
||||
}
|
||||
// Attempt to get the CPU backend to compile this code
|
||||
return { Thread->CPUBackend->CompileCode(IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR, StartAddr, Length};
|
||||
return { Thread->CPUBackend->CompileCode(GuestRIP, IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR, StartAddr, Length};
|
||||
}
|
||||
|
||||
bool Context::LoadAOTIRCache(std::istream &stream) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
static bool readAll(int fd, void *data, size_t size) {
|
||||
int rv = read(fd, data, size);
|
||||
|
||||
if (rv != size)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::LoadAOTIRCache(int streamfd) {
|
||||
uint64_t tag;
|
||||
stream.read((char*)&tag, sizeof(tag));
|
||||
if (!stream || tag != 0xDEADBEEFC0D30002)
|
||||
|
||||
if (!readAll(streamfd, (char*)&tag, sizeof(tag)) || tag != 0xDEADBEEFC0D30003)
|
||||
return false;
|
||||
|
||||
std::string Module;
|
||||
uint64_t ModSize;
|
||||
|
||||
if (!readAll(streamfd, (char*)&ModSize, sizeof(ModSize)))
|
||||
return false;
|
||||
|
||||
uint64_t ModCount;
|
||||
stream.read((char*)&ModCount, sizeof(ModCount));
|
||||
if (!stream)
|
||||
Module.resize(ModSize);
|
||||
if (!readAll(streamfd, (char*)&Module[0], Module.size()))
|
||||
return false;
|
||||
|
||||
for (int ModIndex = 0; ModIndex < ModCount; ModIndex++) {
|
||||
std::string Module;
|
||||
uint64_t ModSize;
|
||||
stream.read((char*)&ModSize, sizeof(ModSize));
|
||||
if (!stream)
|
||||
return false;
|
||||
struct stat fileinfo;
|
||||
if (fstat(streamfd, &fileinfo) < 0)
|
||||
return false;
|
||||
size_t Size = (fileinfo.st_size + 4095) & ~4095;
|
||||
|
||||
Module.resize(ModSize);
|
||||
stream.read((char*)&Module[0], Module.size());
|
||||
if (!stream)
|
||||
return false;
|
||||
void *FilePtr = FEXCore::Allocator::mmap(nullptr, Size, PROT_READ, MAP_SHARED, streamfd, 0);
|
||||
|
||||
auto &Mod = AOTIRCache[Module];
|
||||
if (FilePtr == MAP_FAILED)
|
||||
return false;
|
||||
|
||||
uint64_t FnCount;
|
||||
stream.read((char*)&FnCount, sizeof(FnCount));
|
||||
if (!stream)
|
||||
return false;
|
||||
auto Array = (AOTIRInlineIndex *)((char*)FilePtr + sizeof(tag) + sizeof(ModSize) + ((ModSize+31) & ~31));
|
||||
|
||||
LogMan::Msg::D("AOTIR: Module %s has %ld functions", Module.c_str(), FnCount);
|
||||
for (int FnIndex = 0; FnIndex < FnCount; FnIndex++) {
|
||||
uint64_t addr, start, crc, len;
|
||||
stream.read((char*)&addr, sizeof(addr));
|
||||
if (!stream)
|
||||
return false;
|
||||
AOTIRCache.insert({Module, {Array, FilePtr, Size}});
|
||||
|
||||
stream.read((char*)&start, sizeof(start));
|
||||
if (!stream)
|
||||
return false;
|
||||
stream.read((char*)&len, sizeof(len));
|
||||
if (!stream)
|
||||
return false;
|
||||
stream.read((char*)&crc, sizeof(crc));
|
||||
if (!stream)
|
||||
return false;
|
||||
auto IR = new IR::IRListView(stream);
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
uint64_t RASize;
|
||||
stream.read((char*)&RASize, sizeof(RASize));
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
IR::RegisterAllocationData *RAData = (IR::RegisterAllocationData *)malloc(IR::RegisterAllocationData::Size(RASize));
|
||||
RAData->MapCount = RASize;
|
||||
|
||||
stream.read((char*)&RAData->Map[0], sizeof(RAData->Map[0]) * RASize);
|
||||
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
stream.read((char*)&RAData->SpillSlotCount, sizeof(RAData->SpillSlotCount));
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
|
||||
IR->IsShared = true;
|
||||
RAData->IsShared = true;
|
||||
|
||||
Mod.insert({addr, {start, len, crc, IR, RAData}});
|
||||
}
|
||||
}
|
||||
LogMan::Msg::D("AOTIR: Module %s has %ld functions", Module.c_str(), Array->Count);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void Context::WriteFilesWithCode(std::function<void(const std::string& fileid, const std::string& filename)> Writer) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
for( const auto &File: FilesWithCode) {
|
||||
Writer(File.first, File.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::WriteAOTIRCache(std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter) {
|
||||
@@ -1076,7 +985,7 @@ namespace FEXCore::Context {
|
||||
|
||||
bool rv = true;
|
||||
|
||||
for (auto AOTModule: AOTIRCache) {
|
||||
for (auto AOTModule: AOTIRCaptureCache) {
|
||||
if (AOTModule.second.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -1085,35 +994,74 @@ namespace FEXCore::Context {
|
||||
if (!*stream) {
|
||||
rv = false;
|
||||
}
|
||||
uint64_t tag = 0xDEADBEEFC0D30002;
|
||||
uint64_t tag = 0xDEADBEEFC0D30003;
|
||||
stream->write((char*)&tag, sizeof(tag));
|
||||
|
||||
uint64_t ModCount = 1;
|
||||
stream->write((char*)&ModCount, sizeof(ModCount));
|
||||
auto ModSize = AOTModule.first.size();
|
||||
stream->write((char*)&ModSize, sizeof(ModSize));
|
||||
stream->write((char*)&AOTModule.first[0], ModSize);
|
||||
|
||||
auto Skip = ((ModSize + 31) & ~31) - ModSize;
|
||||
char Zero = 0;
|
||||
for (int i = 0; i < Skip; i++)
|
||||
stream->write(&Zero, 1);
|
||||
|
||||
// AOTIRInlineIndex
|
||||
|
||||
|
||||
auto FnCount = AOTModule.second.size();
|
||||
stream->write((char*)&FnCount, sizeof(FnCount));
|
||||
|
||||
size_t DataBase = sizeof(FnCount) + sizeof(DataBase) + FnCount * sizeof(AOTIRInlineIndexEntry);
|
||||
stream->write((char*)&DataBase, sizeof(DataBase));
|
||||
|
||||
size_t DataOffset = 0;
|
||||
for (auto entry: AOTModule.second) {
|
||||
//AOTIRInlineIndexEntry
|
||||
|
||||
// GuestStart
|
||||
stream->write((char*)&entry.first, sizeof(entry.first));
|
||||
stream->write((char*)&entry.second.start, sizeof(entry.second.start));
|
||||
stream->write((char*)&entry.second.len, sizeof(entry.second.len));
|
||||
|
||||
// DataOffset
|
||||
stream->write((char*)&DataOffset, sizeof(DataOffset));
|
||||
|
||||
|
||||
DataOffset += sizeof(entry.second.crc);
|
||||
DataOffset += sizeof(entry.second.len);
|
||||
|
||||
DataOffset += entry.second.RAData->Size(entry.second.RAData->MapCount);
|
||||
|
||||
DataOffset += entry.second.IR->GetInlineSize();
|
||||
}
|
||||
|
||||
// AOTIRInlineEntry
|
||||
for (auto entry: AOTModule.second) {
|
||||
//GuestHash
|
||||
stream->write((char*)&entry.second.crc, sizeof(entry.second.crc));
|
||||
|
||||
//GuestLength
|
||||
stream->write((char*)&entry.second.len, sizeof(entry.second.len));
|
||||
|
||||
// RAData (inline)
|
||||
stream->write((char*)entry.second.RAData, entry.second.RAData->Size(entry.second.RAData->MapCount));
|
||||
|
||||
// IRData (inline)
|
||||
entry.second.IR->Serialize(*stream);
|
||||
uint64_t RASize = entry.second.RAData->MapCount;
|
||||
stream->write((char*)&RASize, sizeof(RASize));
|
||||
stream->write((char*)&entry.second.RAData->Map[0], sizeof(entry.second.RAData->Map[0]) * RASize);
|
||||
stream->write((char*)&entry.second.RAData->SpillSlotCount, sizeof(entry.second.RAData->SpillSlotCount));
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Context::CompileBlockJit(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP) {
|
||||
auto NewBlock = CompileBlock(Frame, GuestRIP);
|
||||
|
||||
if (NewBlock == 0) {
|
||||
LogMan::Msg::E("CompileBlockJit: Failed to compile code %lX - aborting process", GuestRIP);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t Context::CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP) {
|
||||
auto Thread = Frame->Thread;
|
||||
|
||||
@@ -1166,7 +1114,11 @@ namespace FEXCore::Context {
|
||||
Length = _Length;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(CodePtr != nullptr, "Failed to compile code %lX", GuestRIP);
|
||||
if (CodePtr == nullptr) {
|
||||
if (DecrementRefCount)
|
||||
--Thread->CompileBlockReentrantRefCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The core managed to compile the code.
|
||||
#if ENABLE_JITSYMBOLS
|
||||
@@ -1187,19 +1139,19 @@ namespace FEXCore::Context {
|
||||
Thread->LocalIRCache.insert({GuestRIP, std::move(Entry)});
|
||||
|
||||
// Add to AOT cache if aot generation is enabled
|
||||
if (Config.AOTIRCapture && RAData) {
|
||||
if ((Config.AOTIRCapture() || Config.AOTIRGenerate()) && RAData) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
|
||||
RAData->IsShared = true;
|
||||
IRList->IsShared = true;
|
||||
IRList->SetShared(true);
|
||||
|
||||
auto hash = fasthash64((void*)StartAddr, Length, 0);
|
||||
auto hash = XXH3_64bits((void*)StartAddr, Length);
|
||||
|
||||
auto file = AddrToFile.lower_bound(StartAddr);
|
||||
if (file != AddrToFile.begin()) {
|
||||
--file;
|
||||
if (file->second.Start <= StartAddr && (file->second.Start + file->second.Len) >= (StartAddr + Length)) {
|
||||
AOTIRCache[file->second.fileid].insert({GuestRIP - file->second.Start + file->second.Offset, {StartAddr - file->second.Start + file->second.Offset, Length, hash, IRList, RAData}});
|
||||
AOTIRCaptureCache[file->second.fileid].insert({GuestRIP - file->second.Start + file->second.Offset, {StartAddr - file->second.Start + file->second.Offset, Length, hash, IRList, RAData}});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1341,7 +1293,7 @@ namespace FEXCore::Context {
|
||||
auto base_filename = std::filesystem::path(filename).filename().string();
|
||||
|
||||
if (base_filename.size()) {
|
||||
auto filename_hash = fasthash64(filename.c_str(), filename.size(), 0xBAADF00D);
|
||||
auto filename_hash = XXH3_64bits(filename.c_str(), filename.size());
|
||||
|
||||
auto fileid = base_filename + "-" + std::to_string(filename_hash) + "-";
|
||||
|
||||
@@ -1351,19 +1303,28 @@ namespace FEXCore::Context {
|
||||
fileid += Config.ABILocalFlags ? "L" : "l";
|
||||
fileid += Config.ABINoPF ? "p" : "P";
|
||||
|
||||
AddrToFile.insert({ Base, { Base, Size, Offset, fileid, nullptr } });
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
|
||||
AddrToFile.insert({ Base, { Base, Size, Offset, fileid, filename, nullptr, false} });
|
||||
|
||||
if (Config.AOTIRLoad && !AOTIRCache.contains(fileid) && AOTIRLoader) {
|
||||
auto stream = AOTIRLoader(fileid);
|
||||
if (*stream) {
|
||||
LoadAOTIRCache(*stream);
|
||||
auto streamfd = AOTIRLoader(fileid);
|
||||
if (streamfd != -1) {
|
||||
LoadAOTIRCache(streamfd);
|
||||
close(streamfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::RemoveNamedRegion(uintptr_t Base, uintptr_t Size) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
// TODO: Support partial removing
|
||||
AddrToFile.erase(Base);
|
||||
}
|
||||
|
||||
void ConfigureAOTGen(FEXCore::Context::Context *CTX, std::set<uint64_t> *ExternalBranches, uint64_t SectionMaxAddress) {
|
||||
CTX->ParentThread->FrontendDecoder->SetExternalBranches(ExternalBranches);
|
||||
CTX->ParentThread->FrontendDecoder->SetSectionMaxAddress(SectionMaxAddress);
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,7 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::
|
||||
// We want to ensure that we are 16 byte aligned at the top of this loop
|
||||
Align16B();
|
||||
aarch64::Label FullLookup{};
|
||||
aarch64::Label CallBlock{};
|
||||
aarch64::Label LoopTop{};
|
||||
aarch64::Label ExitSpillSRA{};
|
||||
aarch64::Label ThreadPauseHandler{};
|
||||
@@ -79,16 +80,19 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::
|
||||
ldr(x2, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip)));
|
||||
auto RipReg = x2;
|
||||
|
||||
if (!config.ExecuteBlocksWithCall) {
|
||||
// L1 Cache
|
||||
ldr(x0, &l_L1Ptr);
|
||||
// L1 Cache
|
||||
ldr(x0, &l_L1Ptr);
|
||||
|
||||
and_(x3, RipReg, LookupCache::L1_ENTRIES_MASK);
|
||||
add(x0, x0, Operand(x3, Shift::LSL, 4));
|
||||
ldp(x1, x0, MemOperand(x0));
|
||||
cmp(x0, RipReg);
|
||||
b(&FullLookup, Condition::ne);
|
||||
br(x1);
|
||||
and_(x3, RipReg, LookupCache::L1_ENTRIES_MASK);
|
||||
add(x0, x0, Operand(x3, Shift::LSL, 4));
|
||||
ldp(x3, x0, MemOperand(x0));
|
||||
cmp(x0, RipReg);
|
||||
b(&FullLookup, Condition::ne);
|
||||
|
||||
if (!config.ExecuteBlocksWithCall) {
|
||||
br(x3);
|
||||
} else {
|
||||
b(&CallBlock);
|
||||
}
|
||||
|
||||
// L1C check failed, do a full lookup
|
||||
@@ -136,40 +140,37 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::
|
||||
|
||||
// If we've made it here then we have a real compiled block
|
||||
{
|
||||
// update L1 cache
|
||||
ldr(x0, &l_L1Ptr);
|
||||
|
||||
and_(x1, RipReg, LookupCache::L1_ENTRIES_MASK);
|
||||
add(x0, x0, Operand(x1, Shift::LSL, 4));
|
||||
stp(x3, x2, MemOperand(x0));
|
||||
|
||||
// Jump to the block
|
||||
if (!config.ExecuteBlocksWithCall) {
|
||||
// update L1 cache
|
||||
ldr(x0, &l_L1Ptr);
|
||||
|
||||
and_(x1, RipReg, LookupCache::L1_ENTRIES_MASK);
|
||||
add(x0, x0, Operand(x1, Shift::LSL, 4));
|
||||
stp(x3, x2, MemOperand(x0));
|
||||
|
||||
br(x3);
|
||||
} else {
|
||||
bind(&CallBlock);
|
||||
mov(x0, STATE);
|
||||
blr(x3);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.ExecuteBlocksWithCall) {
|
||||
// Interpreter continues execution here
|
||||
if (CTX->GetGdbServerStatus()) {
|
||||
// If we have a gdb server running then run in a less efficient mode that checks if we need to exit
|
||||
// This happens when single stepping
|
||||
if (CTX->GetGdbServerStatus()) {
|
||||
// If we have a gdb server running then run in a less efficient mode that checks if we need to exit
|
||||
// This happens when single stepping
|
||||
|
||||
static_assert(sizeof(CTX->Config.RunningMode) == 4, "This is expected to be size of 4");
|
||||
ldr(x0, &l_CTX);
|
||||
ldr(w0, MemOperand(x0, offsetof(FEXCore::Context::Context, Config.RunningMode)));
|
||||
// If the value == 0 then branch to the top
|
||||
cbz(x0, &LoopTop);
|
||||
// Else we need to pause now
|
||||
b(&ThreadPauseHandler);
|
||||
}
|
||||
else {
|
||||
// Unconditionally loop to the top
|
||||
// We will only stop on error when compiling a block or signal
|
||||
b(&LoopTop);
|
||||
static_assert(sizeof(CTX->Config.RunningMode) == 4, "This is expected to be size of 4");
|
||||
ldr(x0, &l_CTX);
|
||||
ldr(w0, MemOperand(x0, offsetof(FEXCore::Context::Context, Config.RunningMode)));
|
||||
// If the value == 0 then branch to the top
|
||||
cbz(x0, &LoopTop);
|
||||
// Else we need to pause now
|
||||
b(&ThreadPauseHandler);
|
||||
} else {
|
||||
// Unconditionally loop to the top
|
||||
// We will only stop on error when compiling a block or signal
|
||||
b(&LoopTop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,7 +351,7 @@ void InterpreterCore::CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore:
|
||||
DispatcherConfig config;
|
||||
config.ExecuteBlocksWithCall = true;
|
||||
|
||||
Dispatcher = new Arm64Dispatcher(ctx, Thread, config);
|
||||
Dispatcher = std::make_unique<Arm64Dispatcher>(ctx, Thread, config);
|
||||
DispatchPtr = Dispatcher->DispatchPtr;
|
||||
CallbackPtr = Dispatcher->CallbackPtr;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
|
||||
if (GuestAction->sa_flags & SA_SIGINFO) {
|
||||
if (SRAEnabled) {
|
||||
if (!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), false)) {
|
||||
LogMan::Throw::A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
|
||||
LOGMAN_THROW_A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
|
||||
} else {
|
||||
// We are in jit, SRA must be spilled
|
||||
SpillSRA(ucontext);
|
||||
@@ -121,7 +121,11 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
|
||||
NewGuestSP -= sizeof(FEXCore::x86_64::ucontext_t);
|
||||
uint64_t UContextLocation = NewGuestSP;
|
||||
|
||||
NewGuestSP -= sizeof(siginfo_t);
|
||||
uint64_t SigInfoLocation = NewGuestSP;
|
||||
|
||||
FEXCore::x86_64::ucontext_t *guest_uctx = reinterpret_cast<FEXCore::x86_64::ucontext_t*>(UContextLocation);
|
||||
siginfo_t *guest_siginfo = reinterpret_cast<siginfo_t*>(SigInfoLocation);
|
||||
|
||||
// We have extended float information
|
||||
guest_uctx->uc_flags |= FEXCore::x86_64::UC_FP_XSTATE;
|
||||
@@ -169,8 +173,21 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
|
||||
guest_uctx->uc_stack.ss_sp = GuestStack->ss_sp;
|
||||
guest_uctx->uc_stack.ss_size = GuestStack->ss_size;
|
||||
|
||||
// XXX: siginfo_t(RSI)
|
||||
Frame->State.gregs[X86State::REG_RSI] = 0x4142434445460000;
|
||||
// siginfo_t
|
||||
siginfo_t *HostSigInfo = reinterpret_cast<siginfo_t*>(info);
|
||||
guest_siginfo->si_signo = Signal;
|
||||
switch (Signal) {
|
||||
case SIGSEGV:
|
||||
case SIGBUS:
|
||||
guest_siginfo->si_code = HostSigInfo->si_code;
|
||||
guest_siginfo->si_errno = HostSigInfo->si_errno;
|
||||
// Macro expansion to get the si_addr
|
||||
guest_siginfo->si_addr = HostSigInfo->si_addr;
|
||||
break;
|
||||
default: LogMan::Msg::D("Unhandled siginfo_t signal: %d", Signal); break;
|
||||
}
|
||||
|
||||
Frame->State.gregs[X86State::REG_RSI] = SigInfoLocation;
|
||||
Frame->State.gregs[X86State::REG_RDX] = UContextLocation;
|
||||
}
|
||||
else {
|
||||
@@ -203,7 +220,7 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
|
||||
else {
|
||||
NewGuestSP -= 4;
|
||||
*(uint32_t*)NewGuestSP = CTX->X86CodeGen.SignalReturn;
|
||||
LogMan::Throw::A(CTX->X86CodeGen.SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB");
|
||||
LOGMAN_THROW_A(CTX->X86CodeGen.SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB");
|
||||
Frame->State.gregs[X86State::REG_RSP] = NewGuestSP;
|
||||
}
|
||||
|
||||
@@ -247,7 +264,7 @@ bool Dispatcher::HandleSignalPause(int Signal, void *info, void *ucontext) {
|
||||
} else {
|
||||
if (SRAEnabled) {
|
||||
// We are in non-jit, SRA is already spilled
|
||||
LogMan::Throw::A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
|
||||
LOGMAN_THROW_A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
|
||||
}
|
||||
ArchHelpers::Context::SetPc(ucontext, ThreadPauseHandlerAddress);
|
||||
}
|
||||
@@ -282,7 +299,7 @@ bool Dispatcher::HandleSignalPause(int Signal, void *info, void *ucontext) {
|
||||
} else {
|
||||
if (SRAEnabled) {
|
||||
// We are in non-jit, SRA is already spilled
|
||||
LogMan::Throw::A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
|
||||
LOGMAN_THROW_A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
|
||||
}
|
||||
ArchHelpers::Context::SetPc(ucontext, ThreadStopHandlerAddress);
|
||||
}
|
||||
@@ -306,14 +323,14 @@ bool Dispatcher::HandleSignalPause(int Signal, void *info, void *ucontext) {
|
||||
}
|
||||
|
||||
uint64_t Dispatcher::GetCompileBlockPtr() {
|
||||
using ClassPtrType = uintptr_t (FEXCore::Context::Context::*)(FEXCore::Core::CpuStateFrame *, uint64_t);
|
||||
using ClassPtrType = void (FEXCore::Context::Context::*)(FEXCore::Core::CpuStateFrame *, uint64_t);
|
||||
union PtrCast {
|
||||
ClassPtrType ClassPtr;
|
||||
uintptr_t Data;
|
||||
};
|
||||
|
||||
PtrCast CompileBlockPtr;
|
||||
CompileBlockPtr.ClassPtr = &FEXCore::Context::Context::CompileBlock;
|
||||
CompileBlockPtr.ClassPtr = &FEXCore::Context::Context::CompileBlockJit;
|
||||
return CompileBlockPtr.Data;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ struct DispatcherConfig {
|
||||
|
||||
class Dispatcher {
|
||||
public:
|
||||
virtual ~Dispatcher() = default;
|
||||
CPUBackend::AsmDispatch DispatchPtr;
|
||||
CPUBackend::JITCallback CallbackPtr;
|
||||
FEXCore::Context::Context::IntCallbackReturn ReturnPtr;
|
||||
@@ -81,4 +82,4 @@ private:
|
||||
std::vector<std::tuple<uint64_t, uint64_t>> CodeBuffers; // Start, End
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ static constexpr size_t MAX_DISPATCHER_CODE_SIZE = 4096;
|
||||
|
||||
X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, DispatcherConfig &config)
|
||||
: Dispatcher(ctx, Thread)
|
||||
, Xbyak::CodeGenerator(MAX_DISPATCHER_CODE_SIZE) {
|
||||
, Xbyak::CodeGenerator(MAX_DISPATCHER_CODE_SIZE, nullptr, this) {
|
||||
|
||||
using namespace Xbyak;
|
||||
using namespace Xbyak::util;
|
||||
@@ -66,6 +66,7 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
|
||||
|
||||
Label LoopTop;
|
||||
Label FullLookup;
|
||||
Label CallBlock;
|
||||
Label NoBlock;
|
||||
Label ExitBlock;
|
||||
Label ThreadPauseHandler;
|
||||
@@ -77,17 +78,20 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
|
||||
// Load our RIP
|
||||
mov(rdx, qword [STATE + offsetof(FEXCore::Core::CPUState, rip)]);
|
||||
|
||||
if (!config.ExecuteBlocksWithCall)
|
||||
{
|
||||
// L1 Cache
|
||||
mov(r13, Thread->LookupCache->GetL1Pointer());
|
||||
mov(rax, rdx);
|
||||
// L1 Cache
|
||||
mov(r13, Thread->LookupCache->GetL1Pointer());
|
||||
mov(rax, rdx);
|
||||
|
||||
and_(rax, LookupCache::L1_ENTRIES_MASK);
|
||||
shl(rax, 4);
|
||||
cmp(qword[r13 + rax + 8], rdx);
|
||||
jne(FullLookup);
|
||||
and_(rax, LookupCache::L1_ENTRIES_MASK);
|
||||
shl(rax, 4);
|
||||
cmp(qword[r13 + rax + 8], rdx);
|
||||
jne(FullLookup);
|
||||
|
||||
if (!config.ExecuteBlocksWithCall) {
|
||||
jmp(qword[r13 + rax + 0]);
|
||||
} else {
|
||||
mov(rax, qword[r13 + rax + 0]);
|
||||
jmp(CallBlock);
|
||||
}
|
||||
|
||||
L(FullLookup);
|
||||
@@ -122,19 +126,19 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
|
||||
je(NoBlock);
|
||||
|
||||
// Update L1
|
||||
if (config.ExecuteBlocksWithCall) {
|
||||
mov(r13, Thread->LookupCache->GetL1Pointer());
|
||||
mov(rcx, rdx);
|
||||
and_(rcx, LookupCache::L1_ENTRIES_MASK);
|
||||
shl(rcx, 1);
|
||||
mov(qword[r13 + rcx*8 + 8], rdx);
|
||||
mov(qword[r13 + rcx*8 + 0], rax);
|
||||
}
|
||||
|
||||
mov(r13, Thread->LookupCache->GetL1Pointer());
|
||||
mov(rcx, rdx);
|
||||
and_(rcx, LookupCache::L1_ENTRIES_MASK);
|
||||
shl(rcx, 1);
|
||||
mov(qword[r13 + rcx*8 + 8], rdx);
|
||||
mov(qword[r13 + rcx*8 + 0], rax);
|
||||
|
||||
// Real block if we made it here
|
||||
if (!config.ExecuteBlocksWithCall) {
|
||||
jmp(rax);
|
||||
} else {
|
||||
L(CallBlock);
|
||||
mov(rdi, STATE);
|
||||
call(rax);
|
||||
|
||||
@@ -177,19 +181,10 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
|
||||
{
|
||||
L(NoBlock);
|
||||
|
||||
using ClassPtrType = uintptr_t (FEXCore::Context::Context::*)(FEXCore::Core::CpuStateFrame *, uint64_t);
|
||||
union PtrCast {
|
||||
ClassPtrType ClassPtr;
|
||||
uintptr_t Data;
|
||||
};
|
||||
|
||||
PtrCast Ptr;
|
||||
Ptr.ClassPtr = &FEXCore::Context::Context::CompileBlock;
|
||||
|
||||
// {rdi, rsi, rdx}
|
||||
mov(rdi, reinterpret_cast<uint64_t>(CTX));
|
||||
mov(rsi, STATE);
|
||||
mov(rax, Ptr.Data);
|
||||
mov(rax, GetCompileBlockPtr());
|
||||
|
||||
call(rax);
|
||||
|
||||
@@ -312,7 +307,7 @@ void InterpreterCore::CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore:
|
||||
DispatcherConfig config;
|
||||
config.ExecuteBlocksWithCall = true;
|
||||
|
||||
Dispatcher = new X86Dispatcher(ctx, Thread, config);
|
||||
Dispatcher = std::make_unique<X86Dispatcher>(ctx, Thread, config);
|
||||
DispatchPtr = Dispatcher->DispatchPtr;
|
||||
CallbackPtr = Dispatcher->CallbackPtr;
|
||||
|
||||
|
||||
@@ -2,16 +2,26 @@
|
||||
|
||||
#include "Interface/Core/Dispatcher/Dispatcher.h"
|
||||
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
#define XBYAK64
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
|
||||
class X86Dispatcher final : public Dispatcher, public Xbyak::CodeGenerator {
|
||||
class X86Dispatcher final : public Dispatcher, public Xbyak::CodeGenerator, public Xbyak::Allocator {
|
||||
public:
|
||||
X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, DispatcherConfig &config);
|
||||
|
||||
virtual ~X86Dispatcher() override;
|
||||
|
||||
// Xbyak::Allocator
|
||||
Xbyak::uint8 *alloc(size_t size) override { Size = size; return reinterpret_cast<uint8_t*>(FEXCore::Allocator::mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); }
|
||||
void free(Xbyak::uint8 *p) override { FEXCore::Allocator::munmap(p, Size); }
|
||||
bool useProtect() const override { return false; }
|
||||
|
||||
private:
|
||||
size_t Size{};
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
+51
-18
@@ -15,6 +15,7 @@ $end_info$
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Debug/X86Tables.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <set>
|
||||
|
||||
namespace FEXCore::Frontend {
|
||||
using namespace FEXCore::X86Tables;
|
||||
@@ -124,7 +125,7 @@ Decoder::Decoder(FEXCore::Context::Context *ctx)
|
||||
|
||||
uint8_t Decoder::ReadByte() {
|
||||
uint8_t Byte = InstStream[InstructionSize];
|
||||
LogMan::Throw::A(InstructionSize < MAX_INST_SIZE, "Max instruction size exceeded!");
|
||||
LOGMAN_THROW_A(InstructionSize < MAX_INST_SIZE, "Max instruction size exceeded!");
|
||||
Instruction[InstructionSize] = Byte;
|
||||
InstructionSize++;
|
||||
return Byte;
|
||||
@@ -141,7 +142,7 @@ uint64_t Decoder::ReadData(uint8_t Size) {
|
||||
}
|
||||
|
||||
if (Size > sizeof(uint64_t)) {
|
||||
LogMan::Msg::A("Unknown data size to read");
|
||||
LOGMAN_MSG_A("Unknown data size to read");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -284,7 +285,7 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModR
|
||||
Operand->TypeSIB.Base = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, SIB.base, false, false, false, false, ModRM.mod == 0 ? 0b101 : 16);
|
||||
|
||||
uint64_t Literal {0};
|
||||
LogMan::Throw::A(Displacement <= 4, "Number of bytes should be <= 4 for literal src");
|
||||
LOGMAN_THROW_A(Displacement <= 4, "Number of bytes should be <= 4 for literal src");
|
||||
|
||||
Literal = ReadData(Displacement);
|
||||
if (Displacement == 1) {
|
||||
@@ -343,7 +344,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(!(Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P),
|
||||
LOGMAN_THROW_A(!(Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P),
|
||||
"Group Ops should have been decoded before this!");
|
||||
|
||||
uint8_t DestSize{};
|
||||
@@ -466,7 +467,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
}
|
||||
|
||||
if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_REX_IN_BYTE)) {
|
||||
LogMan::Throw::A(!HasMODRM, "This instruction shouldn't have ModRM!");
|
||||
LOGMAN_THROW_A(!HasMODRM, "This instruction shouldn't have ModRM!");
|
||||
|
||||
// If the REX is in the byte that means the lower nibble of the OP contains the destination GPR
|
||||
// This also means that the destination is always a GPR on these ones
|
||||
@@ -475,6 +476,9 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
CurrentDest->TypeGPR.Type = DecodedOperand::TYPE_GPR;
|
||||
DecodeInst->Dest.TypeGPR.HighBits = (Is8BitDest && !HasREX && (Op & 0b111) >= 0b100) || HasHighXMM;
|
||||
CurrentDest->TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, Op & 0b111, Is8BitDest, HasREX, false, false);
|
||||
|
||||
if (CurrentDest->TypeGPR.GPR == FEXCore::X86State::REG_INVALID)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t Bytes = Info->MoreBytes;
|
||||
@@ -501,27 +505,36 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
GPR.TypeGPR.HighBits = (GPR8Bit && ModRM.reg >= 0b100 && !HasREX) || HasHighXMM;
|
||||
GPR.TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_R ? 1 : 0, ModRM.reg, GPR8Bit, HasREX, HasXMMGPR, HasMMGPR);
|
||||
|
||||
if (GPR.TypeGPR.GPR == FEXCore::X86State::REG_INVALID)
|
||||
return false;
|
||||
|
||||
// ModRM.mod == 0b11 == Register
|
||||
// ModRM.Mod != 0b11 == Register-direct addressing
|
||||
if (ModRM.mod == 0b11) {
|
||||
NonGPR.TypeGPR.Type = DecodedOperand::TYPE_GPR;
|
||||
NonGPR.TypeGPR.HighBits = (NonGPR8Bit && ModRM.rm >= 0b100 && !HasREX) || HasHighXMM;
|
||||
NonGPR.TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, NonGPR8Bit, HasREX, HasXMMNonGPR, HasMMNonGPR);
|
||||
if (NonGPR.TypeGPR.GPR == FEXCore::X86State::REG_INVALID)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
auto Disp = DecodeModRMs_Disp[Has16BitAddressing];
|
||||
(this->*Disp)(&NonGPR, ModRM);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
size_t CurrentSrc = 0;
|
||||
|
||||
if (Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MODRM) {
|
||||
if (Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SF_MOD_DST) {
|
||||
ModRMOperand(DecodeInst->Src[CurrentSrc], DecodeInst->Dest, HasXMMSrc, HasXMMDst, HasMMSrc, HasMMDst, Is8BitSrc, Is8BitDest);
|
||||
if (!ModRMOperand(DecodeInst->Src[CurrentSrc], DecodeInst->Dest, HasXMMSrc, HasXMMDst, HasMMSrc, HasMMDst, Is8BitSrc, Is8BitDest))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
ModRMOperand(DecodeInst->Dest, DecodeInst->Src[CurrentSrc], HasXMMDst, HasXMMSrc, HasMMDst, HasMMSrc, Is8BitDest, Is8BitSrc);
|
||||
if (!ModRMOperand(DecodeInst->Dest, DecodeInst->Src[CurrentSrc], HasXMMDst, HasXMMSrc, HasMMDst, HasMMSrc, Is8BitDest, Is8BitSrc))
|
||||
return false;
|
||||
}
|
||||
++CurrentSrc;
|
||||
}
|
||||
@@ -540,7 +553,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
}
|
||||
|
||||
if (Bytes != 0) {
|
||||
LogMan::Throw::A(Bytes <= 8, "Number of bytes should be <= 8 for literal src");
|
||||
LOGMAN_THROW_A(Bytes <= 8, "Number of bytes should be <= 8 for literal src");
|
||||
|
||||
DecodeInst->Src[CurrentSrc].TypeLiteral.Size = Bytes;
|
||||
|
||||
@@ -566,7 +579,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
DecodeInst->Src[CurrentSrc].TypeLiteral.Literal = Literal;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(Bytes == 0, "Inst at 0x%lx: 0x%04x '%s' Had an instruction of size %d with %d remaining", DecodeInst->PC, DecodeInst->OP, DecodeInst->TableInfo->Name, InstructionSize, Bytes);
|
||||
LOGMAN_THROW_A(Bytes == 0, "Inst at 0x%lx: 0x%04x '%s' Had an instruction of size %d with %d remaining", DecodeInst->PC, DecodeInst->OP, DecodeInst->TableInfo->Name, InstructionSize, Bytes);
|
||||
DecodeInst->InstSize = InstructionSize;
|
||||
return true;
|
||||
}
|
||||
@@ -591,7 +604,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, "REX PREFIX should have been decoded before this!");
|
||||
LOGMAN_THROW_A(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, "REX PREFIX should have been decoded before this!");
|
||||
|
||||
if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 &&
|
||||
Info->Type <= FEXCore::X86Tables::TYPE_GROUP_11) {
|
||||
@@ -647,7 +660,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
|
||||
3,
|
||||
};
|
||||
uint8_t Field = RegToField[ModRM.reg];
|
||||
LogMan::Throw::A(Field != 255, "Invalid field selected!");
|
||||
LOGMAN_THROW_A(Field != 255, "Invalid field selected!");
|
||||
|
||||
LocalOp = (Field << 3) | ModRM.rm;
|
||||
return NormalOp(&SecondModRMTableOps[LocalOp], LocalOp);
|
||||
@@ -681,7 +694,10 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
|
||||
uint8_t Byte2 = ReadByte();
|
||||
pp = Byte2 & 0b11;
|
||||
map_select = Byte1 & 0b11111;
|
||||
LogMan::Throw::A(map_select >= 1 && map_select <= 3, "We don't understand a map_select of: %d", map_select);
|
||||
if (!(map_select >= 1 && map_select <= 3)) {
|
||||
LogMan::Msg::E("We don't understand a map_select of: %d", map_select);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t VEXOp = ReadByte();
|
||||
@@ -729,6 +745,8 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
DecodeInst->PC = PC;
|
||||
|
||||
for(;;) {
|
||||
if (InstructionSize >= MAX_INST_SIZE)
|
||||
return false;
|
||||
uint8_t Op = ReadByte();
|
||||
switch (Op) {
|
||||
case 0x0F: {// Escape Op
|
||||
@@ -879,7 +897,7 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
auto Info = &FEXCore::X86Tables::BaseOps[Op];
|
||||
|
||||
if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode");
|
||||
LOGMAN_THROW_A(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode");
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX;
|
||||
|
||||
// Widening displacement
|
||||
@@ -909,6 +927,10 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
|
||||
}
|
||||
|
||||
if (DecodeInst->Dest.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR) {
|
||||
assert(DecodeInst->Dest.TypeGPR.GPR != 255);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -928,19 +950,23 @@ void Decoder::BranchTargetInMultiblockRange() {
|
||||
// auto RIPOffset = LoadSource(Op, Op->Src[0], Op->Flags);
|
||||
// auto RIPTargetConst = _Constant(Op->PC + Op->InstSize);
|
||||
// Target offset is PC + InstSize + Literal
|
||||
LogMan::Throw::A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
|
||||
LOGMAN_THROW_A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
|
||||
TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].TypeLiteral.Literal;
|
||||
break;
|
||||
}
|
||||
case 0xE9:
|
||||
case 0xEB: // Both are unconditional JMP instructions
|
||||
LogMan::Throw::A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
|
||||
LOGMAN_THROW_A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
|
||||
TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].TypeLiteral.Literal;
|
||||
Conditional = false;
|
||||
break;
|
||||
case 0xE8: // Call - Immediate target, We don't want to inline calls
|
||||
if (ExternalBranches) {
|
||||
ExternalBranches->insert(DecodeInst->PC + DecodeInst->InstSize);
|
||||
}
|
||||
[[fallthrough]];
|
||||
case 0xC2: // RET imm
|
||||
case 0xC3: // RET
|
||||
case 0xE8: // Call - Immediate target, We don't want to inline calls
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
@@ -970,6 +996,10 @@ void Decoder::BranchTargetInMultiblockRange() {
|
||||
BlocksToDecode.find(TargetRIP) == BlocksToDecode.end()) {
|
||||
BlocksToDecode.emplace(TargetRIP);
|
||||
}
|
||||
} else {
|
||||
if (ExternalBranches) {
|
||||
ExternalBranches->insert(TargetRIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -993,7 +1023,7 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
|
||||
// If we don't have symbols available then we become a bit optimistic about multiblock ranges
|
||||
if (!SymbolAvailable) {
|
||||
// If we don't have a symbol available then assume all branches are valid for multiblock
|
||||
SymbolMaxAddress = ~0ULL;
|
||||
SymbolMaxAddress = SectionMaxAddress;
|
||||
SymbolMinAddress = EntryPoint;
|
||||
}
|
||||
|
||||
@@ -1023,7 +1053,10 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
|
||||
|
||||
if (ErrorDuringDecoding) {
|
||||
LogMan::Msg::D("Couldn't Decode something at 0x%lx, Started at 0x%lx", PC + PCOffset, PC);
|
||||
LogMan::Throw::A(Blocks.size() != 1, "Decode Error in entry block");
|
||||
if (Blocks.size() == 1) {
|
||||
return false;
|
||||
}
|
||||
LOGMAN_THROW_A(Blocks.size() != 1, "Decode Error in entry block");
|
||||
|
||||
CurrentBlockDecoding.HasInvalidInstruction = true;
|
||||
if (ErrorDuringDecoding && Blocks.size() != 1) {
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
uint64_t DecodedMinAddress {};
|
||||
uint64_t DecodedMaxAddress {~0ULL};
|
||||
|
||||
void SetSectionMaxAddress(uint64_t v) { SectionMaxAddress = v; }
|
||||
void SetExternalBranches(std::set<uint64_t> *v) { ExternalBranches = v; }
|
||||
private:
|
||||
FEXCore::Context::Context *CTX;
|
||||
|
||||
@@ -65,10 +67,12 @@ private:
|
||||
uint64_t MaxCondBranchBackwards {~0ULL};
|
||||
uint64_t SymbolMaxAddress {};
|
||||
uint64_t SymbolMinAddress {~0ULL};
|
||||
uint64_t SectionMaxAddress {~0ULL};
|
||||
|
||||
std::vector<DecodedBlocks> Blocks;
|
||||
std::set<uint64_t> BlocksToDecode;
|
||||
std::set<uint64_t> HasBlocks;
|
||||
std::set<uint64_t> *ExternalBranches {nullptr};
|
||||
|
||||
// ModRM rm decoding
|
||||
using DecodeModRMPtr = void (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM);
|
||||
|
||||
@@ -22,9 +22,8 @@ using DestMapType = std::vector<uint32_t>;
|
||||
class InterpreterCore final : public CPUBackend {
|
||||
public:
|
||||
explicit InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, bool CompileThread);
|
||||
~InterpreterCore() override;
|
||||
std::string GetName() override { return "Interpreter"; }
|
||||
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||
|
||||
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
||||
|
||||
@@ -46,7 +45,7 @@ private:
|
||||
template<typename Res>
|
||||
Res GetSrc(void* SSAData, IR::OrderedNodeWrapper Src);
|
||||
|
||||
Dispatcher *Dispatcher{};
|
||||
std::unique_ptr<Dispatcher> Dispatcher{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ static void InterpreterExecution(FEXCore::Core::CpuStateFrame *Frame) {
|
||||
|
||||
auto LocalEntry = Thread->LocalIRCache.find(Thread->CurrentFrame->State.rip);
|
||||
|
||||
InterpreterOps::InterpretIR(Thread, LocalEntry->second.IR.get(), LocalEntry->second.DebugData.get());
|
||||
InterpreterOps::InterpretIR(Thread, Thread->CurrentFrame->State.rip, LocalEntry->second.IR.get(), LocalEntry->second.DebugData.get());
|
||||
}
|
||||
|
||||
bool InterpreterCore::HandleSIGBUS(int Signal, void *info, void *ucontext) {
|
||||
@@ -111,13 +111,7 @@ InterpreterCore::InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InterpreterCore::~InterpreterCore() {
|
||||
delete Dispatcher;
|
||||
}
|
||||
|
||||
|
||||
void *InterpreterCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||
void *InterpreterCore::CompileCode(uint64_t Entry, [[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||
return reinterpret_cast<void*>(InterpreterExecution);
|
||||
}
|
||||
|
||||
|
||||
+167
-146
File diff suppressed because it is too large.
Load diff
@@ -36,7 +36,7 @@ namespace FEXCore::CPU {
|
||||
class InterpreterOps {
|
||||
|
||||
public:
|
||||
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData);
|
||||
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, uint64_t Entry, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData);
|
||||
static bool GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info);
|
||||
};
|
||||
};
|
||||
+37
-38
@@ -46,7 +46,7 @@ DEF_OP(TruncElementPair) {
|
||||
mov(Dst.second, Src.second);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Truncation size: %d", Op->Size); break;
|
||||
default: LOGMAN_MSG_A("Unhandled Truncation size: %d", Op->Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ DEF_OP(Constant) {
|
||||
DEF_OP(EntrypointOffset) {
|
||||
auto Op = IROp->C<IR::IROp_EntrypointOffset>();
|
||||
|
||||
auto Constant = IR->GetHeader()->Entry + Op->Offset;
|
||||
auto Constant = Entry + Op->Offset;
|
||||
auto Dst = GetReg<RA_64>(Node);
|
||||
LoadConstant(Dst, Constant);
|
||||
}
|
||||
@@ -95,7 +95,7 @@ DEF_OP(Add) {
|
||||
case 8:
|
||||
add(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Add size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Add size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
switch (OpSize) {
|
||||
@@ -105,7 +105,7 @@ DEF_OP(Add) {
|
||||
case 8:
|
||||
add(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Add size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Add size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ DEF_OP(Sub) {
|
||||
case 8:
|
||||
sub(GRS(Node), GRS(Op->Header.Args[0].ID()), Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Sub size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Sub size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
switch (OpSize) {
|
||||
@@ -131,7 +131,7 @@ DEF_OP(Sub) {
|
||||
case 8:
|
||||
sub(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Sub size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Sub size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ DEF_OP(Neg) {
|
||||
case 8:
|
||||
neg(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,12 +159,11 @@ DEF_OP(Mul) {
|
||||
switch (OpSize) {
|
||||
case 4:
|
||||
mul(Dst.W(), GetReg<RA_32>(Op->Header.Args[0].ID()), GetReg<RA_32>(Op->Header.Args[1].ID()));
|
||||
sxtw(Dst, Dst);
|
||||
break;
|
||||
case 8:
|
||||
mul(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +179,7 @@ DEF_OP(UMul) {
|
||||
case 8:
|
||||
mul(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +216,7 @@ DEF_OP(Div) {
|
||||
sdiv(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown DIV Size: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown DIV Size: %d", Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +243,7 @@ DEF_OP(UDiv) {
|
||||
udiv(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown UDIV Size: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown UDIV Size: %d", Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +290,7 @@ DEF_OP(Rem) {
|
||||
msub(GetReg<RA_64>(Node), TMP1, Divisor, Dividend);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown REM Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown REM Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +332,7 @@ DEF_OP(URem) {
|
||||
msub(GetReg<RA_64>(Node), TMP1, Divisor, Dividend);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown UREM Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown UREM Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,12 +344,12 @@ DEF_OP(MulH) {
|
||||
sxtw(TMP1, GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
sxtw(TMP2, GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
mul(TMP1, TMP1, TMP2);
|
||||
sbfx(GetReg<RA_64>(Node), TMP1, 32, 32);
|
||||
ubfx(GetReg<RA_64>(Node), TMP1, 32, 32);
|
||||
break;
|
||||
case 8:
|
||||
smulh(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +366,7 @@ DEF_OP(UMulH) {
|
||||
case 8:
|
||||
umulh(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +462,7 @@ DEF_OP(Ror) {
|
||||
break;
|
||||
}
|
||||
|
||||
default: LogMan::Msg::A("Unhandled ROR size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled ROR size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
switch (OpSize) {
|
||||
@@ -476,7 +475,7 @@ DEF_OP(Ror) {
|
||||
break;
|
||||
}
|
||||
|
||||
default: LogMan::Msg::A("Unhandled ROR size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled ROR size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,7 +494,7 @@ DEF_OP(Extr) {
|
||||
break;
|
||||
}
|
||||
|
||||
default: LogMan::Msg::A("Unhandled EXTR size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled EXTR size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +539,7 @@ DEF_OP(LDiv) {
|
||||
mov(GetReg<RA_64>(Node), x0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LDIV Size: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown LDIV Size: %d", Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,7 +582,7 @@ DEF_OP(LUDiv) {
|
||||
mov(GetReg<RA_64>(Node), x0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LUDIV Size: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown LUDIV Size: %d", Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,7 +635,7 @@ DEF_OP(LRem) {
|
||||
mov(GetReg<RA_64>(Node), x0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LREM Size: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown LREM Size: %d", Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,7 +685,7 @@ DEF_OP(LURem) {
|
||||
mov(GetReg<RA_64>(Node), x0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LUREM Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LUREM Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +699,7 @@ DEF_OP(Not) {
|
||||
case 8:
|
||||
mvn(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,7 +730,7 @@ DEF_OP(Popcount) {
|
||||
// fmov has zero extended, unused bytes are zero
|
||||
addv(VTMP1.B(), VTMP1.V8B());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Popcount size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Popcount size: %d", OpSize);
|
||||
}
|
||||
|
||||
auto Dst = GetReg<RA_32>(Node);
|
||||
@@ -780,7 +779,7 @@ DEF_OP(FindMSB) {
|
||||
clz(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
sub(Dst, TMP1, Dst);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown REV size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown REV size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,7 +800,7 @@ DEF_OP(FindTrailingZeros) {
|
||||
rbit(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
clz(GetReg<RA_64>(Node), GetReg<RA_64>(Node));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,7 +819,7 @@ DEF_OP(CountLeadingZeroes) {
|
||||
case 8:
|
||||
clz(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,7 +837,7 @@ DEF_OP(Rev) {
|
||||
case 8:
|
||||
rev(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown REV size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown REV size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,15 +859,15 @@ DEF_OP(Bfi) {
|
||||
bfi(TMP1, GetReg<RA_64>(Op->Header.Args[1].ID()), Op->lsb, Op->Width);
|
||||
mov(GetReg<RA_64>(Node), TMP1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown BFI size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown BFI size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Bfe) {
|
||||
auto Op = IROp->C<IR::IROp_Bfe>();
|
||||
uint8_t OpSize = IROp->Size;
|
||||
LogMan::Throw::A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
|
||||
LogMan::Throw::A(Op->Width != 0, "Invalid BFE width of 0");
|
||||
LOGMAN_THROW_A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
|
||||
LOGMAN_THROW_A(Op->Width != 0, "Invalid BFE width of 0");
|
||||
|
||||
auto Dst = GetReg<RA_64>(Node);
|
||||
ubfx(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()), Op->lsb, Op->Width);
|
||||
@@ -913,7 +912,7 @@ Condition MapSelectCC(IR::CondClassType Cond) {
|
||||
case FEXCore::IR::COND_MI:
|
||||
case FEXCore::IR::COND_PL:
|
||||
default:
|
||||
LogMan::Msg::A("Unsupported compare type");
|
||||
LOGMAN_MSG_A("Unsupported compare type");
|
||||
return Condition::nv;
|
||||
}
|
||||
}
|
||||
@@ -931,7 +930,7 @@ DEF_OP(Select) {
|
||||
} else if (IsFPR(Op->Cmp1.ID())) {
|
||||
fcmp(GRFCMP(Op->Cmp1.ID()), GRFCMP(Op->Cmp2.ID()));
|
||||
} else {
|
||||
LogMan::Msg::A("Select: Expected GPR or FPR");
|
||||
LOGMAN_MSG_A("Select: Expected GPR or FPR");
|
||||
}
|
||||
|
||||
auto cc = MapSelectCC(Op->Cond);
|
||||
@@ -942,7 +941,7 @@ DEF_OP(Select) {
|
||||
|
||||
if (is_const_true || is_const_false) {
|
||||
if (is_const_false != true || is_const_true != true || const_true != 1 || const_false != 0) {
|
||||
LogMan::Msg::A("Select: Unsupported compare inline parameters");
|
||||
LOGMAN_MSG_A("Select: Unsupported compare inline parameters");
|
||||
}
|
||||
cset(GRS(Node), cc);
|
||||
} else {
|
||||
@@ -966,7 +965,7 @@ DEF_OP(VExtractToGPR) {
|
||||
case 8:
|
||||
umov(GetReg<RA_64>(Node), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->Idx);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled ExtractElementSize: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled ExtractElementSize: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,7 +1013,7 @@ DEF_OP(FCmp) {
|
||||
bool set = false;
|
||||
|
||||
if (Op->Flags & (1 << IR::FCMP_FLAG_EQ)) {
|
||||
LogMan::Throw::A(IR::FCMP_FLAG_EQ == 0, "IR::FCMP_FLAG_EQ must equal 0");
|
||||
LOGMAN_THROW_A(IR::FCMP_FLAG_EQ == 0, "IR::FCMP_FLAG_EQ must equal 0");
|
||||
// EQ or unordered
|
||||
cset(Dst, Condition::eq); // Z = 1
|
||||
csinc(Dst, Dst, xzr, Condition::vc); // IF !V ? Z : 1
|
||||
|
||||
+26
-26
@@ -34,7 +34,7 @@ DEF_OP(CASPair) {
|
||||
mov(Dst.first, TMP3);
|
||||
mov(Dst.second, TMP4);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -89,7 +89,7 @@ DEF_OP(CASPair) {
|
||||
bind(&LoopExpected);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unsupported: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ DEF_OP(CAS) {
|
||||
case 2: casalh(TMP2.W(), Desired.W(), MemOperand(MemSrc)); break;
|
||||
case 4: casal(TMP2.W(), Desired.W(), MemOperand(MemSrc)); break;
|
||||
case 8: casal(TMP2.X(), Desired.X(), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unsupported: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
|
||||
}
|
||||
mov(GetReg<RA_64>(Node), TMP2);
|
||||
}
|
||||
@@ -206,7 +206,7 @@ DEF_OP(CAS) {
|
||||
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,7 @@ DEF_OP(AtomicAdd) {
|
||||
case 2: staddlh(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
case 4: staddl(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
case 8: staddl(GetReg<RA_64>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -264,7 +264,7 @@ DEF_OP(AtomicAdd) {
|
||||
cbnz(TMP2, &LoopTop);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,7 +281,7 @@ DEF_OP(AtomicSub) {
|
||||
case 2: staddlh(TMP2.W(), MemOperand(MemSrc)); break;
|
||||
case 4: staddl(TMP2.W(), MemOperand(MemSrc)); break;
|
||||
case 8: staddl(TMP2.X(), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -323,7 +323,7 @@ DEF_OP(AtomicSub) {
|
||||
cbnz(TMP2, &LoopTop);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,7 +340,7 @@ DEF_OP(AtomicAnd) {
|
||||
case 2: stclrlh(TMP2.W(), MemOperand(MemSrc)); break;
|
||||
case 4: stclrl(TMP2.W(), MemOperand(MemSrc)); break;
|
||||
case 8: stclrl(TMP2.X(), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -382,7 +382,7 @@ DEF_OP(AtomicAnd) {
|
||||
cbnz(TMP2, &LoopTop);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,7 +398,7 @@ DEF_OP(AtomicOr) {
|
||||
case 2: stsetlh(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
case 4: stsetl(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
case 8: stsetl(GetReg<RA_64>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -440,7 +440,7 @@ DEF_OP(AtomicOr) {
|
||||
cbnz(TMP2, &LoopTop);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,7 +456,7 @@ DEF_OP(AtomicXor) {
|
||||
case 2: steorlh(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
case 4: steorl(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
case 8: steorl(GetReg<RA_64>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -498,7 +498,7 @@ DEF_OP(AtomicXor) {
|
||||
cbnz(TMP2, &LoopTop);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,7 +515,7 @@ DEF_OP(AtomicSwap) {
|
||||
case 2: swplh(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 4: swpl(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 8: swpl(TMP2.X(), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -558,7 +558,7 @@ DEF_OP(AtomicSwap) {
|
||||
mov(GetReg<RA_64>(Node), TMP2.X());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,7 +573,7 @@ DEF_OP(AtomicFetchAdd) {
|
||||
case 2: ldaddalh(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 4: ldaddal(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 8: ldaddal(GetReg<RA_64>(Op->Header.Args[1].ID()), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -619,7 +619,7 @@ DEF_OP(AtomicFetchAdd) {
|
||||
mov(GetReg<RA_64>(Node), TMP2);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -635,7 +635,7 @@ DEF_OP(AtomicFetchSub) {
|
||||
case 2: ldaddalh(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 4: ldaddal(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 8: ldaddal(TMP2.X(), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -681,7 +681,7 @@ DEF_OP(AtomicFetchSub) {
|
||||
mov(GetReg<RA_64>(Node), TMP2);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -697,7 +697,7 @@ DEF_OP(AtomicFetchAnd) {
|
||||
case 2: ldclralh(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 4: ldclral(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 8: ldclral(TMP2.X(), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -743,7 +743,7 @@ DEF_OP(AtomicFetchAnd) {
|
||||
mov(GetReg<RA_64>(Node), TMP2);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,7 +758,7 @@ DEF_OP(AtomicFetchOr) {
|
||||
case 2: ldsetalh(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 4: ldsetal(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 8: ldsetal(GetReg<RA_64>(Op->Header.Args[1].ID()), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -804,7 +804,7 @@ DEF_OP(AtomicFetchOr) {
|
||||
mov(GetReg<RA_64>(Node), TMP2);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -819,7 +819,7 @@ DEF_OP(AtomicFetchXor) {
|
||||
case 2: ldeoralh(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 4: ldeoral(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
|
||||
case 8: ldeoral(GetReg<RA_64>(Op->Header.Args[1].ID()), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -865,7 +865,7 @@ DEF_OP(AtomicFetchXor) {
|
||||
mov(GetReg<RA_64>(Node), TMP2);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ DEF_OP(ExitFunction) {
|
||||
uint64_t NewRIP;
|
||||
|
||||
if (IsInlineConstant(Op->NewRIP, &NewRIP) || IsInlineEntrypointOffset(Op->NewRIP, &NewRIP)) {
|
||||
Literal l_BranchHost{Dispatcher->ExitFunctionLinkerAddress};
|
||||
Literal l_BranchHost{ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress};
|
||||
Literal l_BranchGuest{NewRIP};
|
||||
|
||||
ldr(x0, &l_BranchHost);
|
||||
@@ -96,7 +96,7 @@ DEF_OP(ExitFunction) {
|
||||
br(x1);
|
||||
|
||||
bind(&FullLookup);
|
||||
LoadConstant(TMP1, Dispatcher->AbsoluteLoopTopAddress);
|
||||
LoadConstant(TMP1, ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress);
|
||||
str(RipReg, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip)));
|
||||
br(TMP1);
|
||||
}
|
||||
@@ -142,7 +142,7 @@ Condition MapBranchCC(IR::CondClassType Cond) {
|
||||
case FEXCore::IR::COND_MI:
|
||||
case FEXCore::IR::COND_PL:
|
||||
default:
|
||||
LogMan::Msg::A("Unsupported compare type");
|
||||
LOGMAN_MSG_A("Unsupported compare type");
|
||||
return Condition::nv;
|
||||
}
|
||||
}
|
||||
@@ -169,10 +169,10 @@ DEF_OP(CondJump) {
|
||||
bool isConst = IsInlineConstant(Op->Cmp2, &Const);
|
||||
|
||||
if (isConst && Const == 0 && Op->Cond.Val == FEXCore::IR::COND_EQ) {
|
||||
LogMan::Throw::A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
|
||||
LOGMAN_THROW_A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
|
||||
cbz(GRCMP(Op->Cmp1.ID()), TrueTargetLabel);
|
||||
} else if (isConst && Const == 0 && Op->Cond.Val == FEXCore::IR::COND_NEQ) {
|
||||
LogMan::Throw::A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
|
||||
LOGMAN_THROW_A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
|
||||
cbnz(GRCMP(Op->Cmp1.ID()), TrueTargetLabel);
|
||||
} else {
|
||||
if (IsGPR(Op->Cmp1.ID())) {
|
||||
@@ -183,7 +183,7 @@ DEF_OP(CondJump) {
|
||||
} else if (IsFPR(Op->Cmp1.ID())) {
|
||||
fcmp(GRFCMP(Op->Cmp1.ID()), GRFCMP(Op->Cmp2.ID()));
|
||||
} else {
|
||||
LogMan::Msg::A("CondJump: Expected GPR or FPR");
|
||||
LOGMAN_MSG_A("CondJump: Expected GPR or FPR");
|
||||
}
|
||||
|
||||
b(TrueTargetLabel, MapBranchCC(Op->Cond));
|
||||
@@ -262,7 +262,7 @@ DEF_OP(ValidateCode) {
|
||||
int idx = 0;
|
||||
|
||||
LoadConstant(GetReg<RA_64>(Node), 0);
|
||||
LoadConstant(x0, IR->GetHeader()->Entry + Op->Offset);
|
||||
LoadConstant(x0, Entry + Op->Offset);
|
||||
LoadConstant(x1, 1);
|
||||
|
||||
while (len >= 8)
|
||||
@@ -311,7 +311,7 @@ DEF_OP(RemoveCodeEntry) {
|
||||
PushDynamicRegsAndLR();
|
||||
|
||||
mov(x0, STATE);
|
||||
LoadConstant(x1, IR->GetHeader()->Entry);
|
||||
LoadConstant(x1, Entry);
|
||||
|
||||
LoadConstant(x2, reinterpret_cast<uintptr_t>(&Context::Context::RemoveCodeEntryFromJit));
|
||||
SpillStaticRegs();
|
||||
|
||||
@@ -31,7 +31,7 @@ DEF_OP(VInsGPR) {
|
||||
ins(GetDst(Node).V2D(), Op->Index, GetReg<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,12 +52,12 @@ DEF_OP(VCastFromGPR) {
|
||||
case 8:
|
||||
fmov(GetDst(Node).D(), GetReg<RA_64>(Op->Header.Args[0].ID()).X());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Float_FromGPR_U) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(Float_FromGPR_S) {
|
||||
@@ -95,7 +95,7 @@ DEF_OP(Float_FToF) {
|
||||
fcvt(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown FCVT sizes: 0x%x", Conv);
|
||||
default: LOGMAN_MSG_A("Unknown FCVT sizes: 0x%x", Conv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ DEF_OP(Vector_UToF) {
|
||||
case 8:
|
||||
ucvtf(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ DEF_OP(Vector_SToF) {
|
||||
case 8:
|
||||
scvtf(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ DEF_OP(Vector_FToZU) {
|
||||
case 8:
|
||||
fcvtzu(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ DEF_OP(Vector_FToZS) {
|
||||
case 8:
|
||||
fcvtzs(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ DEF_OP(Vector_FToU) {
|
||||
frinti(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
fcvtzu(GetDst(Node).V2D(), GetDst(Node).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ DEF_OP(Vector_FToS) {
|
||||
frinti(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
fcvtzs(GetDst(Node).V2D(), GetDst(Node).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ DEF_OP(Vector_FToF) {
|
||||
fcvtn(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Conversion Type : 0%04x", Conv); break;
|
||||
default: LOGMAN_MSG_A("Unknown Conversion Type : 0%04x", Conv); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+67
-32
@@ -22,6 +22,7 @@ $end_info$
|
||||
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Core/UContext.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include "Interface/Core/Interpreter/InterpreterOps.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
@@ -43,7 +44,7 @@ void Arm64JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
|
||||
FallbackInfo Info;
|
||||
if (!InterpreterOps::GetFallbackHandler(IROp, &Info)) {
|
||||
auto Name = FEXCore::IR::GetName(IROp->Op);
|
||||
LogMan::Msg::A("Unhandled IR Op: %s", std::string(Name).c_str());
|
||||
LOGMAN_MSG_A("Unhandled IR Op: %s", std::string(Name).c_str());
|
||||
} else {
|
||||
switch(Info.ABI) {
|
||||
case FABI_VOID_U16:{
|
||||
@@ -291,7 +292,7 @@ void Arm64JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
|
||||
case FABI_UNKNOWN:
|
||||
default:
|
||||
auto Name = FEXCore::IR::GetName(IROp->Op);
|
||||
LogMan::Msg::A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
|
||||
LOGMAN_MSG_A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,18 +304,18 @@ Arm64JITCore::CodeBuffer Arm64JITCore::AllocateNewCodeBuffer(size_t Size) {
|
||||
CodeBuffer Buffer;
|
||||
Buffer.Size = Size;
|
||||
Buffer.Ptr = static_cast<uint8_t*>(
|
||||
mmap(nullptr,
|
||||
FEXCore::Allocator::mmap(nullptr,
|
||||
Buffer.Size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0));
|
||||
LogMan::Throw::A(!!Buffer.Ptr, "Couldn't allocate code buffer");
|
||||
LOGMAN_THROW_A(!!Buffer.Ptr, "Couldn't allocate code buffer");
|
||||
Dispatcher->RegisterCodeBuffer(Buffer.Ptr, Buffer.Size);
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
void Arm64JITCore::FreeCodeBuffer(CodeBuffer Buffer) {
|
||||
munmap(Buffer.Ptr, Buffer.Size);
|
||||
FEXCore::Allocator::munmap(Buffer.Ptr, Buffer.Size);
|
||||
Dispatcher->RemoveCodeBuffer(Buffer.Ptr);
|
||||
}
|
||||
|
||||
@@ -359,6 +360,34 @@ bool Arm64JITCore::HandleSIGBUS(int Signal, void *info, void *ucontext) {
|
||||
// Back up one instruction and have another go
|
||||
ArchHelpers::Context::SetPc(ucontext, ArchHelpers::Context::GetPc(ucontext) - 4);
|
||||
}
|
||||
else if ((Instr & FEXCore::ArchHelpers::Arm64::LDAXP_MASK) == FEXCore::ArchHelpers::Arm64::LDAXP_INST) { // LDAXP
|
||||
uint32_t DataReg2 = (Instr >> 10) & 0x1F;
|
||||
// Convert to LDP
|
||||
uint32_t LDP = 0b0010'1001'0100'0000'0000'0000'0000'0000;
|
||||
LDP |= Size << 31;
|
||||
LDP |= DataReg2 << 10;
|
||||
LDP |= AddrReg << 5;
|
||||
LDP |= DataReg;
|
||||
PC[-1] = DMB;
|
||||
PC[0] = LDP;
|
||||
PC[1] = DMB;
|
||||
// Back up one instruction and have another go
|
||||
ArchHelpers::Context::SetPc(ucontext, ArchHelpers::Context::GetPc(ucontext) - 4);
|
||||
}
|
||||
else if ((Instr & FEXCore::ArchHelpers::Arm64::STLXP_MASK) == FEXCore::ArchHelpers::Arm64::STLXP_INST) { // STLXP
|
||||
uint32_t DataReg2 = (Instr >> 10) & 0x1F;
|
||||
// Convert to STP
|
||||
uint32_t STP = 0b0010'1001'0000'0000'0000'0000'0000'0000;
|
||||
STP |= Size << 31;
|
||||
STP |= DataReg2 << 10;
|
||||
STP |= AddrReg << 5;
|
||||
STP |= DataReg;
|
||||
PC[-1] = DMB;
|
||||
PC[0] = STP;
|
||||
PC[1] = DMB;
|
||||
// Back up one instruction and have another go
|
||||
ArchHelpers::Context::SetPc(ucontext, ArchHelpers::Context::GetPc(ucontext) - 4);
|
||||
}
|
||||
else if ((Instr & FEXCore::ArchHelpers::Arm64::CASPAL_MASK) == FEXCore::ArchHelpers::Arm64::CASPAL_INST) { // CASPAL
|
||||
if (FEXCore::ArchHelpers::Arm64::HandleCASPAL(ucontext, info, Instr)) {
|
||||
// Skip this instruction now
|
||||
@@ -412,7 +441,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::Intern
|
||||
config.ExitFunctionLinkThis = reinterpret_cast<uintptr_t>(this);
|
||||
config.StaticRegisterAssignment = true;
|
||||
|
||||
Dispatcher = new Arm64Dispatcher(CTX, ThreadState, config);
|
||||
Dispatcher = std::make_unique<Arm64Dispatcher>(CTX, ThreadState, config);
|
||||
DispatchPtr = Dispatcher->DispatchPtr;
|
||||
CallbackPtr = Dispatcher->CallbackPtr;
|
||||
}
|
||||
@@ -466,6 +495,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::Intern
|
||||
if (!CompileThread) {
|
||||
ThreadSharedData.SignalHandlerRefCounterPtr = &Dispatcher->SignalHandlerRefCounter;
|
||||
ThreadSharedData.SignalReturnInstruction = Dispatcher->SignalHandlerReturnAddress;
|
||||
ThreadSharedData.Dispatcher = Dispatcher.get();
|
||||
|
||||
// This will register the host signal handler per thread, which is fine
|
||||
CTX->SignalDelegation->RegisterHostSignalHandler(SIGILL, [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool {
|
||||
@@ -545,72 +575,76 @@ Arm64JITCore::~Arm64JITCore() {
|
||||
FreeCodeBuffer(InitialCodeBuffer);
|
||||
}
|
||||
|
||||
static IR::PhysicalRegister GetPhys(IR::RegisterAllocationData *RAData, uint32_t Node) {
|
||||
IR::PhysicalRegister Arm64JITCore::GetPhys(uint32_t Node) {
|
||||
auto PhyReg = RAData->GetNodeRegister(Node);
|
||||
|
||||
LogMan::Throw::A(!PhyReg.IsInvalid(), "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
|
||||
LOGMAN_THROW_A(!PhyReg.IsInvalid(), "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
|
||||
|
||||
return PhyReg;
|
||||
}
|
||||
|
||||
template<>
|
||||
aarch64::Register Arm64JITCore::GetReg<Arm64JITCore::RA_32>(uint32_t Node) {
|
||||
auto Reg = GetPhys(RAData, Node);
|
||||
auto Reg = GetPhys(Node);
|
||||
|
||||
if (Reg.Class == IR::GPRFixedClass.Val) {
|
||||
return SRA64[Reg.Reg].W();
|
||||
} else if (Reg.Class == IR::GPRClass.Val) {
|
||||
return RA64[Reg.Reg].W();
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
|
||||
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<>
|
||||
aarch64::Register Arm64JITCore::GetReg<Arm64JITCore::RA_64>(uint32_t Node) {
|
||||
auto Reg = GetPhys(RAData, Node);
|
||||
auto Reg = GetPhys(Node);
|
||||
|
||||
if (Reg.Class == IR::GPRFixedClass.Val) {
|
||||
return SRA64[Reg.Reg];
|
||||
} else if (Reg.Class == IR::GPRClass.Val) {
|
||||
return RA64[Reg.Reg];
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
|
||||
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::pair<aarch64::Register, aarch64::Register> Arm64JITCore::GetSrcPair<Arm64JITCore::RA_32>(uint32_t Node) {
|
||||
uint32_t Reg = GetPhys(RAData, Node).Reg;
|
||||
uint32_t Reg = GetPhys(Node).Reg;
|
||||
return RA32Pair[Reg];
|
||||
}
|
||||
|
||||
template<>
|
||||
std::pair<aarch64::Register, aarch64::Register> Arm64JITCore::GetSrcPair<Arm64JITCore::RA_64>(uint32_t Node) {
|
||||
uint32_t Reg = GetPhys(RAData, Node).Reg;
|
||||
uint32_t Reg = GetPhys(Node).Reg;
|
||||
return RA64Pair[Reg];
|
||||
}
|
||||
|
||||
aarch64::VRegister Arm64JITCore::GetSrc(uint32_t Node) {
|
||||
auto Reg = GetPhys(RAData, Node);
|
||||
auto Reg = GetPhys(Node);
|
||||
|
||||
if (Reg.Class == IR::FPRFixedClass.Val) {
|
||||
return SRAFPR[Reg.Reg];
|
||||
} else if (Reg.Class == IR::FPRClass.Val) {
|
||||
return RAFPR[Reg.Reg];
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
|
||||
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
aarch64::VRegister Arm64JITCore::GetDst(uint32_t Node) {
|
||||
auto Reg = GetPhys(RAData, Node);
|
||||
auto Reg = GetPhys(Node);
|
||||
|
||||
if (Reg.Class == IR::FPRFixedClass.Val) {
|
||||
return SRAFPR[Reg.Reg];
|
||||
} else if (Reg.Class == IR::FPRClass.Val) {
|
||||
return RAFPR[Reg.Reg];
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
|
||||
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -635,7 +669,7 @@ bool Arm64JITCore::IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode,
|
||||
if (OpHeader->Op == IR::IROps::OP_INLINEENTRYPOINTOFFSET) {
|
||||
auto Op = OpHeader->C<IR::IROp_InlineEntrypointOffset>();
|
||||
if (Value) {
|
||||
*Value = IR->GetHeader()->Entry + Op->Offset;
|
||||
*Value = Entry + Op->Offset;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
@@ -644,7 +678,7 @@ bool Arm64JITCore::IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode,
|
||||
}
|
||||
|
||||
FEXCore::IR::RegisterClassType Arm64JITCore::GetRegClass(uint32_t Node) {
|
||||
return FEXCore::IR::RegisterClassType {GetPhys(RAData, Node).Class};
|
||||
return FEXCore::IR::RegisterClassType {GetPhys(Node).Class};
|
||||
}
|
||||
|
||||
|
||||
@@ -660,17 +694,18 @@ bool Arm64JITCore::IsGPR(uint32_t Node) {
|
||||
return Class == IR::GPRClass || Class == IR::GPRFixedClass;
|
||||
}
|
||||
|
||||
void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||
void *Arm64JITCore::CompileCode(uint64_t Entry, [[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||
using namespace aarch64;
|
||||
JumpTargets.clear();
|
||||
uint32_t SSACount = IR->GetSSACount();
|
||||
|
||||
this->Entry = Entry;
|
||||
this->RAData = RAData;
|
||||
|
||||
auto HeaderOp = IR->GetHeader();
|
||||
|
||||
#ifndef NDEBUG
|
||||
LoadConstant(x0, HeaderOp->Entry);
|
||||
LoadConstant(x0, Entry);
|
||||
#endif
|
||||
|
||||
this->IR = IR;
|
||||
@@ -702,7 +737,7 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
|
||||
// X4-r18 = RA
|
||||
|
||||
auto Buffer = GetBuffer();
|
||||
auto Entry = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
|
||||
auto GuestEntry = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
|
||||
|
||||
if (CTX->GetGdbServerStatus()) {
|
||||
aarch64::Label RunBlock;
|
||||
@@ -719,17 +754,17 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
|
||||
cbz(w0, &RunBlock);
|
||||
{
|
||||
// Make sure RIP is syncronized to the context
|
||||
LoadConstant(x0, HeaderOp->Entry);
|
||||
LoadConstant(x0, Entry);
|
||||
str(x0, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip)));
|
||||
|
||||
// Stop the thread
|
||||
LoadConstant(x0, Dispatcher->ThreadPauseHandlerAddressSpillSRA);
|
||||
LoadConstant(x0, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddressSpillSRA);
|
||||
br(x0);
|
||||
}
|
||||
bind(&RunBlock);
|
||||
}
|
||||
|
||||
//LogMan::Throw::A(RAData->HasFullRA(), "Arm64 JIT only works with RA");
|
||||
//LOGMAN_THROW_A(RAData->HasFullRA(), "Arm64 JIT only works with RA");
|
||||
|
||||
SpillSlots = RAData->SpillSlots();
|
||||
|
||||
@@ -747,7 +782,7 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
|
||||
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
|
||||
using namespace FEXCore::IR;
|
||||
auto BlockIROp = BlockHeader->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
LOGMAN_THROW_A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
|
||||
{
|
||||
uint32_t Node = IR->GetID(BlockNode);
|
||||
@@ -793,15 +828,15 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
|
||||
FinalizeCode();
|
||||
|
||||
auto CodeEnd = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
|
||||
CPU.EnsureIAndDCacheCoherency(reinterpret_cast<void*>(Entry), CodeEnd - reinterpret_cast<uint64_t>(Entry));
|
||||
CPU.EnsureIAndDCacheCoherency(reinterpret_cast<void*>(GuestEntry), CodeEnd - reinterpret_cast<uint64_t>(GuestEntry));
|
||||
|
||||
if (DebugData) {
|
||||
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(CodeEnd) - reinterpret_cast<uintptr_t>(Entry);
|
||||
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(CodeEnd) - reinterpret_cast<uintptr_t>(GuestEntry);
|
||||
}
|
||||
|
||||
this->IR = nullptr;
|
||||
|
||||
return reinterpret_cast<void*>(Entry);
|
||||
return reinterpret_cast<void*>(GuestEntry);
|
||||
}
|
||||
|
||||
uint64_t Arm64JITCore::ExitFunctionLink(Arm64JITCore *core, FEXCore::Core::CpuStateFrame *Frame, uint64_t *record) {
|
||||
@@ -813,11 +848,11 @@ uint64_t Arm64JITCore::ExitFunctionLink(Arm64JITCore *core, FEXCore::Core::CpuSt
|
||||
if (!HostCode) {
|
||||
//printf("ExitFunctionLink: Aborting, %lX not in cache\n", GuestRip);
|
||||
Frame->State.rip = GuestRip;
|
||||
return core->Dispatcher->AbsoluteLoopTopAddress;
|
||||
return core->ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress;
|
||||
}
|
||||
|
||||
uintptr_t branch = (uintptr_t)(record) - 8;
|
||||
auto LinkerAddress = core->Dispatcher->ExitFunctionLinkerAddress;
|
||||
auto LinkerAddress = core->ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress;
|
||||
|
||||
auto offset = HostCode/4 - branch/4;
|
||||
if (IsInt26(offset)) {
|
||||
|
||||
+11
-2
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
~Arm64JITCore() override;
|
||||
std::string GetName() override { return "JIT"; }
|
||||
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||
|
||||
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
||||
|
||||
@@ -63,11 +63,14 @@ public:
|
||||
void CopyNecessaryDataForCompileThread(CPUBackend *Original) override;
|
||||
|
||||
private:
|
||||
Dispatcher *Dispatcher;
|
||||
FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO);
|
||||
|
||||
std::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
|
||||
Label *PendingTargetLabel;
|
||||
FEXCore::Context::Context *CTX;
|
||||
FEXCore::Core::InternalThreadState *ThreadState;
|
||||
FEXCore::IR::IRListView const *IR;
|
||||
uint64_t Entry;
|
||||
|
||||
std::map<IR::OrderedNodeWrapper::NodeOffsetType, aarch64::Label> JumpTargets;
|
||||
|
||||
@@ -113,6 +116,8 @@ private:
|
||||
|
||||
FEXCore::IR::RegisterClassType GetRegClass(uint32_t Node);
|
||||
|
||||
IR::PhysicalRegister GetPhys(uint32_t Node);
|
||||
|
||||
bool IsFPR(uint32_t Node);
|
||||
bool IsGPR(uint32_t Node);
|
||||
|
||||
@@ -162,6 +167,7 @@ private:
|
||||
uint64_t SignalReturnInstruction{};
|
||||
|
||||
uint32_t *SignalHandlerRefCounterPtr{};
|
||||
FEXCore::CPU::Dispatcher *Dispatcher{};
|
||||
};
|
||||
|
||||
CompilerSharedData ThreadSharedData;
|
||||
@@ -300,8 +306,11 @@ private:
|
||||
DEF_OP(StoreMem);
|
||||
DEF_OP(LoadMemTSO);
|
||||
DEF_OP(StoreMemTSO);
|
||||
DEF_OP(ParanoidLoadMemTSO);
|
||||
DEF_OP(ParanoidStoreMemTSO);
|
||||
DEF_OP(VLoadMemElement);
|
||||
DEF_OP(VStoreMemElement);
|
||||
DEF_OP(CacheLineClear);
|
||||
|
||||
///< Misc ops
|
||||
DEF_OP(EndBlock);
|
||||
|
||||
+226
-60
@@ -29,7 +29,7 @@ DEF_OP(LoadContext) {
|
||||
case 8:
|
||||
ldr(GetReg<RA_64>(Node), MemOperand(STATE, Op->Offset));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -50,7 +50,7 @@ DEF_OP(LoadContext) {
|
||||
case 16:
|
||||
ldr(Dst, MemOperand(STATE, Op->Offset));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ DEF_OP(StoreContext) {
|
||||
case 8:
|
||||
str(GetReg<RA_64>(Op->Header.Args[0].ID()), MemOperand(STATE, Op->Offset));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -93,7 +93,7 @@ DEF_OP(StoreContext) {
|
||||
case 16:
|
||||
str(Src, MemOperand(STATE, Op->Offset));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,29 +106,29 @@ DEF_OP(LoadRegister) {
|
||||
auto regId = (Op->Offset - offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0])) / 8;
|
||||
auto regOffs = Op->Offset & 7;
|
||||
|
||||
LogMan::Throw::A(regId < SRA64.size(), "out of range regId");
|
||||
LOGMAN_THROW_A(regId < SRA64.size(), "out of range regId");
|
||||
|
||||
auto reg = SRA64[regId];
|
||||
|
||||
switch(Op->Header.Size) {
|
||||
case 1:
|
||||
LogMan::Throw::A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
|
||||
ubfx(GetReg<RA_64>(Node), reg, regOffs * 8, 8);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
ubfx(GetReg<RA_64>(Node), reg, 0, 16);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
if (GetReg<RA_64>(Node).GetCode() != reg.GetCode())
|
||||
mov(GetReg<RA_32>(Node), reg.W());
|
||||
break;
|
||||
|
||||
case 8:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
if (GetReg<RA_64>(Node).GetCode() != reg.GetCode())
|
||||
mov(GetReg<RA_64>(Node), reg);
|
||||
break;
|
||||
@@ -137,24 +137,24 @@ DEF_OP(LoadRegister) {
|
||||
auto regId = (Op->Offset - offsetof(FEXCore::Core::CpuStateFrame, State.xmm[0][0])) / 16;
|
||||
auto regOffs = Op->Offset & 15;
|
||||
|
||||
LogMan::Throw::A(regId < SRAFPR.size(), "out of range regId");
|
||||
LOGMAN_THROW_A(regId < SRAFPR.size(), "out of range regId");
|
||||
|
||||
auto guest = SRAFPR[regId];
|
||||
auto host = GetSrc(Node);
|
||||
|
||||
switch(Op->Header.Size) {
|
||||
case 1:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
mov(host.B(), guest.B());
|
||||
break;
|
||||
|
||||
case 2:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
fmov(host.H(), guest.H());
|
||||
break;
|
||||
|
||||
case 4:
|
||||
LogMan::Throw::A((regOffs & 3) == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A((regOffs & 3) == 0, "unexpected regOffs");
|
||||
if (regOffs == 0) {
|
||||
if (host.GetCode() != guest.GetCode())
|
||||
fmov(host.S(), guest.S());
|
||||
@@ -164,7 +164,7 @@ DEF_OP(LoadRegister) {
|
||||
break;
|
||||
|
||||
case 8:
|
||||
LogMan::Throw::A((regOffs & 7) == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A((regOffs & 7) == 0, "unexpected regOffs");
|
||||
if (regOffs == 0) {
|
||||
if (host.GetCode() != guest.GetCode())
|
||||
mov(host.D(), guest.D());
|
||||
@@ -174,13 +174,13 @@ DEF_OP(LoadRegister) {
|
||||
break;
|
||||
|
||||
case 16:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
if (host.GetCode() != guest.GetCode())
|
||||
mov(host.Q(), guest.Q());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unhandled Op->Class %d", Op->Class);
|
||||
LOGMAN_THROW_A(false, "Unhandled Op->Class %d", Op->Class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,28 +191,28 @@ DEF_OP(StoreRegister) {
|
||||
auto regId = Op->Offset / 8 - 1;
|
||||
auto regOffs = Op->Offset & 7;
|
||||
|
||||
LogMan::Throw::A(regId < SRA64.size(), "out of range regId");
|
||||
LOGMAN_THROW_A(regId < SRA64.size(), "out of range regId");
|
||||
|
||||
auto reg = SRA64[regId];
|
||||
|
||||
switch(Op->Header.Size) {
|
||||
case 1:
|
||||
LogMan::Throw::A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
|
||||
bfi(reg, GetReg<RA_64>(Op->Value.ID()), regOffs * 8, 8);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
bfi(reg, GetReg<RA_64>(Op->Value.ID()), 0, 16);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
bfi(reg, GetReg<RA_64>(Op->Value.ID()), 0, 32);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
if (GetReg<RA_64>(Op->Value.ID()).GetCode() != reg.GetCode())
|
||||
mov(reg, GetReg<RA_64>(Op->Value.ID()));
|
||||
break;
|
||||
@@ -221,7 +221,7 @@ DEF_OP(StoreRegister) {
|
||||
auto regId = (Op->Offset - offsetof(FEXCore::Core::CpuStateFrame, State.xmm[0][0])) / 16;
|
||||
auto regOffs = Op->Offset & 15;
|
||||
|
||||
LogMan::Throw::A(regId < SRAFPR.size(), "regId out of range");
|
||||
LOGMAN_THROW_A(regId < SRAFPR.size(), "regId out of range");
|
||||
|
||||
auto guest = SRAFPR[regId];
|
||||
auto host = GetSrc(Op->Value.ID());
|
||||
@@ -232,28 +232,28 @@ DEF_OP(StoreRegister) {
|
||||
break;
|
||||
|
||||
case 2:
|
||||
LogMan::Throw::A((regOffs & 1) == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A((regOffs & 1) == 0, "unexpected regOffs");
|
||||
ins(guest.V8H(), regOffs/2, host.V8H(), 0);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
LogMan::Throw::A((regOffs & 3) == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A((regOffs & 3) == 0, "unexpected regOffs");
|
||||
ins(guest.V4S(), regOffs/4, host.V4S(), 0);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
LogMan::Throw::A((regOffs & 7) == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A((regOffs & 7) == 0, "unexpected regOffs");
|
||||
ins(guest.V2D(), regOffs / 8, host.V2D(), 0);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
|
||||
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
|
||||
if (guest.GetCode() != host.GetCode())
|
||||
mov(guest.Q(), host.Q());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unhandled Op->Class %d", Op->Class);
|
||||
LOGMAN_THROW_A(false, "Unhandled Op->Class %d", Op->Class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,15 +287,15 @@ DEF_OP(LoadContextIndexed) {
|
||||
ldr(GetReg<RA_64>(Node), MemOperand(TMP1, Op->BaseOffset));
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
LogMan::Msg::A("Invalid Class load of size 16");
|
||||
LOGMAN_MSG_A("Invalid Class load of size 16");
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -332,12 +332,12 @@ DEF_OP(LoadContextIndexed) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,15 +373,15 @@ DEF_OP(StoreContextIndexed) {
|
||||
str(value, MemOperand(TMP1, Op->BaseOffset));
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
LogMan::Msg::A("Invalid Class load of size 16");
|
||||
LOGMAN_MSG_A("Invalid Class load of size 16");
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -420,12 +420,12 @@ DEF_OP(StoreContextIndexed) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,7 +453,7 @@ DEF_OP(SpillRegister) {
|
||||
str(GetReg<RA_64>(Op->Header.Args[0].ID()), MemOperand(sp, SlotOffset));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
|
||||
}
|
||||
} else if (Op->Class == FEXCore::IR::FPRClass) {
|
||||
switch (OpSize) {
|
||||
@@ -469,10 +469,10 @@ DEF_OP(SpillRegister) {
|
||||
str(GetSrc(Op->Header.Args[0].ID()), MemOperand(sp, SlotOffset));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
LogMan::Msg::A("Unhandled SpillRegister class: %d", Op->Class.Val);
|
||||
LOGMAN_MSG_A("Unhandled SpillRegister class: %d", Op->Class.Val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ DEF_OP(FillRegister) {
|
||||
ldr(GetReg<RA_64>(Node), MemOperand(sp, SlotOffset));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
|
||||
}
|
||||
} else if (Op->Class == FEXCore::IR::FPRClass) {
|
||||
switch (OpSize) {
|
||||
@@ -515,10 +515,10 @@ DEF_OP(FillRegister) {
|
||||
ldr(GetDst(Node), MemOperand(sp, SlotOffset));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
LogMan::Msg::A("Unhandled FillRegister class: %d", Op->Class.Val);
|
||||
LOGMAN_MSG_A("Unhandled FillRegister class: %d", Op->Class.Val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ MemOperand Arm64JITCore::GenerateMemOperand(uint8_t AccessSize, aarch64::Registe
|
||||
return MemOperand(Base);
|
||||
} else {
|
||||
if (OffsetScale != 1 && OffsetScale != AccessSize) {
|
||||
LogMan::Msg::A("Unhandled GenerateMemOperand OffsetScale: %d", OffsetScale);
|
||||
LOGMAN_MSG_A("Unhandled GenerateMemOperand OffsetScale: %d", OffsetScale);
|
||||
}
|
||||
uint64_t Const;
|
||||
if (IsInlineConstant(Offset, &Const)) {
|
||||
@@ -550,7 +550,7 @@ MemOperand Arm64JITCore::GenerateMemOperand(uint8_t AccessSize, aarch64::Registe
|
||||
case IR::MEM_OFFSET_UXTW.Val: return MemOperand(Base, RegOffset.W(), Extend::UXTW, (int)std::log2(OffsetScale) );
|
||||
case IR::MEM_OFFSET_SXTW.Val: return MemOperand(Base, RegOffset.W(), Extend::SXTW, (int)std::log2(OffsetScale) );
|
||||
|
||||
default: LogMan::Msg::A("Unhandled GenerateMemOperand OffsetType: %d", OffsetType.Val); break;
|
||||
default: LOGMAN_MSG_A("Unhandled GenerateMemOperand OffsetType: %d", OffsetType.Val); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,7 +578,7 @@ DEF_OP(LoadMem) {
|
||||
case 8:
|
||||
ldr(Dst, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -599,7 +599,7 @@ DEF_OP(LoadMem) {
|
||||
case 16:
|
||||
ldr(Dst, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -610,7 +610,7 @@ DEF_OP(LoadMemTSO) {
|
||||
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
if (!Op->Offset.IsInvalid()) {
|
||||
LogMan::Msg::A("LoadMemTSO: No offset allowed");
|
||||
LOGMAN_MSG_A("LoadMemTSO: No offset allowed");
|
||||
}
|
||||
|
||||
if (SupportsRCPC && Op->Class == FEXCore::IR::GPRClass) {
|
||||
@@ -633,7 +633,7 @@ DEF_OP(LoadMemTSO) {
|
||||
case 8:
|
||||
ldapr(Dst, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
nop();
|
||||
}
|
||||
@@ -658,7 +658,7 @@ DEF_OP(LoadMemTSO) {
|
||||
case 8:
|
||||
ldar(Dst, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
nop();
|
||||
}
|
||||
@@ -679,7 +679,7 @@ DEF_OP(LoadMemTSO) {
|
||||
case 16:
|
||||
ldr(Dst, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
dmb(InnerShareable, BarrierAll);
|
||||
}
|
||||
@@ -706,7 +706,7 @@ DEF_OP(StoreMem) {
|
||||
case 8:
|
||||
str(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -727,7 +727,7 @@ DEF_OP(StoreMem) {
|
||||
case 16:
|
||||
str(Src, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -737,7 +737,7 @@ DEF_OP(StoreMemTSO) {
|
||||
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
if (!Op->Offset.IsInvalid()) {
|
||||
LogMan::Msg::A("StoreMemTSO: No offset allowed");
|
||||
LOGMAN_MSG_A("StoreMemTSO: No offset allowed");
|
||||
}
|
||||
|
||||
if (Op->Class == FEXCore::IR::GPRClass) {
|
||||
@@ -757,7 +757,7 @@ DEF_OP(StoreMemTSO) {
|
||||
case 8:
|
||||
stlr(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
nop();
|
||||
}
|
||||
@@ -781,18 +781,177 @@ DEF_OP(StoreMemTSO) {
|
||||
case 16:
|
||||
str(Src, MemSrc);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
dmb(InnerShareable, BarrierAll);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(ParanoidLoadMemTSO) {
|
||||
auto Op = IROp->C<IR::IROp_LoadMemTSO>();
|
||||
|
||||
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
if (!Op->Offset.IsInvalid()) {
|
||||
LOGMAN_MSG_A("LoadMemTSO: No offset allowed");
|
||||
}
|
||||
|
||||
if (Op->Class == FEXCore::IR::GPRClass) {
|
||||
if (Op->Size == 1) {
|
||||
// 8bit load is always aligned to natural alignment
|
||||
auto Dst = GetReg<RA_64>(Node);
|
||||
ldarb(Dst, MemSrc);
|
||||
}
|
||||
else {
|
||||
auto Dst = GetReg<RA_64>(Node);
|
||||
nop();
|
||||
switch (Op->Size) {
|
||||
case 2:
|
||||
ldarh(Dst, MemSrc);
|
||||
break;
|
||||
case 4:
|
||||
ldar(Dst.W(), MemSrc);
|
||||
break;
|
||||
case 8:
|
||||
ldar(Dst, MemSrc);
|
||||
break;
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
nop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto Dst = GetDst(Node);
|
||||
switch (Op->Size) {
|
||||
case 2:
|
||||
nop();
|
||||
ldarh(TMP1, MemSrc);
|
||||
nop();
|
||||
fmov(Dst, TMP1);
|
||||
break;
|
||||
case 4:
|
||||
nop();
|
||||
ldar(TMP1.W(), MemSrc);
|
||||
nop();
|
||||
fmov(Dst, TMP1);
|
||||
break;
|
||||
case 8:
|
||||
nop();
|
||||
ldar(TMP1, MemSrc);
|
||||
nop();
|
||||
fmov(Dst, TMP1);
|
||||
break;
|
||||
case 16:
|
||||
nop();
|
||||
ldaxp(TMP1, TMP2, MemSrc);
|
||||
clrex();
|
||||
mov(Dst.V2D(), 0, TMP1);
|
||||
mov(Dst.V2D(), 1, TMP2);
|
||||
break;
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(ParanoidStoreMemTSO) {
|
||||
auto Op = IROp->C<IR::IROp_StoreMemTSO>();
|
||||
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
if (!Op->Offset.IsInvalid()) {
|
||||
LOGMAN_MSG_A("StoreMemTSO: No offset allowed");
|
||||
}
|
||||
|
||||
if (Op->Class == FEXCore::IR::GPRClass) {
|
||||
if (Op->Size == 1) {
|
||||
// 8bit load is always aligned to natural alignment
|
||||
stlrb(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
|
||||
}
|
||||
else {
|
||||
nop();
|
||||
switch (Op->Size) {
|
||||
case 2:
|
||||
stlrh(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
|
||||
break;
|
||||
case 4:
|
||||
stlr(GetReg<RA_32>(Op->Header.Args[1].ID()), MemSrc);
|
||||
break;
|
||||
case 8:
|
||||
stlr(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
|
||||
break;
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
nop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto Src = GetSrc(Op->Header.Args[1].ID());
|
||||
if (Op->Size == 1) {
|
||||
// 8bit load is always aligned to natural alignment
|
||||
mov(TMP1, Src.V4S(), 0);
|
||||
stlrb(TMP1, MemSrc);
|
||||
}
|
||||
else {
|
||||
switch (Op->Size) {
|
||||
case 2:
|
||||
mov(TMP1, Src.V4S(), 0);
|
||||
nop();
|
||||
stlrh(TMP1, MemSrc);
|
||||
nop();
|
||||
break;
|
||||
case 4:
|
||||
mov(TMP1, Src.V4S(), 0);
|
||||
nop();
|
||||
stlr(TMP1.W(), MemSrc);
|
||||
nop();
|
||||
break;
|
||||
case 8:
|
||||
mov(TMP1, Src.V2D(), 0);
|
||||
nop();
|
||||
stlr(TMP1, MemSrc);
|
||||
nop();
|
||||
break;
|
||||
case 16: {
|
||||
// Move vector to GPRs
|
||||
mov(TMP1, Src.V2D(), 0);
|
||||
mov(TMP2, Src.V2D(), 1);
|
||||
Label B;
|
||||
bind(&B);
|
||||
|
||||
nop(); // < Overwritten with DMB
|
||||
// ldaxp must not have both the destination registers be the same
|
||||
ldaxp(xzr, TMP3, MemSrc); // <- Can hit SIGBUS
|
||||
nop(); // < Overwritten with DMB
|
||||
stlxp(TMP3, TMP1, TMP2, MemSrc); // <- Can also hit SIGBUS
|
||||
cbnz(TMP3, &B); // < Overwritten with DMB
|
||||
break;
|
||||
}
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VLoadMemElement) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VStoreMemElement) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(CacheLineClear) {
|
||||
auto Op = IROp->C<IR::IROp_CacheLineClear>();
|
||||
|
||||
auto MemReg = GetReg<RA_64>(Op->Header.Args[0].ID());
|
||||
|
||||
// Clear dcache only
|
||||
// icache doesn't matter here since the guest application shouldn't be calling clflush on JIT code.
|
||||
mov(TMP1, MemReg);
|
||||
for (size_t i = 0; i < std::max(1U, DCacheLineSize / 64U); ++i) {
|
||||
dc(DataCacheOp::CVAU, TMP1);
|
||||
add(TMP1, TMP1, DCacheLineSize);
|
||||
}
|
||||
dsb(InnerShareable, BarrierAll);
|
||||
}
|
||||
|
||||
#undef DEF_OP
|
||||
@@ -810,10 +969,17 @@ void Arm64JITCore::RegisterMemoryHandlers() {
|
||||
REGISTER_OP(STOREFLAG, StoreFlag);
|
||||
REGISTER_OP(LOADMEM, LoadMem);
|
||||
REGISTER_OP(STOREMEM, StoreMem);
|
||||
REGISTER_OP(LOADMEMTSO, LoadMemTSO);
|
||||
REGISTER_OP(STOREMEMTSO, StoreMemTSO);
|
||||
if (ParanoidTSO()) {
|
||||
REGISTER_OP(LOADMEMTSO, ParanoidLoadMemTSO);
|
||||
REGISTER_OP(STOREMEMTSO, ParanoidStoreMemTSO);
|
||||
}
|
||||
else {
|
||||
REGISTER_OP(LOADMEMTSO, LoadMemTSO);
|
||||
REGISTER_OP(STOREMEMTSO, StoreMemTSO);
|
||||
}
|
||||
REGISTER_OP(VLOADMEMELEMENT, VLoadMemElement);
|
||||
REGISTER_OP(VSTOREMEMELEMENT, VStoreMemElement);
|
||||
REGISTER_OP(CACHELINECLEAR, CacheLineClear);
|
||||
#undef REGISTER_OP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ $end_info$
|
||||
#include "Interface/Core/JIT/Arm64/JITClass.h"
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
static void PrintValue(uint64_t Value) {
|
||||
LogMan::Msg::D("Value: 0x%lx", Value);
|
||||
}
|
||||
|
||||
static void PrintVectorValue(uint64_t Value, uint64_t ValueUpper) {
|
||||
LogMan::Msg::D("Value: 0x%016lx'%016lx", ValueUpper, Value);
|
||||
}
|
||||
|
||||
using namespace vixl;
|
||||
using namespace vixl::aarch64;
|
||||
@@ -24,7 +31,7 @@ DEF_OP(Fence) {
|
||||
case IR::Fence_Store.Val:
|
||||
dmb(FullSystem, BarrierWrites);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Fence: %d", Op->Fence); break;
|
||||
default: LOGMAN_MSG_A("Unknown Fence: %d", Op->Fence); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +42,15 @@ DEF_OP(Break) {
|
||||
case 5: // Guest ud2
|
||||
hlt(4);
|
||||
break;
|
||||
case 1: // Int <imm8>
|
||||
hlt(4);
|
||||
break;
|
||||
case 2: // overflow
|
||||
hlt(4);
|
||||
break;
|
||||
case 3: // int 1
|
||||
hlt(4);
|
||||
break;
|
||||
case 4: { // HLT
|
||||
// Time to quit
|
||||
// Set our stack to the starting stack location
|
||||
@@ -42,18 +58,18 @@ DEF_OP(Break) {
|
||||
add(sp, TMP1, 0);
|
||||
|
||||
// Now we need to jump to the thread stop handler
|
||||
LoadConstant(TMP1, Dispatcher->ThreadStopHandlerAddressSpillSRA);
|
||||
LoadConstant(TMP1, ThreadSharedData.Dispatcher->ThreadStopHandlerAddressSpillSRA);
|
||||
br(TMP1);
|
||||
break;
|
||||
}
|
||||
case 6: { // INT3
|
||||
ResetStack();
|
||||
|
||||
LoadConstant(TMP1, Dispatcher->ThreadPauseHandlerAddressSpillSRA);
|
||||
LoadConstant(TMP1, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddressSpillSRA);
|
||||
br(TMP1);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Break reason: %d", Op->Reason);
|
||||
default: LOGMAN_MSG_A("Unknown Break reason: %d", Op->Reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +131,28 @@ DEF_OP(SetRoundingMode) {
|
||||
msr(FPCR, TMP1);
|
||||
}
|
||||
|
||||
DEF_OP(Print) {
|
||||
auto Op = IROp->C<IR::IROp_Print>();
|
||||
|
||||
PushDynamicRegsAndLR();
|
||||
|
||||
if (IsGPR(Op->Header.Args[0].ID())) {
|
||||
mov(x0, GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
LoadConstant(x3, reinterpret_cast<uint64_t>(PrintValue));
|
||||
}
|
||||
else {
|
||||
fmov(x0, GetSrc(Op->Header.Args[0].ID()).V1D());
|
||||
// Bug in vixl that source vector needs to b V1D rather than V2D?
|
||||
fmov(x1, GetSrc(Op->Header.Args[0].ID()).V1D(), 1);
|
||||
LoadConstant(x3, reinterpret_cast<uint64_t>(PrintVectorValue));
|
||||
}
|
||||
SpillStaticRegs();
|
||||
blr(x3);
|
||||
FillStaticRegs();
|
||||
|
||||
PopDynamicRegsAndLR();
|
||||
}
|
||||
|
||||
#undef DEF_OP
|
||||
void Arm64JITCore::RegisterMiscHandlers() {
|
||||
#define REGISTER_OP(op, x) OpHandlers[FEXCore::IR::IROps::OP_##op] = &Arm64JITCore::Op_##x
|
||||
@@ -127,7 +165,7 @@ void Arm64JITCore::RegisterMiscHandlers() {
|
||||
REGISTER_OP(BREAK, Break);
|
||||
REGISTER_OP(PHI, NoOp);
|
||||
REGISTER_OP(PHIVALUE, NoOp);
|
||||
REGISTER_OP(PRINT, Unhandled);
|
||||
REGISTER_OP(PRINT, Print);
|
||||
REGISTER_OP(GETROUNDINGMODE, GetRoundingMode);
|
||||
REGISTER_OP(SETROUNDINGMODE, SetRoundingMode);
|
||||
REGISTER_OP(INVALIDATEFLAGS, NoOp);
|
||||
|
||||
@@ -26,7 +26,7 @@ DEF_OP(ExtractElementPair) {
|
||||
mov (GetReg<RA_64>(Node), Regs[Op->Element]);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Size"); break;
|
||||
default: LOGMAN_MSG_A("Unknown Size"); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ DEF_OP(CreateElementPair) {
|
||||
RegTmp = x0;
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Size"); break;
|
||||
default: LOGMAN_MSG_A("Unknown Size"); break;
|
||||
}
|
||||
|
||||
if (Dst.first.GetCode() != RegSecond.GetCode()) {
|
||||
|
||||
+151
-116
@@ -22,7 +22,7 @@ DEF_OP(VectorZero) {
|
||||
eor(GetDst(Node).V16B(), GetDst(Node).V16B(), GetDst(Node).V16B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,21 +32,28 @@ DEF_OP(VectorImm) {
|
||||
uint8_t OpSize = IROp->Size;
|
||||
uint8_t Elements = OpSize / Op->Header.ElementSize;
|
||||
|
||||
movi(GetDst(Node).VCast(OpSize * 8, Elements), Op->Immediate);
|
||||
if (Op->Header.ElementSize == 8) {
|
||||
// movi with 64bit element size doesn't do what we want here
|
||||
LoadConstant(TMP1.X(), Op->Immediate);
|
||||
dup(GetDst(Node).V2D(), TMP1.X());
|
||||
}
|
||||
else {
|
||||
movi(GetDst(Node).VCast(OpSize * 8, Elements), Op->Immediate);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(CreateVector2) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(CreateVector4) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(SplatVector2) {
|
||||
auto Op = IROp->C<IR::IROp_SplatVector2>();
|
||||
uint8_t OpSize = IROp->Size;
|
||||
LogMan::Throw::A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
|
||||
LOGMAN_THROW_A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
|
||||
|
||||
uint8_t ElementSize = OpSize / 2;
|
||||
|
||||
@@ -57,14 +64,14 @@ DEF_OP(SplatVector2) {
|
||||
case 8:
|
||||
dup(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(SplatVector4) {
|
||||
auto Op = IROp->C<IR::IROp_SplatVector4>();
|
||||
uint8_t OpSize = IROp->Size;
|
||||
LogMan::Throw::A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
|
||||
LOGMAN_THROW_A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
|
||||
|
||||
uint8_t ElementSize = OpSize / 4;
|
||||
|
||||
@@ -75,7 +82,7 @@ DEF_OP(SplatVector4) {
|
||||
case 8:
|
||||
dup(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +118,7 @@ DEF_OP(VMov) {
|
||||
mov(GetDst(Node).V16B(), GetSrc(Op->Header.Args[0].ID()).V16B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +156,7 @@ DEF_OP(VAdd) {
|
||||
add(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +179,7 @@ DEF_OP(VSub) {
|
||||
sub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +202,7 @@ DEF_OP(VUQAdd) {
|
||||
uqadd(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +225,7 @@ DEF_OP(VUQSub) {
|
||||
uqsub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +248,7 @@ DEF_OP(VSQAdd) {
|
||||
sqadd(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +271,7 @@ DEF_OP(VSQSub) {
|
||||
sqsub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +293,7 @@ DEF_OP(VAddP) {
|
||||
addp(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -307,7 +314,7 @@ DEF_OP(VAddP) {
|
||||
addp(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,7 +333,7 @@ DEF_OP(VAddV) {
|
||||
case 8:
|
||||
addp(GetDst(Node).VCast(OpSize * 8, 1), GetSrc(Op->Header.Args[0].ID()).VCast(OpSize * 8, Elements));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +348,7 @@ DEF_OP(VURAvg) {
|
||||
urhadd(GetDst(Node).V8H(), GetSrc(Op->Header.Args[0].ID()).V8H(), GetSrc(Op->Header.Args[1].ID()).V8H());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +363,7 @@ DEF_OP(VAbs) {
|
||||
abs(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -368,7 +375,7 @@ DEF_OP(VAbs) {
|
||||
case 8:
|
||||
abs(GetDst(Node).VCast(OpSize * 8, Elements), GetSrc(Op->Header.Args[0].ID()).VCast(OpSize * 8, Elements));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,7 +394,7 @@ DEF_OP(VFAdd) {
|
||||
fadd(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -401,7 +408,7 @@ DEF_OP(VFAdd) {
|
||||
fadd(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,7 +424,7 @@ DEF_OP(VFAddP) {
|
||||
faddp(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +442,7 @@ DEF_OP(VFSub) {
|
||||
fsub(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -449,7 +456,7 @@ DEF_OP(VFSub) {
|
||||
fsub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,7 +475,7 @@ DEF_OP(VFMul) {
|
||||
fmul(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -482,7 +489,7 @@ DEF_OP(VFMul) {
|
||||
fmul(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -501,7 +508,7 @@ DEF_OP(VFDiv) {
|
||||
fdiv(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -515,7 +522,7 @@ DEF_OP(VFDiv) {
|
||||
fdiv(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -527,28 +534,36 @@ DEF_OP(VFMin) {
|
||||
// Scalar
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 4: {
|
||||
fmin(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
|
||||
fcmp(GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
|
||||
fcsel(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S(), Condition::mi);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
fmin(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
fcmp(GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
fcsel(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D(), Condition::mi);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Vector
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 4: {
|
||||
fmin(GetDst(Node).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
|
||||
fcmgt(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
|
||||
mov(VTMP2.V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
|
||||
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V4S(), VTMP2.V4S());
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
fmin(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
fcmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -560,28 +575,36 @@ DEF_OP(VFMax) {
|
||||
// Scalar
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 4: {
|
||||
fmax(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
|
||||
fcmp(GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
|
||||
fcsel(GetDst(Node).S(), GetSrc(Op->Header.Args[1].ID()).S(), GetSrc(Op->Header.Args[0].ID()).S(), Condition::mi);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
fmax(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
fcmp(GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
fcsel(GetDst(Node).D(), GetSrc(Op->Header.Args[1].ID()).D(), GetSrc(Op->Header.Args[0].ID()).D(), Condition::mi);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Vector
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 4: {
|
||||
fmax(GetDst(Node).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
|
||||
fcmgt(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
|
||||
mov(VTMP2.V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
|
||||
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V4S(), VTMP2.V4S());
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
fmax(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
fcmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,7 +625,7 @@ DEF_OP(VFRecp) {
|
||||
fdiv(GetDst(Node).D(), VTMP1.D(), GetSrc(Op->Header.Args[0].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -618,7 +641,7 @@ DEF_OP(VFRecp) {
|
||||
fdiv(GetDst(Node).V2D(), VTMP1.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,7 +660,7 @@ DEF_OP(VFSqrt) {
|
||||
fsqrt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -651,7 +674,7 @@ DEF_OP(VFSqrt) {
|
||||
fsqrt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -674,7 +697,7 @@ DEF_OP(VFRSqrt) {
|
||||
fdiv(GetDst(Node).D(), VTMP1.D(), VTMP2.D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -692,7 +715,7 @@ DEF_OP(VFRSqrt) {
|
||||
fdiv(GetDst(Node).V2D(), VTMP1.V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -713,7 +736,7 @@ DEF_OP(VNeg) {
|
||||
case 8:
|
||||
neg(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -727,7 +750,7 @@ DEF_OP(VFNeg) {
|
||||
case 8:
|
||||
fneg(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -752,10 +775,13 @@ DEF_OP(VUMin) {
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
umin(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
cmhi(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,10 +801,13 @@ DEF_OP(VSMin) {
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
smin(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
cmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,10 +827,13 @@ DEF_OP(VUMax) {
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
umax(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
cmhi(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,10 +853,13 @@ DEF_OP(VSMax) {
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
smax(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
cmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
|
||||
mov(GetDst(Node).V2D(), VTMP2.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -845,7 +880,7 @@ DEF_OP(VZip) {
|
||||
zip1(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -866,7 +901,7 @@ DEF_OP(VZip) {
|
||||
zip1(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -888,7 +923,7 @@ DEF_OP(VZip2) {
|
||||
zip2(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -909,7 +944,7 @@ DEF_OP(VZip2) {
|
||||
zip2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -942,7 +977,7 @@ DEF_OP(VCMPEQ) {
|
||||
cmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -964,7 +999,7 @@ DEF_OP(VCMPEQ) {
|
||||
cmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -983,7 +1018,7 @@ DEF_OP(VCMPEQZ) {
|
||||
cmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1005,7 +1040,7 @@ DEF_OP(VCMPEQZ) {
|
||||
cmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1024,7 +1059,7 @@ DEF_OP(VCMPGT) {
|
||||
cmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1046,7 +1081,7 @@ DEF_OP(VCMPGT) {
|
||||
cmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1065,7 +1100,7 @@ DEF_OP(VCMPGTZ) {
|
||||
cmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1087,7 +1122,7 @@ DEF_OP(VCMPGTZ) {
|
||||
cmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1106,7 +1141,7 @@ DEF_OP(VCMPLTZ) {
|
||||
cmlt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1128,7 +1163,7 @@ DEF_OP(VCMPLTZ) {
|
||||
cmlt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1147,7 +1182,7 @@ DEF_OP(VFCMPEQ) {
|
||||
fcmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1165,7 +1200,7 @@ DEF_OP(VFCMPEQ) {
|
||||
fcmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1184,7 +1219,7 @@ DEF_OP(VFCMPNEQ) {
|
||||
fcmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
mvn(GetDst(Node).V8B(), GetDst(Node).V8B());
|
||||
}
|
||||
@@ -1203,7 +1238,7 @@ DEF_OP(VFCMPNEQ) {
|
||||
fcmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
mvn(GetDst(Node).V16B(), GetDst(Node).V16B());
|
||||
}
|
||||
@@ -1223,7 +1258,7 @@ DEF_OP(VFCMPLT) {
|
||||
fcmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[1].ID()).D(), GetSrc(Op->Header.Args[0].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1241,7 +1276,7 @@ DEF_OP(VFCMPLT) {
|
||||
fcmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1260,7 +1295,7 @@ DEF_OP(VFCMPGT) {
|
||||
fcmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1278,7 +1313,7 @@ DEF_OP(VFCMPGT) {
|
||||
fcmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1297,7 +1332,7 @@ DEF_OP(VFCMPLE) {
|
||||
fcmge(GetDst(Node).D(), GetSrc(Op->Header.Args[1].ID()).D(), GetSrc(Op->Header.Args[0].ID()).D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1315,7 +1350,7 @@ DEF_OP(VFCMPLE) {
|
||||
fcmge(GetDst(Node).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1338,7 +1373,7 @@ DEF_OP(VFCMPORD) {
|
||||
orr(GetDst(Node).V8B(), VTMP1.V8B(), VTMP2.V8B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1362,7 +1397,7 @@ DEF_OP(VFCMPORD) {
|
||||
orr(GetDst(Node).V16B(), VTMP1.V16B(), VTMP2.V16B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1387,7 +1422,7 @@ DEF_OP(VFCMPUNO) {
|
||||
mvn(GetDst(Node).V8B(), GetDst(Node).V8B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1414,21 +1449,21 @@ DEF_OP(VFCMPUNO) {
|
||||
mvn(GetDst(Node).V16B(), GetDst(Node).V16B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VUShl) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VUShr) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VSShr) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VUShlS) {
|
||||
@@ -1455,7 +1490,7 @@ DEF_OP(VUShlS) {
|
||||
ushl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), VTMP1.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1487,7 +1522,7 @@ DEF_OP(VUShrS) {
|
||||
ushl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), VTMP1.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1519,7 +1554,7 @@ DEF_OP(VSShrS) {
|
||||
sshl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), VTMP1.V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1550,7 +1585,7 @@ DEF_OP(VInsElement) {
|
||||
mov(reg.V2D(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V2D(), Op->SrcIdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
if (GetDst(Node).GetCode() != reg.GetCode()) {
|
||||
@@ -1585,7 +1620,7 @@ DEF_OP(VInsScalarElement) {
|
||||
mov(reg.V2D(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V2D(), 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
if (GetDst(Node).GetCode() != reg.GetCode()) {
|
||||
@@ -1609,7 +1644,7 @@ DEF_OP(VExtractElement) {
|
||||
case 8:
|
||||
mov(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->Index);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled ExtractElementSize: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled ExtractElementSize: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1724,7 +1759,7 @@ DEF_OP(VUShrI) {
|
||||
ushr(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1749,7 +1784,7 @@ DEF_OP(VSShrI) {
|
||||
sshr(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), std::min((uint8_t)(Op->Header.ElementSize * 8 - 1), Op->BitShift));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1777,7 +1812,7 @@ DEF_OP(VShlI) {
|
||||
shl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1798,7 +1833,7 @@ DEF_OP(VUShrNI) {
|
||||
shrn(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1818,7 +1853,7 @@ DEF_OP(VUShrNI2) {
|
||||
shrn2(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V2D(), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
mov(GetDst(Node), VTMP1);
|
||||
@@ -1841,7 +1876,7 @@ DEF_OP(VSXTL) {
|
||||
case 8:
|
||||
sxtl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1857,7 +1892,7 @@ DEF_OP(VSXTL2) {
|
||||
case 8:
|
||||
sxtl2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1873,7 +1908,7 @@ DEF_OP(VUXTL) {
|
||||
case 8:
|
||||
uxtl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1889,7 +1924,7 @@ DEF_OP(VUXTL2) {
|
||||
case 8:
|
||||
uxtl2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1905,7 +1940,7 @@ DEF_OP(VSQXTN) {
|
||||
case 4:
|
||||
sqxtn(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1927,7 +1962,7 @@ DEF_OP(VSQXTN2) {
|
||||
sqxtn(VTMP2.V2S(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
ins(VTMP1.V4S(), 1, VTMP2.V4S(), 0);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1941,7 +1976,7 @@ DEF_OP(VSQXTN2) {
|
||||
case 4:
|
||||
sqxtn2(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
mov(GetDst(Node), VTMP1);
|
||||
@@ -1959,7 +1994,7 @@ DEF_OP(VSQXTUN) {
|
||||
case 4:
|
||||
sqxtun(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1981,7 +2016,7 @@ DEF_OP(VSQXTUN2) {
|
||||
sqxtun(VTMP2.V2S(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
ins(VTMP1.V4S(), 1, VTMP2.V4S(), 0);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1995,7 +2030,7 @@ DEF_OP(VSQXTUN2) {
|
||||
case 4:
|
||||
sqxtun2(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
mov(GetDst(Node), VTMP1);
|
||||
@@ -2020,7 +2055,7 @@ DEF_OP(VMul) {
|
||||
mul(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2039,7 +2074,7 @@ DEF_OP(VUMull) {
|
||||
umull(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2058,7 +2093,7 @@ DEF_OP(VSMull) {
|
||||
smull(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2077,7 +2112,7 @@ DEF_OP(VUMull2) {
|
||||
umull2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2096,7 +2131,7 @@ DEF_OP(VSMull2) {
|
||||
smull2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2113,7 +2148,7 @@ DEF_OP(VTBL1) {
|
||||
tbl(GetDst(Node).V16B(), GetSrc(Op->Header.Args[0].ID()).V16B(), GetSrc(Op->Header.Args[1].ID()).V16B());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-35
@@ -20,7 +20,7 @@ DEF_OP(TruncElementPair) {
|
||||
mov(Dst.second, Src.second);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled Truncation size: %d", Op->Size); break;
|
||||
default: LOGMAN_MSG_A("Unhandled Truncation size: %d", Op->Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ DEF_OP(Constant) {
|
||||
DEF_OP(EntrypointOffset) {
|
||||
auto Op = IROp->C<IR::IROp_EntrypointOffset>();
|
||||
|
||||
auto Constant = IR->GetHeader()->Entry + Op->Offset;
|
||||
auto Constant = Entry + Op->Offset;
|
||||
mov(GetDst<RA_64>(Node), Constant);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ DEF_OP(Add) {
|
||||
case 8:
|
||||
add(rax, Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled Add size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled Add size: %d", OpSize);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -81,7 +81,7 @@ DEF_OP(Add) {
|
||||
case 8:
|
||||
add(rax, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled Add size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled Add size: %d", OpSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ DEF_OP(Sub) {
|
||||
case 8:
|
||||
sub(rax, Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled Sub size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled Sub size: %d", OpSize);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -114,7 +114,7 @@ DEF_OP(Sub) {
|
||||
case 8:
|
||||
sub(rax, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled Sub size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled Sub size: %d", OpSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ DEF_OP(Neg) {
|
||||
Src = GetSrc<RA_64>(Op->Header.Args[0].ID());
|
||||
Dst = GetDst<RA_64>(Node);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled Neg size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled Neg size: %d", OpSize);
|
||||
break;
|
||||
}
|
||||
mov(Dst, Src);
|
||||
@@ -160,7 +160,7 @@ DEF_OP(Mul) {
|
||||
imul(rax, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
mov(Dst, rax);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ DEF_OP(UMul) {
|
||||
mul(GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ DEF_OP(Div) {
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown UDIV Size: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown UDIV Size: %d", Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ DEF_OP(UDiv) {
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown UDIV OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown UDIV OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ DEF_OP(Rem) {
|
||||
mov(GetDst<RA_64>(Node), rdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown UDIV Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown UDIV Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ DEF_OP(URem) {
|
||||
mov(GetDst<RA_64>(Node), rdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown UDIV OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown UDIV OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ DEF_OP(MulH) {
|
||||
imul(GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
mov(GetDst<RA_64>(Node), rdx);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ DEF_OP(UMulH) {
|
||||
mul(GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
mov(GetDst<RA_64>(Node), rdx);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ DEF_OP(Lshl) {
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
shl(GetDst<RA_64>(Node), Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown LSHL Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LSHL Size: %d\n", OpSize); break;
|
||||
};
|
||||
} else {
|
||||
mov(rcx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
@@ -456,7 +456,7 @@ DEF_OP(Lshl) {
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
shl(GetDst<RA_64>(Node), cl);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown LSHL Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LSHL Size: %d\n", OpSize); break;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -488,7 +488,7 @@ DEF_OP(Lshr) {
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
shr(GetDst<RA_64>(Node), Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Size: %d\n", OpSize); break;
|
||||
};
|
||||
|
||||
} else {
|
||||
@@ -512,7 +512,7 @@ DEF_OP(Lshr) {
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
shr(GetDst<RA_64>(Node), cl);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Size: %d\n", OpSize); break;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -546,7 +546,7 @@ DEF_OP(Ashr) {
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
sar(GetDst<RA_64>(Node), Const);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown ASHR Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown ASHR Size: %d\n", OpSize); break;
|
||||
};
|
||||
|
||||
} else {
|
||||
@@ -571,7 +571,7 @@ DEF_OP(Ashr) {
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
sar(GetDst<RA_64>(Node), cl);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown ASHR Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown ASHR Size: %d\n", OpSize); break;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -596,7 +596,7 @@ DEF_OP(Ror) {
|
||||
ror(rax, Const);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown ROR Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown ROR Size: %d\n", OpSize); break;
|
||||
}
|
||||
} else {
|
||||
mov (rcx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
@@ -612,7 +612,7 @@ DEF_OP(Ror) {
|
||||
ror(rax, cl);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown ROR Size: %d\n", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown ROR Size: %d\n", OpSize); break;
|
||||
}
|
||||
}
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
@@ -668,7 +668,7 @@ DEF_OP(LDiv) {
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LDIV OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LDIV OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +700,7 @@ DEF_OP(LUDiv) {
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LUDIV OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LUDIV OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +732,7 @@ DEF_OP(LRem) {
|
||||
mov(GetDst<RA_64>(Node), rdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LREM OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LREM OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,7 +764,7 @@ DEF_OP(LURem) {
|
||||
mov(GetDst<RA_64>(Node), rdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown LUDIV OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown LUDIV OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,7 +829,7 @@ DEF_OP(FindMSB) {
|
||||
case 8:
|
||||
bsr(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown OpSize: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unknown OpSize: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,7 +853,7 @@ DEF_OP(FindTrailingZeros) {
|
||||
mov(rax, 0x40);
|
||||
cmovz(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,7 +876,7 @@ DEF_OP(CountLeadingZeroes) {
|
||||
lzcnt(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -915,7 +915,7 @@ DEF_OP(CountLeadingZeroes) {
|
||||
mov(GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -937,7 +937,7 @@ DEF_OP(Rev) {
|
||||
mov (GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
bswap(GetDst<RA_64>(Node).cvt64());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown REV size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown REV size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,7 +972,7 @@ DEF_OP(Bfe) {
|
||||
auto Op = IROp->C<IR::IROp_Bfe>();
|
||||
uint8_t OpSize = IROp->Size;
|
||||
|
||||
LogMan::Throw::A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
|
||||
LOGMAN_THROW_A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
|
||||
|
||||
auto Dst = GetDst<RA_64>(Node);
|
||||
|
||||
@@ -1073,7 +1073,7 @@ DEF_OP(Select) {
|
||||
|
||||
if (is_const_true || is_const_false) {
|
||||
if (is_const_false != true || is_const_true != true || const_true != 1 || const_false != 0) {
|
||||
LogMan::Msg::A("Select: Unsupported compare inline parameters");
|
||||
LOGMAN_MSG_A("Select: Unsupported compare inline parameters");
|
||||
}
|
||||
(this->*SetCC)(al);
|
||||
movzx(Dst, al);
|
||||
@@ -1104,7 +1104,7 @@ DEF_OP(VExtractToGPR) {
|
||||
pextrq(GetDst<RA_64>(Node), GetSrc(Op->Header.Args[0].ID()), Op->Idx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-30
@@ -55,7 +55,7 @@ DEF_OP(CASPair) {
|
||||
mov(Dst.second, rdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unsupported: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ DEF_OP(CAS) {
|
||||
|
||||
Xbyak::Reg MemReg = GetSrc<RA_64>(Op->Header.Args[2].ID());
|
||||
|
||||
mov(rdx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
mov(rax, GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
// RCX now contains pointer
|
||||
@@ -82,31 +81,31 @@ DEF_OP(CAS) {
|
||||
// RDX contains our desired
|
||||
|
||||
lock();
|
||||
|
||||
switch (OpSize) {
|
||||
case 1: {
|
||||
cmpxchg(byte [MemReg], dl);
|
||||
movzx(rax, al);
|
||||
cmpxchg(byte [MemReg], GetSrc<RA_8>(Op->Header.Args[1].ID()));
|
||||
movzx(GetDst<RA_64>(Node), al);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
cmpxchg(word [MemReg], dx);
|
||||
movzx(rax, ax);
|
||||
cmpxchg(word [MemReg], GetSrc<RA_16>(Op->Header.Args[1].ID()));
|
||||
movzx(GetDst<RA_64>(Node), ax);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
cmpxchg(dword [MemReg], edx);
|
||||
cmpxchg(dword [MemReg], GetSrc<RA_32>(Op->Header.Args[1].ID()));
|
||||
// RAX now contains the result
|
||||
mov (GetDst<RA_64>(Node), eax);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
cmpxchg(qword [MemReg], rdx);
|
||||
cmpxchg(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
// RAX now contains the result
|
||||
mov (GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unsupported: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
|
||||
}
|
||||
|
||||
// RAX now contains the result
|
||||
mov (GetDst<RA_64>(Node), rax);
|
||||
}
|
||||
|
||||
DEF_OP(AtomicAdd) {
|
||||
@@ -128,7 +127,7 @@ DEF_OP(AtomicAdd) {
|
||||
case 8:
|
||||
add(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +149,7 @@ DEF_OP(AtomicSub) {
|
||||
case 8:
|
||||
sub(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +171,7 @@ DEF_OP(AtomicAnd) {
|
||||
case 8:
|
||||
and_(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +193,7 @@ DEF_OP(AtomicOr) {
|
||||
case 8:
|
||||
or_(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +215,7 @@ DEF_OP(AtomicXor) {
|
||||
case 8:
|
||||
xor_(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,17 +227,17 @@ DEF_OP(AtomicSwap) {
|
||||
|
||||
switch (Op->Size) {
|
||||
case 1:
|
||||
mov(GetDst<RA_8>(Node), GetSrc<RA_8>(Op->Header.Args[1].ID()));
|
||||
movzx(GetDst<RA_64>(Node), GetSrc<RA_8>(Op->Header.Args[1].ID()));
|
||||
lock();
|
||||
xchg(byte [MemReg], GetDst<RA_8>(Node));
|
||||
break;
|
||||
case 2:
|
||||
mov(GetDst<RA_16>(Node), GetSrc<RA_16>(Op->Header.Args[1].ID()));
|
||||
movzx(GetDst<RA_64>(Node), GetSrc<RA_16>(Op->Header.Args[1].ID()));
|
||||
lock();
|
||||
xchg(word [MemReg], GetDst<RA_16>(Node));
|
||||
break;
|
||||
case 4:
|
||||
mov(GetDst<RA_32>(Node), GetSrc<RA_32>(Op->Header.Args[1].ID()));
|
||||
mov(GetDst<RA_64>(Node), GetSrc<RA_32>(Op->Header.Args[1].ID()));
|
||||
lock();
|
||||
xchg(dword [MemReg], GetDst<RA_32>(Node));
|
||||
break;
|
||||
@@ -247,7 +246,7 @@ DEF_OP(AtomicSwap) {
|
||||
lock();
|
||||
xchg(qword [MemReg], GetDst<RA_64>(Node));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,13 +256,13 @@ DEF_OP(AtomicFetchAdd) {
|
||||
Xbyak::Reg MemReg = GetSrc<RA_64>(Op->Header.Args[0].ID());
|
||||
switch (Op->Size) {
|
||||
case 1:
|
||||
mov(cl, GetSrc<RA_8>(Op->Header.Args[1].ID()));
|
||||
movzx(rcx, GetSrc<RA_8>(Op->Header.Args[1].ID()));
|
||||
lock();
|
||||
xadd(byte [MemReg], cl);
|
||||
movzx(GetDst<RA_32>(Node), cl);
|
||||
break;
|
||||
case 2:
|
||||
mov(cx, GetSrc<RA_16>(Op->Header.Args[1].ID()));
|
||||
movzx(rcx, GetSrc<RA_16>(Op->Header.Args[1].ID()));
|
||||
lock();
|
||||
xadd(word [MemReg], cx);
|
||||
movzx(GetDst<RA_32>(Node), cx);
|
||||
@@ -272,7 +271,7 @@ DEF_OP(AtomicFetchAdd) {
|
||||
mov(ecx, GetSrc<RA_32>(Op->Header.Args[1].ID()));
|
||||
lock();
|
||||
xadd(dword [MemReg], ecx);
|
||||
mov(GetDst<RA_32>(Node), ecx);
|
||||
mov(GetDst<RA_64>(Node), ecx);
|
||||
break;
|
||||
case 8:
|
||||
mov(rcx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
@@ -280,7 +279,7 @@ DEF_OP(AtomicFetchAdd) {
|
||||
xadd(qword [MemReg], rcx);
|
||||
mov(GetDst<RA_64>(Node), rcx);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +316,7 @@ DEF_OP(AtomicFetchSub) {
|
||||
xadd(qword [MemReg], rcx);
|
||||
mov(GetDst<RA_64>(Node), rcx);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +394,7 @@ DEF_OP(AtomicFetchAnd) {
|
||||
mov(GetDst<RA_64>(Node), TMP3.cvt64());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +471,7 @@ DEF_OP(AtomicFetchOr) {
|
||||
mov(GetDst<RA_64>(Node), TMP3.cvt64());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +548,7 @@ DEF_OP(AtomicFetchXor) {
|
||||
mov(GetDst<RA_64>(Node), TMP3.cvt64());
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ DEF_OP(ExitFunction) {
|
||||
jmp(qword[rax]);
|
||||
|
||||
L(l_BranchHost);
|
||||
dq(Dispatcher->ExitFunctionLinkerAddress);
|
||||
dq(ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress);
|
||||
L(l_BranchGuest);
|
||||
dq(NewRIP);
|
||||
} else {
|
||||
@@ -101,7 +101,7 @@ DEF_OP(ExitFunction) {
|
||||
jmp(qword[LookupBase + 0]);
|
||||
|
||||
L(FullLookup);
|
||||
mov(rax, Dispatcher->AbsoluteLoopTopAddress);
|
||||
mov(rax, ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress);
|
||||
mov(qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, State.rip)], RipReg);
|
||||
jmp(rax);
|
||||
}
|
||||
@@ -253,7 +253,7 @@ DEF_OP(ValidateCode) {
|
||||
int idx = 0;
|
||||
|
||||
xor_(GetDst<RA_64>(Node), GetDst<RA_64>(Node));
|
||||
mov(rax, IR->GetHeader()->Entry + Op->Offset);
|
||||
mov(rax, Entry + Op->Offset);
|
||||
mov(rbx, 1);
|
||||
while (len >= 4) {
|
||||
cmp(dword[rax + idx], *(uint32_t*)(OldCode + idx));
|
||||
@@ -286,7 +286,7 @@ DEF_OP(RemoveCodeEntry) {
|
||||
sub(rsp, 8); // Align
|
||||
|
||||
mov(rdi, STATE);
|
||||
mov(rax, IR->GetHeader()->Entry); // imm64 move
|
||||
mov(rax, Entry); // imm64 move
|
||||
mov(rsi, rax);
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ DEF_OP(VInsGPR) {
|
||||
pinsrq(GetDst(Node), GetSrc<RA_64>(Op->Header.Args[1].ID()), Op->Index);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,12 +52,12 @@ DEF_OP(VCastFromGPR) {
|
||||
case 8:
|
||||
vmovq(GetDst(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()).cvt64());
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Float_FromGPR_U) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(Float_FromGPR_S) {
|
||||
@@ -95,12 +95,12 @@ DEF_OP(Float_FToF) {
|
||||
cvtsd2ss(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown FCVT sizes: 0x%x", Conv);
|
||||
default: LOGMAN_MSG_A("Unknown FCVT sizes: 0x%x", Conv);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Vector_UToF) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(Vector_SToF) {
|
||||
@@ -121,12 +121,12 @@ DEF_OP(Vector_SToF) {
|
||||
cvtsi2sd(xmm15, rax);
|
||||
movlhps(GetDst(Node), xmm15);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Vector_FToZU) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(Vector_FToZS) {
|
||||
@@ -138,12 +138,12 @@ DEF_OP(Vector_FToZS) {
|
||||
case 8:
|
||||
cvttpd2dq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Vector_FToU) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(Vector_FToS) {
|
||||
@@ -155,7 +155,7 @@ DEF_OP(Vector_FToS) {
|
||||
case 8:
|
||||
cvtpd2dq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ DEF_OP(Vector_FToF) {
|
||||
cvtpd2ps(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Conversion Type : 0%04x", Conv); break;
|
||||
default: LOGMAN_MSG_A("Unknown Conversion Type : 0%04x", Conv); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-21
@@ -15,6 +15,7 @@ $end_info$
|
||||
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Core/UContext.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <signal.h>
|
||||
@@ -30,17 +31,17 @@ CodeBuffer AllocateNewCodeBuffer(size_t Size) {
|
||||
CodeBuffer Buffer;
|
||||
Buffer.Size = Size;
|
||||
Buffer.Ptr = static_cast<uint8_t*>(
|
||||
mmap(nullptr,
|
||||
FEXCore::Allocator::mmap(nullptr,
|
||||
Buffer.Size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0));
|
||||
LogMan::Throw::A(Buffer.Ptr != reinterpret_cast<uint8_t*>(~0ULL), "Couldn't allocate code buffer");
|
||||
LOGMAN_THROW_A(Buffer.Ptr != reinterpret_cast<uint8_t*>(~0ULL), "Couldn't allocate code buffer");
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
void FreeCodeBuffer(CodeBuffer Buffer) {
|
||||
munmap(Buffer.Ptr, Buffer.Size);
|
||||
FEXCore::Allocator::munmap(Buffer.Ptr, Buffer.Size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,7 +85,7 @@ void X86JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
|
||||
FallbackInfo Info;
|
||||
if (!InterpreterOps::GetFallbackHandler(IROp, &Info)) {
|
||||
auto Name = FEXCore::IR::GetName(IROp->Op);
|
||||
LogMan::Msg::A("Unhandled IR Op: %s", std::string(Name).c_str());
|
||||
LOGMAN_MSG_A("Unhandled IR Op: %s", std::string(Name).c_str());
|
||||
} else {
|
||||
switch(Info.ABI) {
|
||||
case FABI_VOID_U16: {
|
||||
@@ -282,7 +283,7 @@ void X86JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
|
||||
case FABI_UNKNOWN:
|
||||
default:
|
||||
auto Name = FEXCore::IR::GetName(IROp->Op);
|
||||
LogMan::Msg::A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
|
||||
LOGMAN_MSG_A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,13 +331,13 @@ X86JITCore::X86JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalTh
|
||||
config.ExitFunctionLink = reinterpret_cast<uintptr_t>(&ExitFunctionLink);
|
||||
config.ExitFunctionLinkThis = reinterpret_cast<uintptr_t>(this);
|
||||
|
||||
Dispatcher = new X86Dispatcher(CTX, ThreadState, config);
|
||||
Dispatcher = std::make_unique<X86Dispatcher>(CTX, ThreadState, config);
|
||||
DispatchPtr = Dispatcher->DispatchPtr;
|
||||
CallbackPtr = Dispatcher->CallbackPtr;
|
||||
|
||||
ThreadSharedData.SignalHandlerRefCounterPtr = &Dispatcher->SignalHandlerRefCounter;
|
||||
ThreadSharedData.SignalHandlerReturnAddress = Dispatcher->SignalHandlerReturnAddress;
|
||||
|
||||
ThreadSharedData.Dispatcher = Dispatcher.get();
|
||||
|
||||
// This will register the host signal handler per thread, which is fine
|
||||
CTX->SignalDelegation->RegisterHostSignalHandler(SIGILL, [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool {
|
||||
@@ -413,7 +414,7 @@ void X86JITCore::ClearCache() {
|
||||
IR::PhysicalRegister X86JITCore::GetPhys(uint32_t Node) {
|
||||
auto PhyReg = RAData->GetNodeRegister(Node);
|
||||
|
||||
LogMan::Throw::A(PhyReg.Raw != 255, "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
|
||||
LOGMAN_THROW_A(PhyReg.Raw != 255, "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
|
||||
|
||||
return PhyReg;
|
||||
}
|
||||
@@ -529,7 +530,7 @@ bool X86JITCore::IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode, u
|
||||
if (OpHeader->Op == IR::IROps::OP_INLINEENTRYPOINTOFFSET) {
|
||||
auto Op = OpHeader->C<IR::IROp_InlineEntrypointOffset>();
|
||||
if (Value) {
|
||||
*Value = IR->GetHeader()->Entry + Op->Offset;
|
||||
*Value = Entry + Op->Offset;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
@@ -562,7 +563,7 @@ std::tuple<X86JITCore::SetCC, X86JITCore::CMovCC, X86JITCore::JCC> X86JITCore::G
|
||||
case FEXCore::IR::COND_VS:
|
||||
case FEXCore::IR::COND_VC:
|
||||
default:
|
||||
LogMan::Msg::A("Unsupported compare type");
|
||||
LOGMAN_MSG_A("Unsupported compare type");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -570,10 +571,11 @@ std::tuple<X86JITCore::SetCC, X86JITCore::CMovCC, X86JITCore::JCC> X86JITCore::G
|
||||
return { &CodeGenerator::sete , &CodeGenerator::cmove , &CodeGenerator::je };
|
||||
}
|
||||
|
||||
void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||
void *X86JITCore::CompileCode(uint64_t Entry, [[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||
JumpTargets.clear();
|
||||
uint32_t SSACount = IR->GetSSACount();
|
||||
|
||||
this->Entry = Entry;
|
||||
this->RAData = RAData;
|
||||
|
||||
// Fairly excessive buffer range to make sure we don't overflow
|
||||
@@ -582,7 +584,7 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
|
||||
ThreadState->CTX->ClearCodeCache(ThreadState, false);
|
||||
}
|
||||
|
||||
void *Entry = getCurr<void*>();
|
||||
void *GuestEntry = getCurr<void*>();
|
||||
this->IR = IR;
|
||||
|
||||
if (CTX->GetGdbServerStatus()) {
|
||||
@@ -597,14 +599,14 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
|
||||
cmp(dword [rax + (offsetof(FEXCore::Context::Context, Config.RunningMode))], 0);
|
||||
je(RunBlock);
|
||||
// Else we need to pause now
|
||||
mov(rax, Dispatcher->ThreadPauseHandlerAddress);
|
||||
mov(rax, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddress);
|
||||
jmp(rax);
|
||||
ud2();
|
||||
|
||||
L(RunBlock);
|
||||
}
|
||||
|
||||
LogMan::Throw::A(RAData != nullptr, "Needs RA");
|
||||
LOGMAN_THROW_A(RAData != nullptr, "Needs RA");
|
||||
|
||||
SpillSlots = RAData->SpillSlots();
|
||||
|
||||
@@ -613,7 +615,7 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
|
||||
}
|
||||
|
||||
#ifdef BLOCKSTATS
|
||||
BlockSamplingData::BlockData *SamplingData = CTX->BlockData->GetBlockData(HeaderOp->Entry);
|
||||
BlockSamplingData::BlockData *SamplingData = CTX->BlockData->GetBlockData(Entry);
|
||||
if (GetSamplingData) {
|
||||
mov(rcx, reinterpret_cast<uintptr_t>(SamplingData));
|
||||
rdtsc();
|
||||
@@ -661,7 +663,7 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
|
||||
using namespace FEXCore::IR;
|
||||
{
|
||||
auto BlockIROp = BlockHeader->CW<IROp_CodeBlock>();
|
||||
LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
LOGMAN_THROW_A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
|
||||
uint32_t Node = IR->GetID(BlockNode);
|
||||
auto IsTarget = JumpTargets.find(Node);
|
||||
@@ -730,15 +732,15 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
|
||||
}
|
||||
PendingTargetLabel = nullptr;
|
||||
|
||||
void *Exit = getCurr<void*>();
|
||||
void *GuestExit = getCurr<void*>();
|
||||
this->IR = nullptr;
|
||||
|
||||
ready();
|
||||
|
||||
if (DebugData) {
|
||||
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(Exit) - reinterpret_cast<uintptr_t>(Entry);
|
||||
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(GuestExit) - reinterpret_cast<uintptr_t>(GuestEntry);
|
||||
}
|
||||
return Entry;
|
||||
return GuestEntry;
|
||||
}
|
||||
|
||||
uint64_t X86JITCore::ExitFunctionLink(X86JITCore *core, FEXCore::Core::CpuStateFrame *Frame, uint64_t *record) {
|
||||
@@ -749,10 +751,10 @@ uint64_t X86JITCore::ExitFunctionLink(X86JITCore *core, FEXCore::Core::CpuStateF
|
||||
|
||||
if (!HostCode) {
|
||||
Thread->CurrentFrame->State.rip = GuestRip;
|
||||
return core->Dispatcher->AbsoluteLoopTopAddress;
|
||||
return core->ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress;
|
||||
}
|
||||
|
||||
auto LinkerAddress = core->Dispatcher->ExitFunctionLinkerAddress;
|
||||
auto LinkerAddress = core->ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress;
|
||||
Thread->LookupCache->AddBlockLink(GuestRip, (uintptr_t)record, [record, LinkerAddress]{
|
||||
// undo the link
|
||||
record[0] = LinkerAddress;
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
explicit X86JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, CodeBuffer Buffer, bool CompileThread);
|
||||
~X86JITCore() override;
|
||||
std::string GetName() override { return "JIT"; }
|
||||
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||
|
||||
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
||||
|
||||
@@ -83,7 +83,8 @@ private:
|
||||
FEXCore::Context::Context *CTX;
|
||||
FEXCore::Core::InternalThreadState *ThreadState;
|
||||
FEXCore::IR::IRListView const *IR;
|
||||
FEXCore::CPU::Dispatcher *Dispatcher;
|
||||
std::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
|
||||
uint64_t Entry;
|
||||
|
||||
std::unordered_map<IR::OrderedNodeWrapper::NodeOffsetType, Label> JumpTargets;
|
||||
Xbyak::util::Cpu Features{};
|
||||
@@ -161,6 +162,7 @@ private:
|
||||
uint64_t SignalHandlerReturnAddress{};
|
||||
|
||||
uint32_t *SignalHandlerRefCounterPtr{};
|
||||
FEXCore::CPU::Dispatcher *Dispatcher{};
|
||||
};
|
||||
|
||||
CompilerSharedData ThreadSharedData;
|
||||
@@ -306,6 +308,7 @@ private:
|
||||
DEF_OP(StoreMem);
|
||||
DEF_OP(VLoadMemElement);
|
||||
DEF_OP(VStoreMemElement);
|
||||
DEF_OP(CacheLineClear);
|
||||
|
||||
///< Misc ops
|
||||
DEF_OP(EndBlock);
|
||||
|
||||
+39
-30
@@ -36,10 +36,10 @@ DEF_OP(LoadContext) {
|
||||
}
|
||||
break;
|
||||
case 16: {
|
||||
LogMan::Msg::A("Invalid GPR load of size 16");
|
||||
LOGMAN_MSG_A("Invalid GPR load of size 16");
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -69,7 +69,7 @@ DEF_OP(LoadContext) {
|
||||
movups(GetDst(Node), xword [STATE + Op->Offset]);
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ DEF_OP(StoreContext) {
|
||||
case 16:
|
||||
LogMan::Msg::D("Invalid store size of 16");
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -129,7 +129,7 @@ DEF_OP(StoreContext) {
|
||||
movups(xword [STATE + Op->Offset], GetSrc(Op->Header.Args[0].ID()));
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreContext size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreContext size: %d", OpSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,15 +160,15 @@ DEF_OP(LoadContextIndexed) {
|
||||
mov(GetDst<RA_64>(Node), qword [rax + index * Op->Stride]);
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
LogMan::Msg::A("Invalid Class load of size 16");
|
||||
LOGMAN_MSG_A("Invalid Class load of size 16");
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -195,7 +195,7 @@ DEF_OP(LoadContextIndexed) {
|
||||
vmovq(GetDst(Node), qword [rax + index * Op->Stride]);
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -223,12 +223,12 @@ DEF_OP(LoadContextIndexed) {
|
||||
movups(GetDst(Node), xword [STATE + rax]);
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,13 +248,13 @@ DEF_OP(StoreContextIndexed) {
|
||||
case 4:
|
||||
case 8: {
|
||||
if (!(size == 1 || size == 2 || size == 4 || size == 8)) {
|
||||
LogMan::Msg::A("Unhandled StoreContextIndexed size: %d", Op->Size);
|
||||
LOGMAN_MSG_A("Unhandled StoreContextIndexed size: %d", Op->Size);
|
||||
}
|
||||
mov(AddressFrame(Op->Size * 8) [rax + index * Op->Stride], value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -279,7 +279,7 @@ DEF_OP(StoreContextIndexed) {
|
||||
vmovq(AddressFrame(Op->Size * 8) [rax + index * Op->Stride], value);
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled StoreContextIndexed size: %d", size);
|
||||
LOGMAN_MSG_A("Unhandled StoreContextIndexed size: %d", size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -307,12 +307,12 @@ DEF_OP(StoreContextIndexed) {
|
||||
movups(xword [STATE + rax], value);
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled StoreContextIndexed size: %d", size);
|
||||
LOGMAN_MSG_A("Unhandled StoreContextIndexed size: %d", size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
|
||||
LOGMAN_MSG_A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,7 +340,7 @@ DEF_OP(SpillRegister) {
|
||||
mov(qword [rsp + SlotOffset], GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
|
||||
}
|
||||
} else if (Op->Class == FEXCore::IR::FPRClass) {
|
||||
switch (OpSize) {
|
||||
@@ -356,10 +356,10 @@ DEF_OP(SpillRegister) {
|
||||
movaps(xword [rsp + SlotOffset], GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
LogMan::Msg::A("Unhandled SpillRegister class: %d", Op->Class.Val);
|
||||
LOGMAN_MSG_A("Unhandled SpillRegister class: %d", Op->Class.Val);
|
||||
}
|
||||
|
||||
|
||||
@@ -388,7 +388,7 @@ DEF_OP(FillRegister) {
|
||||
mov(GetDst<RA_64>(Node), qword [rsp + SlotOffset]);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled FillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled FillRegister size: %d", OpSize);
|
||||
}
|
||||
} else if (Op->Class == FEXCore::IR::FPRClass) {
|
||||
switch (OpSize) {
|
||||
@@ -404,10 +404,10 @@ DEF_OP(FillRegister) {
|
||||
movaps(GetDst(Node), xword [rsp + SlotOffset]);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unhandled FillRegister size: %d", OpSize);
|
||||
default: LOGMAN_MSG_A("Unhandled FillRegister size: %d", OpSize);
|
||||
}
|
||||
} else {
|
||||
LogMan::Msg::A("Unhandled FillRegister class: %d", Op->Class.Val);
|
||||
LOGMAN_MSG_A("Unhandled FillRegister class: %d", Op->Class.Val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,11 +430,11 @@ Xbyak::RegExp X86JITCore::GenerateModRM(Xbyak::Reg Base, IR::OrderedNodeWrapper
|
||||
return Base;
|
||||
} else {
|
||||
if (OffsetScale != 1 && OffsetScale != 2 && OffsetScale != 4 && OffsetScale != 8) {
|
||||
LogMan::Msg::A("Unhandled GenerateModRM OffsetScale: %d", OffsetScale);
|
||||
LOGMAN_MSG_A("Unhandled GenerateModRM OffsetScale: %d", OffsetScale);
|
||||
}
|
||||
|
||||
if (OffsetType != IR::MEM_OFFSET_SXTX) {
|
||||
LogMan::Msg::A("Unhandled GenerateModRM OffsetType: %d", OffsetType.Val);
|
||||
LOGMAN_MSG_A("Unhandled GenerateModRM OffsetType: %d", OffsetType.Val);
|
||||
}
|
||||
|
||||
uint64_t Const;
|
||||
@@ -475,7 +475,7 @@ DEF_OP(LoadMem) {
|
||||
mov(Dst, qword [MemPtr]);
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -511,7 +511,7 @@ DEF_OP(LoadMem) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -537,7 +537,7 @@ DEF_OP(StoreMem) {
|
||||
case 8:
|
||||
mov(qword [MemPtr], GetSrc<RA_64>(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -560,17 +560,25 @@ DEF_OP(StoreMem) {
|
||||
else
|
||||
movups(xword [MemPtr], GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
|
||||
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VLoadMemElement) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VStoreMemElement) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(CacheLineClear) {
|
||||
auto Op = IROp->C<IR::IROp_CacheLineClear>();
|
||||
|
||||
Xbyak::Reg MemReg = GetSrc<RA_64>(Op->Addr.ID());
|
||||
|
||||
clflush(ptr [MemReg]);
|
||||
}
|
||||
|
||||
#undef DEF_OP
|
||||
@@ -592,6 +600,7 @@ void X86JITCore::RegisterMemoryHandlers() {
|
||||
REGISTER_OP(STOREMEMTSO, StoreMem);
|
||||
REGISTER_OP(VLOADMEMELEMENT, VLoadMemElement);
|
||||
REGISTER_OP(VSTOREMEMELEMENT, VStoreMemElement);
|
||||
REGISTER_OP(CACHELINECLEAR, CacheLineClear);
|
||||
#undef REGISTER_OP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ DEF_OP(Fence) {
|
||||
case IR::Fence_Store.Val:
|
||||
sfence();
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Fence: %d", Op->Fence); break;
|
||||
default: LOGMAN_MSG_A("Unknown Fence: %d", Op->Fence); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,22 @@ DEF_OP(Break) {
|
||||
case 5: // Guest ud2
|
||||
ud2();
|
||||
break;
|
||||
case 1: // Int <imm8>
|
||||
ud2();
|
||||
break;
|
||||
case 2: // overflow
|
||||
ud2();
|
||||
break;
|
||||
case 3: // int 1
|
||||
ud2();
|
||||
break;
|
||||
case 4: { // HLT
|
||||
// Time to quit
|
||||
// Set our stack to the starting stack location
|
||||
mov(rsp, qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, ReturningStackLocation)]);
|
||||
|
||||
// Now we need to jump to the thread stop handler
|
||||
mov(TMP1, Dispatcher->ThreadStopHandlerAddress);
|
||||
mov(TMP1, ThreadSharedData.Dispatcher->ThreadStopHandlerAddress);
|
||||
jmp(TMP1);
|
||||
break;
|
||||
}
|
||||
@@ -56,7 +65,7 @@ DEF_OP(Break) {
|
||||
}
|
||||
|
||||
// This jump target needs to be a constant offset here
|
||||
mov(TMP1, Dispatcher->ThreadPauseHandlerAddress);
|
||||
mov(TMP1, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddress);
|
||||
jmp(TMP1);
|
||||
}
|
||||
else {
|
||||
@@ -65,12 +74,12 @@ DEF_OP(Break) {
|
||||
mov(rsp, qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, ReturningStackLocation)]);
|
||||
|
||||
// Now we need to jump to the thread stop handler
|
||||
mov(TMP1, Dispatcher->ThreadStopHandlerAddress);
|
||||
mov(TMP1, ThreadSharedData.Dispatcher->ThreadStopHandlerAddress);
|
||||
jmp(TMP1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Break reason: %d", Op->Reason);
|
||||
default: LOGMAN_MSG_A("Unknown Break reason: %d", Op->Reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ DEF_OP(ExtractElementPair) {
|
||||
mov (GetDst<RA_64>(Node), Regs[Op->Element]);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Size"); break;
|
||||
default: LOGMAN_MSG_A("Unknown Size"); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ DEF_OP(CreateElementPair) {
|
||||
RegTmp = rax;
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Size"); break;
|
||||
default: LOGMAN_MSG_A("Unknown Size"); break;
|
||||
}
|
||||
|
||||
if (Dst.first != RegSecond) {
|
||||
|
||||
+119
-103
@@ -62,24 +62,24 @@ DEF_OP(VectorImm) {
|
||||
}
|
||||
|
||||
DEF_OP(CreateVector2) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(CreateVector4) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(SplatVector) {
|
||||
auto Op = IROp->C<IR::IROp_SplatVector2>();
|
||||
uint8_t OpSize = IROp->Size;
|
||||
|
||||
LogMan::Throw::A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
|
||||
LOGMAN_THROW_A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
|
||||
uint8_t Elements = 0;
|
||||
|
||||
switch (Op->Header.Op) {
|
||||
case IR::OP_SPLATVECTOR4: Elements = 4; break;
|
||||
case IR::OP_SPLATVECTOR2: Elements = 2; break;
|
||||
default: LogMan::Msg::A("Uknown Splat size"); break;
|
||||
default: LOGMAN_MSG_A("Uknown Splat size"); break;
|
||||
}
|
||||
|
||||
uint8_t ElementSize = OpSize / Elements;
|
||||
@@ -92,7 +92,7 @@ DEF_OP(SplatVector) {
|
||||
case 8:
|
||||
movddup(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.Size); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ DEF_OP(VMov) {
|
||||
movaps(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ DEF_OP(VAdd) {
|
||||
vpaddq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ DEF_OP(VSub) {
|
||||
vpsubq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ DEF_OP(VUQAdd) {
|
||||
vpaddusw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ DEF_OP(VUQSub) {
|
||||
vpsubusw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ DEF_OP(VSQAdd) {
|
||||
vpaddsw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ DEF_OP(VSQSub) {
|
||||
vpsubsw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ DEF_OP(VAddP) {
|
||||
case 4:
|
||||
vphaddd(GetDst(Node), xmm15, xmm14);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -317,7 +317,7 @@ DEF_OP(VAddP) {
|
||||
case 4:
|
||||
vphaddd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,7 +349,7 @@ DEF_OP(VAddV) {
|
||||
pinsrd(xmm15, eax, 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
movaps(Dest, xmm15);
|
||||
@@ -366,7 +366,7 @@ DEF_OP(VURAvg) {
|
||||
vpavgw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ DEF_OP(VAbs) {
|
||||
vpabsq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ DEF_OP(VFAdd) {
|
||||
vaddsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -422,7 +422,7 @@ DEF_OP(VFAdd) {
|
||||
vaddpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,7 +436,7 @@ DEF_OP(VFAddP) {
|
||||
case 8:
|
||||
vhaddpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ DEF_OP(VFSub) {
|
||||
vsubsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -469,7 +469,7 @@ DEF_OP(VFSub) {
|
||||
vsubpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,7 +489,7 @@ DEF_OP(VFMul) {
|
||||
vmulsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -503,7 +503,7 @@ DEF_OP(VFMul) {
|
||||
vmulpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -523,7 +523,7 @@ DEF_OP(VFDiv) {
|
||||
vdivsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -537,7 +537,7 @@ DEF_OP(VFDiv) {
|
||||
vdivpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -557,7 +557,7 @@ DEF_OP(VFMin) {
|
||||
vminsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -571,7 +571,7 @@ DEF_OP(VFMin) {
|
||||
vminpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,7 +591,7 @@ DEF_OP(VFMax) {
|
||||
vmaxsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -605,7 +605,7 @@ DEF_OP(VFMax) {
|
||||
vmaxpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -623,7 +623,7 @@ DEF_OP(VFRecp) {
|
||||
vdivss(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -636,7 +636,7 @@ DEF_OP(VFRecp) {
|
||||
vdivps(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,7 +656,7 @@ DEF_OP(VFSqrt) {
|
||||
vsqrtsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -670,7 +670,7 @@ DEF_OP(VFSqrt) {
|
||||
vsqrtpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,7 +696,7 @@ DEF_OP(VFRSqrt) {
|
||||
divsd(GetDst(Node), xmm15);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -710,7 +710,7 @@ DEF_OP(VFRSqrt) {
|
||||
divps(GetDst(Node), xmm15);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -735,7 +735,7 @@ DEF_OP(VNeg) {
|
||||
vpsubq(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +756,7 @@ DEF_OP(VFNeg) {
|
||||
vxorpd(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,20 +768,36 @@ DEF_OP(VNot) {
|
||||
|
||||
DEF_OP(VUMin) {
|
||||
auto Op = IROp->C<IR::IROp_VUMin>();
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 1: {
|
||||
vpminub(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
if (Op->Header.Size == Op->Header.ElementSize) {
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 8: {
|
||||
// This isn't very nice on x86 until AVX-512
|
||||
pextrq(TMP1, GetSrc(Op->Header.Args[0].ID()), 0);
|
||||
pextrq(TMP2, GetSrc(Op->Header.Args[1].ID()), 0);
|
||||
cmp(TMP1, TMP2);
|
||||
cmovb(TMP2, TMP1);
|
||||
pinsrq(GetDst(Node), TMP2, 0);
|
||||
break;
|
||||
}
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
case 2: {
|
||||
vpminuw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 1: {
|
||||
vpminub(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
vpminuw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
vpminud(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
case 4: {
|
||||
vpminud(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,7 +816,7 @@ DEF_OP(VSMin) {
|
||||
vpminsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,7 +835,7 @@ DEF_OP(VUMax) {
|
||||
vpmaxud(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,7 +854,7 @@ DEF_OP(VSMax) {
|
||||
vpmaxsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,7 +879,7 @@ DEF_OP(VZip) {
|
||||
punpcklqdq(xmm15, GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
movapd(GetDst(Node), xmm15);
|
||||
}
|
||||
@@ -890,7 +906,7 @@ DEF_OP(VZip2) {
|
||||
vpunpckhdq(GetDst(Node), xmm15, xmm14);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -911,7 +927,7 @@ DEF_OP(VZip2) {
|
||||
punpckhqdq(xmm15, GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
movapd(GetDst(Node), xmm15);
|
||||
}
|
||||
@@ -940,7 +956,7 @@ DEF_OP(VCMPEQ) {
|
||||
case 8:
|
||||
vpcmpeqq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,7 +977,7 @@ DEF_OP(VCMPEQZ) {
|
||||
case 8:
|
||||
vpcmpeqq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), xmm15);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,7 +997,7 @@ DEF_OP(VCMPGT) {
|
||||
case 8:
|
||||
vpcmpgtq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1002,7 +1018,7 @@ DEF_OP(VCMPGTZ) {
|
||||
case 8:
|
||||
vpcmpgtq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), xmm15);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1023,7 +1039,7 @@ DEF_OP(VCMPLTZ) {
|
||||
case 8:
|
||||
vpcmpgtq(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,7 +1055,7 @@ DEF_OP(VFCMPEQ) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 0);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1050,7 +1066,7 @@ DEF_OP(VFCMPEQ) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 0);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1067,7 +1083,7 @@ DEF_OP(VFCMPNEQ) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 4);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1079,7 +1095,7 @@ DEF_OP(VFCMPNEQ) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 4);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1096,7 +1112,7 @@ DEF_OP(VFCMPLT) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1107,7 +1123,7 @@ DEF_OP(VFCMPLT) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1124,7 +1140,7 @@ DEF_OP(VFCMPGT) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[1].ID()), GetSrc(Op->Header.Args[0].ID()), 1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1135,7 +1151,7 @@ DEF_OP(VFCMPGT) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[1].ID()), GetSrc(Op->Header.Args[0].ID()), 1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1152,7 +1168,7 @@ DEF_OP(VFCMPLE) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 2);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1163,7 +1179,7 @@ DEF_OP(VFCMPLE) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 2);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1180,7 +1196,7 @@ DEF_OP(VFCMPORD) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 7);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1191,7 +1207,7 @@ DEF_OP(VFCMPORD) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 7);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1208,7 +1224,7 @@ DEF_OP(VFCMPUNO) {
|
||||
case 8:
|
||||
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 3);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1219,21 +1235,21 @@ DEF_OP(VFCMPUNO) {
|
||||
case 8:
|
||||
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 3);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VUShl) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VUShr) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VSShr) {
|
||||
LogMan::Msg::A("Unimplemented");
|
||||
LOGMAN_MSG_A("Unimplemented");
|
||||
}
|
||||
|
||||
DEF_OP(VUShlS) {
|
||||
@@ -1252,7 +1268,7 @@ DEF_OP(VUShlS) {
|
||||
vpsllq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1272,7 +1288,7 @@ DEF_OP(VUShrS) {
|
||||
vpsrlq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,7 +1305,7 @@ DEF_OP(VSShrS) {
|
||||
break;
|
||||
}
|
||||
case 8: // Doesn't exist on x86
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1322,7 +1338,7 @@ DEF_OP(VInsElement) {
|
||||
pinsrq(xmm15, rax, Op->DestIdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
movapd(GetDst(Node), xmm15);
|
||||
@@ -1357,7 +1373,7 @@ DEF_OP(VInsScalarElement) {
|
||||
pinsrq(xmm15, rax, Op->DestIdx);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
movapd(GetDst(Node), xmm15);
|
||||
@@ -1387,7 +1403,7 @@ DEF_OP(VExtractElement) {
|
||||
pinsrq(GetDst(Node), rax, 0);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1438,7 +1454,7 @@ DEF_OP(VUShrI) {
|
||||
psrlq(GetDst(Node), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1454,7 +1470,7 @@ DEF_OP(VSShrI) {
|
||||
psrad(GetDst(Node), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1474,7 +1490,7 @@ DEF_OP(VShlI) {
|
||||
psllq(GetDst(Node), Op->BitShift);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1504,7 +1520,7 @@ DEF_OP(VUShrNI) {
|
||||
mov(rcx, 0x80'80'80'80'80'80'80'80); // Upper
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
vmovq(xmm15, rax);
|
||||
@@ -1540,7 +1556,7 @@ DEF_OP(VUShrNI2) {
|
||||
mov(rcx, 0x0B'0A'09'08'03'02'01'00); // Upper
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
|
||||
vmovq(xmm15, rax);
|
||||
@@ -1567,7 +1583,7 @@ DEF_OP(VSXTL) {
|
||||
case 8:
|
||||
pmovsxdq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1586,7 +1602,7 @@ DEF_OP(VSXTL2) {
|
||||
case 8:
|
||||
pmovsxdq(GetDst(Node), GetDst(Node));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1602,7 +1618,7 @@ DEF_OP(VUXTL) {
|
||||
case 8:
|
||||
pmovzxdq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1621,7 +1637,7 @@ DEF_OP(VUXTL2) {
|
||||
case 8:
|
||||
pmovzxdq(GetDst(Node), GetDst(Node));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1634,7 +1650,7 @@ DEF_OP(VSQXTN) {
|
||||
case 2:
|
||||
packssdw(xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
psrldq(xmm15, 8);
|
||||
movaps(GetDst(Node), xmm15);
|
||||
@@ -1653,7 +1669,7 @@ DEF_OP(VSQXTN2) {
|
||||
case 2:
|
||||
packssdw(xmm15, GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
|
||||
if (OpSize == 8) {
|
||||
@@ -1671,7 +1687,7 @@ DEF_OP(VSQXTUN) {
|
||||
case 2:
|
||||
packusdw(xmm15, GetSrc(Op->Header.Args[0].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
psrldq(xmm15, 8);
|
||||
movaps(GetDst(Node), xmm15);
|
||||
@@ -1690,7 +1706,7 @@ DEF_OP(VSQXTUN2) {
|
||||
case 2:
|
||||
packusdw(xmm15, GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
|
||||
}
|
||||
if (OpSize == 8) {
|
||||
psrldq(xmm15, OpSize / 2);
|
||||
@@ -1710,7 +1726,7 @@ DEF_OP(VMul) {
|
||||
vpmulld(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1741,7 +1757,7 @@ DEF_OP(VUMull) {
|
||||
vpmuludq(GetDst(Node), xmm14, xmm15);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1776,7 +1792,7 @@ DEF_OP(VSMull) {
|
||||
vpmuldq(GetDst(Node), xmm14, xmm15);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1812,7 +1828,7 @@ DEF_OP(VUMull2) {
|
||||
vpmuludq(GetDst(Node), xmm14, xmm15);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1852,7 +1868,7 @@ DEF_OP(VSMull2) {
|
||||
vpmuldq(GetDst(Node), xmm14, xmm15);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1870,7 +1886,7 @@ DEF_OP(VTBL1) {
|
||||
vpshufb(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown OpSize: %d", OpSize); break;
|
||||
default: LOGMAN_MSG_A("Unknown OpSize: %d", OpSize); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -8,6 +8,8 @@ $end_info$
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/Core.h"
|
||||
#include "Interface/Core/LookupCache.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace FEXCore {
|
||||
@@ -26,27 +28,27 @@ LookupCache::LookupCache(FEXCore::Context::Context *CTX)
|
||||
// Allocate a region of memory that we can use to back our block pointers
|
||||
// We need one pointer per page of virtual memory
|
||||
// At 64GB of virtual memory this will allocate 128MB of virtual memory space
|
||||
PagePointer = reinterpret_cast<uintptr_t>(mmap(nullptr, ctx->Config.VirtualMemSize / 4096 * 8, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
PagePointer = reinterpret_cast<uintptr_t>(FEXCore::Allocator::mmap(nullptr, ctx->Config.VirtualMemSize / 4096 * 8, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
|
||||
// Allocate our memory backing our pages
|
||||
// We need 32KB per guest page (One pointer per byte)
|
||||
// XXX: We can drop down to 16KB if we store 4byte offsets from the code base
|
||||
// We currently limit to 128MB of real memory for caching for the total cache size.
|
||||
// Can end up being inefficient if we compile a small number of blocks per page
|
||||
PageMemory = reinterpret_cast<uintptr_t>(mmap(nullptr, CODE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
LogMan::Throw::A(PageMemory != -1ULL, "Failed to allocate page memory");
|
||||
PageMemory = reinterpret_cast<uintptr_t>(FEXCore::Allocator::mmap(nullptr, CODE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
LOGMAN_THROW_A(PageMemory != -1ULL, "Failed to allocate page memory");
|
||||
|
||||
// L1 Cache
|
||||
L1Pointer = reinterpret_cast<uintptr_t>(mmap(nullptr, L1_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
LogMan::Throw::A(L1Pointer != -1ULL, "Failed to allocate L1Pointer");
|
||||
L1Pointer = reinterpret_cast<uintptr_t>(FEXCore::Allocator::mmap(nullptr, L1_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
LOGMAN_THROW_A(L1Pointer != -1ULL, "Failed to allocate L1Pointer");
|
||||
|
||||
VirtualMemSize = ctx->Config.VirtualMemSize;
|
||||
}
|
||||
|
||||
LookupCache::~LookupCache() {
|
||||
munmap(reinterpret_cast<void*>(PagePointer), ctx->Config.VirtualMemSize / 4096 * 8);
|
||||
munmap(reinterpret_cast<void*>(PageMemory), CODE_SIZE);
|
||||
munmap(reinterpret_cast<void*>(L1Pointer), L1_SIZE);
|
||||
FEXCore::Allocator::munmap(reinterpret_cast<void*>(PagePointer), ctx->Config.VirtualMemSize / 4096 * 8);
|
||||
FEXCore::Allocator::munmap(reinterpret_cast<void*>(PageMemory), CODE_SIZE);
|
||||
FEXCore::Allocator::munmap(reinterpret_cast<void*>(L1Pointer), L1_SIZE);
|
||||
}
|
||||
|
||||
void LookupCache::HintUsedRange(uint64_t Address, uint64_t Size) {
|
||||
|
||||
+8
-5
@@ -39,13 +39,17 @@ public:
|
||||
|
||||
void AddBlockMapping(uint64_t Address, void *HostCode, uint64_t Start, uint64_t Length) {
|
||||
auto InsertPoint = BlockList.emplace(Address, (uintptr_t)HostCode);
|
||||
LogMan::Throw::A(InsertPoint.second == true, "Dupplicate block mapping added");
|
||||
LOGMAN_THROW_A(InsertPoint.second == true, "Dupplicate block mapping added");
|
||||
|
||||
for (auto CurrentPage = Start >> 12, EndPage = (Start + Length) >> 12; CurrentPage <= EndPage; CurrentPage++) {
|
||||
CodePages[CurrentPage].push_back(Address);
|
||||
}
|
||||
|
||||
// no need to update L1 or L2, they will get updated on first lookup
|
||||
// There is no need to update L1 or L2, they will get updated on first lookup
|
||||
// However, adding to L1 here increases performance
|
||||
auto &L1Entry = reinterpret_cast<LookupCacheEntry*>(L1Pointer)[Address & L1_ENTRIES_MASK];
|
||||
L1Entry.GuestCode = Address;
|
||||
L1Entry.HostCode = (uintptr_t)HostCode;
|
||||
}
|
||||
|
||||
void Erase(uint64_t Address) {
|
||||
@@ -105,9 +109,8 @@ private:
|
||||
void CacheBlockMapping(uint64_t Address, uintptr_t HostCode) {
|
||||
// Do L1
|
||||
auto &L1Entry = reinterpret_cast<LookupCacheEntry*>(L1Pointer)[Address & L1_ENTRIES_MASK];
|
||||
if (L1Entry.GuestCode == Address) {
|
||||
L1Entry.GuestCode = L1Entry.HostCode = 0;
|
||||
}
|
||||
L1Entry.GuestCode = Address;
|
||||
L1Entry.HostCode = HostCode;
|
||||
|
||||
// Do ful map
|
||||
auto FullAddress = Address;
|
||||
|
||||
+180
-77
@@ -130,6 +130,7 @@ void OpDispatchBuilder::ThunkOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::LEAOp(OpcodeArgs) {
|
||||
// LEA specifically ignores segment prefixes
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
uint32_t DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? 2 :
|
||||
X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? 8 : 4;
|
||||
@@ -188,7 +189,11 @@ RSP
|
||||
SS
|
||||
*/
|
||||
void OpDispatchBuilder::IRETOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode == true, "IRET only implemented for x64");
|
||||
if (CTX->Config.Is64BitMode == false) {
|
||||
LogMan::Msg::E("IRET only implemented for x64");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
@@ -276,7 +281,7 @@ void OpDispatchBuilder::SecondaryALUOp(OpcodeArgs) {
|
||||
break;
|
||||
default:
|
||||
IROp = FEXCore::IR::IROps::OP_LAST;
|
||||
LogMan::Msg::A("Unknown ALU Op: 0x%x", Op->OP);
|
||||
LOGMAN_MSG_A("Unknown ALU Op: 0x%x", Op->OP);
|
||||
break;
|
||||
};
|
||||
#undef OPD
|
||||
@@ -316,7 +321,7 @@ void OpDispatchBuilder::SecondaryALUOp(OpcodeArgs) {
|
||||
Result = _Xor(Dest, Src);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Atomic IR Op: %d", IROp); break;
|
||||
default: LOGMAN_MSG_A("Unknown Atomic IR Op: %d", IROp); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -871,7 +876,7 @@ OrderedNode *OpDispatchBuilder::SelectCC(uint8_t OP, OrderedNode *TrueValue, Ord
|
||||
Check, OneConst, TrueValue, FalseValue);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown CC Op: 0x%x\n", OP); return nullptr;
|
||||
default: LOGMAN_MSG_A("Unknown CC Op: 0x%x\n", OP); return nullptr;
|
||||
}
|
||||
|
||||
// Try folding the flags generation in the select op
|
||||
@@ -997,7 +1002,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) {
|
||||
|
||||
auto SrcCond = SelectCC(Op->OP & 0xF, TakeBranch, DoNotTakeBranch);
|
||||
|
||||
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].TypeLiteral.Literal;
|
||||
|
||||
@@ -1056,7 +1061,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) {
|
||||
TakeBranch = _Constant(1);
|
||||
DoNotTakeBranch = _Constant(0);
|
||||
|
||||
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].TypeLiteral.Literal;
|
||||
|
||||
@@ -1119,7 +1124,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) {
|
||||
|
||||
uint32_t SrcSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) ? 4 : 8;
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Target = Op->PC + Op->InstSize + Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
@@ -1187,7 +1192,7 @@ void OpDispatchBuilder::JUMPOp(OpcodeArgs) {
|
||||
|
||||
// This is just an unconditional relative literal jump
|
||||
if (Multiblock) {
|
||||
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].TypeLiteral.Literal;
|
||||
auto JumpBlock = JumpTargets.find(Target);
|
||||
if (JumpBlock != JumpTargets.end()) {
|
||||
@@ -1492,18 +1497,25 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) {
|
||||
_StoreContext(GPRClass, 2, offsetof(FEXCore::Core::CPUState, ss), Src);
|
||||
break;
|
||||
case 6: // GS
|
||||
LogMan::Throw::A(!CTX->Config.Is64BitMode, "We don't support modifying GS selector in 64bit mode!");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
_StoreContext(GPRClass, 2, offsetof(FEXCore::Core::CPUState, gs), Src);
|
||||
} else {
|
||||
LogMan::Msg::E("We don't support modifying GS selector in 64bit mode!");
|
||||
DecodeFailure = true;
|
||||
}
|
||||
break;
|
||||
case 7: // FS
|
||||
LogMan::Throw::A(!CTX->Config.Is64BitMode, "We don't support modifying FS selector in 64bit mode!");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
_StoreContext(GPRClass, 2, offsetof(FEXCore::Core::CPUState, fs), Src);
|
||||
} else {
|
||||
LogMan::Msg::E("We don't support modifying FS selector in 64bit mode!");
|
||||
DecodeFailure = true;
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown segment register: %d", Op->Dest.TypeGPR.GPR);
|
||||
default:
|
||||
LogMan::Msg::E("Unknown segment register: %d", Op->Dest.TypeGPR.GPR);
|
||||
DecodeFailure = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1538,7 +1550,10 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) {
|
||||
Segment = _LoadContext(2, offsetof(FEXCore::Core::CPUState, fs), GPRClass);
|
||||
}
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown segment register: %d", Op->Src[0].TypeGPR.GPR);
|
||||
default:
|
||||
LogMan::Msg::E("Unknown segment register: %d", Op->Dest.TypeGPR.GPR);
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
StoreResult(GPRClass, Op, Segment, -1);
|
||||
}
|
||||
@@ -1621,7 +1636,7 @@ void OpDispatchBuilder::SHLOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::SHLImmediateOp(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -1679,7 +1694,7 @@ void OpDispatchBuilder::SHROp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::SHRImmediateOp(OpcodeArgs) {
|
||||
auto Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -1756,7 +1771,7 @@ void OpDispatchBuilder::SHLDImmediateOp(OpcodeArgs) {
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -1845,7 +1860,7 @@ void OpDispatchBuilder::SHRDImmediateOp(OpcodeArgs) {
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -1916,7 +1931,7 @@ void OpDispatchBuilder::ASHROp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::ASHRImmediateOp(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -1984,7 +1999,7 @@ void OpDispatchBuilder::ROROp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::RORImmediateOp(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -2062,7 +2077,7 @@ void OpDispatchBuilder::ROLOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::ROLImmediateOp(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -2783,7 +2798,11 @@ void OpDispatchBuilder::IMULOp(OpcodeArgs) {
|
||||
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), LocalResultHigh);
|
||||
}
|
||||
else if (Size == 8) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
LogMan::Msg::E("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
// 64bits stored in RAX
|
||||
// 64bits stored in RDX
|
||||
ResultHigh = _MulH(Src1, Src2);
|
||||
@@ -2828,7 +2847,11 @@ void OpDispatchBuilder::MULOp(OpcodeArgs) {
|
||||
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), ResultHigh);
|
||||
}
|
||||
else if (Size == 8) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
LogMan::Msg::E("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
// 64bits stored in RAX
|
||||
// 64bits stored in RDX
|
||||
ResultHigh = _UMulH(Src1, Src2);
|
||||
@@ -2960,7 +2983,7 @@ void OpDispatchBuilder::WriteSegmentReg(OpcodeArgs) {
|
||||
void OpDispatchBuilder::EnterOp(OpcodeArgs) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Value = Op->Src[0].TypeLiteral.Literal;
|
||||
|
||||
uint16_t AllocSpace = Value & 0xFFFF;
|
||||
@@ -3007,7 +3030,11 @@ void OpDispatchBuilder::RDTSCOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::INCOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX), "Can't handle REP on this\n");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX) {
|
||||
LogMan::Msg::E("Can't handle REP on this");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
OrderedNode *Dest;
|
||||
OrderedNode *Result;
|
||||
@@ -3038,7 +3065,11 @@ void OpDispatchBuilder::INCOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::DECOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX), "Can't handle REP on this\n");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX) {
|
||||
LogMan::Msg::E("Can't handle REP on this");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
OrderedNode *Dest;
|
||||
OrderedNode *Result;
|
||||
@@ -3069,8 +3100,17 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) {
|
||||
|
||||
void OpDispatchBuilder::STOSOp(OpcodeArgs) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "Invalid REPNE on STOS");
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX) {
|
||||
LogMan::Msg::E("Invalid REPNE on STOS");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
|
||||
LogMan::Msg::E("Can't handle adddress size");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto Size = GetSrcSize(Op);
|
||||
|
||||
bool Repeat = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX;
|
||||
@@ -3080,7 +3120,7 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) {
|
||||
OrderedNode *Dest = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
|
||||
// Only ES prefix
|
||||
Dest = AppendSegmentOffset(Dest, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest = AppendSegmentOffset(Dest, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
|
||||
// Store to memory where RDI points
|
||||
_StoreMemAutoTSO(GPRClass, Size, Dest, Src, Size);
|
||||
@@ -3139,7 +3179,7 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) {
|
||||
OrderedNode *Dest = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
|
||||
// Only ES prefix
|
||||
Dest = AppendSegmentOffset(Dest, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest = AppendSegmentOffset(Dest, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
|
||||
// Store to memory where RDI points
|
||||
_StoreMemAutoTSO(GPRClass, Size, Dest, Src, Size);
|
||||
@@ -3169,8 +3209,16 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) {
|
||||
|
||||
void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "Invalid REPNE on MOVS\n");
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX) {
|
||||
LogMan::Msg::E("Invalid REPNE on MOVS");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
|
||||
LogMan::Msg::E("Can't handle adddress size");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// RA now can handle these to be here, to avoud DF accesses
|
||||
auto Size = GetSrcSize(Op);
|
||||
@@ -3205,7 +3253,7 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
|
||||
{
|
||||
OrderedNode *Src = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
|
||||
OrderedNode *Dest = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
Dest = AppendSegmentOffset(Dest, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest = AppendSegmentOffset(Dest, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Src = AppendSegmentOffset(Src, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
|
||||
|
||||
Src = _LoadMemAutoTSO(GPRClass, Size, Src, Size);
|
||||
@@ -3240,7 +3288,7 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
|
||||
else {
|
||||
OrderedNode *RSI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
|
||||
OrderedNode *RDI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
RDI= AppendSegmentOffset(RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
RDI= AppendSegmentOffset(RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
RSI = AppendSegmentOffset(RSI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
|
||||
|
||||
auto Src = _LoadMemAutoTSO(GPRClass, Size, RSI, Size);
|
||||
@@ -3259,7 +3307,12 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
|
||||
LogMan::Msg::E("Can't handle adddress size");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto Size = GetSrcSize(Op);
|
||||
|
||||
bool Repeat = Op->Flags & (FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX | FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX);
|
||||
@@ -3268,7 +3321,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
OrderedNode *Dest_RSI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
|
||||
|
||||
// Only ES prefix
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
// Default DS prefix
|
||||
Dest_RSI = AppendSegmentOffset(Dest_RSI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
|
||||
|
||||
@@ -3325,7 +3378,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
OrderedNode *Dest_RSI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
|
||||
|
||||
// Only ES prefix
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
// Default DS prefix
|
||||
Dest_RSI = AppendSegmentOffset(Dest_RSI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
|
||||
|
||||
@@ -3374,8 +3427,16 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::LODSOp(OpcodeArgs) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "LODS doesn't support REPNE");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX) {
|
||||
LogMan::Msg::E("Invalid REPNE on LODS");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
|
||||
LogMan::Msg::E("Can't handle adddress size");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto Size = GetSrcSize(Op);
|
||||
bool Repeat = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX;
|
||||
@@ -3467,7 +3528,11 @@ void OpDispatchBuilder::LODSOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SCASOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
|
||||
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
|
||||
LogMan::Msg::E("Can't handle adddress size");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
|
||||
@@ -3476,7 +3541,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
|
||||
|
||||
if (!Repeat) {
|
||||
OrderedNode *Dest_RDI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
|
||||
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
|
||||
@@ -3533,7 +3598,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
|
||||
// Working loop
|
||||
{
|
||||
OrderedNode *Dest_RDI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
|
||||
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
|
||||
@@ -3633,7 +3698,11 @@ void OpDispatchBuilder::POPFOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::NEGOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(!DestIsLockedMem(Op), "Can't handle LOCK on NEG\n");
|
||||
if (DestIsLockedMem(Op)) {
|
||||
LogMan::Msg::E("Can't handle LOCK on NEG");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
auto ZeroConst = _Constant(0);
|
||||
OrderedNode *Result = _Sub(ZeroConst, Dest);
|
||||
@@ -3684,7 +3753,11 @@ void OpDispatchBuilder::DIVOp(OpcodeArgs) {
|
||||
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), URemOp);
|
||||
}
|
||||
else if (Size == 8) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
LogMan::Msg::E("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
OrderedNode *Src1 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), GPRClass);
|
||||
OrderedNode *Src2 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), GPRClass);
|
||||
|
||||
@@ -3735,7 +3808,11 @@ void OpDispatchBuilder::IDIVOp(OpcodeArgs) {
|
||||
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), URemOp);
|
||||
}
|
||||
else if (Size == 8) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
LogMan::Msg::E("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
}
|
||||
OrderedNode *Src1 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), GPRClass);
|
||||
OrderedNode *Src2 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), GPRClass);
|
||||
|
||||
@@ -4135,7 +4212,7 @@ void OpDispatchBuilder::PSHUFBOp(OpcodeArgs) {
|
||||
|
||||
template<size_t ElementSize, bool HalfSize, bool Low>
|
||||
void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(ElementSize != 0, "What. No element size?");
|
||||
LOGMAN_THROW_A(ElementSize != 0, "What. No element size?");
|
||||
auto Size = GetSrcSize(Op);
|
||||
OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
uint8_t Shuffle = Op->Src[1].TypeLiteral.Literal;
|
||||
@@ -4163,7 +4240,7 @@ void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
|
||||
|
||||
template<size_t ElementSize>
|
||||
void OpDispatchBuilder::SHUFOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(ElementSize != 0, "What. No element size?");
|
||||
LOGMAN_THROW_A(ElementSize != 0, "What. No element size?");
|
||||
auto Size = GetSrcSize(Op);
|
||||
OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
@@ -4219,7 +4296,7 @@ void OpDispatchBuilder::PINSROp(OpcodeArgs) {
|
||||
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetDstSize(Op), Op->Flags, -1);
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Index = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
uint8_t NumElements = Size / ElementSize;
|
||||
@@ -4235,13 +4312,17 @@ void OpDispatchBuilder::PExtrOp(OpcodeArgs) {
|
||||
auto Size = GetSrcSize(Op);
|
||||
|
||||
OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Index = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
uint8_t NumElements = Size / ElementSize;
|
||||
Index &= NumElements - 1;
|
||||
|
||||
auto Result = _VExtractToGPR(16, ElementSize, Src, Index);
|
||||
OrderedNode *Result = _VExtractToGPR(16, ElementSize, Src, Index);
|
||||
|
||||
if (ElementSize < 4) {
|
||||
Result = _Bfe(4, ElementSize * 8, 0, Result);
|
||||
}
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
@@ -4532,14 +4613,14 @@ void OpDispatchBuilder::CreateJumpBlocks(std::vector<FEXCore::Frontend::Decoder:
|
||||
|
||||
void OpDispatchBuilder::BeginFunction(uint64_t RIP, std::vector<FEXCore::Frontend::Decoder::DecodedBlocks> const *Blocks) {
|
||||
Entry = RIP;
|
||||
auto IRHeader = _IRHeader(InvalidNode, RIP, 0);
|
||||
auto IRHeader = _IRHeader(InvalidNode, 0);
|
||||
Current_Header = IRHeader.first;
|
||||
Current_HeaderNode = IRHeader;
|
||||
CreateJumpBlocks(Blocks);
|
||||
|
||||
auto Block = GetNewJumpBlock(RIP);
|
||||
SetCurrentCodeBlock(Block);
|
||||
IRHeader.first->Blocks = Block->Wrapped(ListData.Begin());
|
||||
IRHeader.first->Blocks = Block->Wrapped(DualListData.ListBegin());
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::Finalize() {
|
||||
@@ -4547,8 +4628,8 @@ void OpDispatchBuilder::Finalize() {
|
||||
|
||||
// Node 0 is invalid node
|
||||
OrderedNode *RealNode = reinterpret_cast<OrderedNode*>(GetNode(1));
|
||||
FEXCore::IR::IROp_Header *IROp = RealNode->Op(Data.Begin());
|
||||
LogMan::Throw::A(IROp->Op == OP_IRHEADER, "First op in function must be our header");
|
||||
FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin());
|
||||
LOGMAN_THROW_A(IROp->Op == OP_IRHEADER, "First op in function must be our header");
|
||||
|
||||
// Let's walk the jump blocks and see if we have handled every block target
|
||||
for (auto &Handler : JumpTargets) {
|
||||
@@ -4556,7 +4637,7 @@ void OpDispatchBuilder::Finalize() {
|
||||
|
||||
// We haven't emitted. Dump out to the dispatcher
|
||||
SetCurrentCodeBlock(Handler.second.BlockEntry);
|
||||
_ExitFunction(_Constant(GPRSize * 8, Handler.first));
|
||||
_ExitFunction(_EntrypointOffset(Handler.first - Entry, GPRSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4574,7 +4655,7 @@ uint8_t OpDispatchBuilder::GetDstSize(FEXCore::X86Tables::DecodedOp Op) {
|
||||
|
||||
uint32_t DstSizeFlag = FEXCore::X86Tables::DecodeFlags::GetSizeDstFlags(Op->Flags);
|
||||
uint8_t Size = Sizes[DstSizeFlag];
|
||||
LogMan::Throw::A(Size != 0, "Invalid destination size for op");
|
||||
LOGMAN_THROW_A(Size != 0, "Invalid destination size for op");
|
||||
return Size;
|
||||
}
|
||||
|
||||
@@ -4592,7 +4673,7 @@ uint8_t OpDispatchBuilder::GetSrcSize(FEXCore::X86Tables::DecodedOp Op) {
|
||||
|
||||
uint32_t SrcSizeFlag = FEXCore::X86Tables::DecodeFlags::GetSizeSrcFlags(Op->Flags);
|
||||
uint8_t Size = Sizes[SrcSizeFlag];
|
||||
LogMan::Throw::A(Size != 0, "Invalid destination size for op");
|
||||
LOGMAN_THROW_A(Size != 0, "Invalid destination size for op");
|
||||
return Size;
|
||||
}
|
||||
|
||||
@@ -4649,7 +4730,7 @@ OrderedNode *OpDispatchBuilder::AppendSegmentOffset(OrderedNode *Value, uint32_t
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp const& Op, FEXCore::X86Tables::DecodedOperand const& Operand, uint8_t OpSize, uint32_t Flags, int8_t Align, bool LoadData, bool ForceLoad) {
|
||||
LogMan::Throw::A(Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
|
||||
LOGMAN_THROW_A(Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
|
||||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL ||
|
||||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_DIRECT ||
|
||||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_INDIRECT ||
|
||||
@@ -4759,7 +4840,7 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClass
|
||||
LoadableType = true;
|
||||
}
|
||||
else {
|
||||
LogMan::Msg::A("Unknown Src Type: %d\n", Operand.TypeNone.Type);
|
||||
LOGMAN_MSG_A("Unknown Src Type: %d\n", Operand.TypeNone.Type);
|
||||
}
|
||||
|
||||
if ((LoadableType && LoadData) || ForceLoad) {
|
||||
@@ -4777,7 +4858,7 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClass
|
||||
|
||||
OrderedNode *OpDispatchBuilder::GetDynamicPC(FEXCore::X86Tables::DecodedOp const& Op, int64_t Offset) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
return _EntrypointOffset(Op->PC + Op->InstSize + Offset - Current_Header->Entry, GPRSize);
|
||||
return _EntrypointOffset(Op->PC + Op->InstSize + Offset - Entry, GPRSize);
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::LoadSource(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp const& Op, FEXCore::X86Tables::DecodedOperand const& Operand, uint32_t Flags, int8_t Align, bool LoadData, bool ForceLoad) {
|
||||
@@ -4786,7 +4867,7 @@ OrderedNode *OpDispatchBuilder::LoadSource(FEXCore::IR::RegisterClassType Class,
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, uint8_t OpSize, int8_t Align) {
|
||||
LogMan::Throw::A((Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
|
||||
LOGMAN_THROW_A((Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
|
||||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL ||
|
||||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_DIRECT ||
|
||||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_INDIRECT ||
|
||||
@@ -4819,11 +4900,11 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
// For all other sizes, the upper bits are guaranteed to already be zero
|
||||
OrderedNode *Value = GetOpSize(Src) == 8 ? _Bfe(4, 32, 0, Src) : Src;
|
||||
|
||||
LogMan::Throw::A(!Operand.TypeGPR.HighBits, "Can't handle 32bit store to high 8bit register");
|
||||
LOGMAN_THROW_A(!Operand.TypeGPR.HighBits, "Can't handle 32bit store to high 8bit register");
|
||||
_StoreContext(Class, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[Operand.TypeGPR.GPR]), Value);
|
||||
}
|
||||
else {
|
||||
LogMan::Throw::A(!(GPRSize == 4 && OpSize > 4), "Oops had a %d GPR load", OpSize);
|
||||
LOGMAN_THROW_A(!(GPRSize == 4 && OpSize > 4), "Oops had a %d GPR load", OpSize);
|
||||
_StoreContext(Class, std::min(GPRSize, OpSize), offsetof(FEXCore::Core::CPUState, gregs[Operand.TypeGPR.GPR]) + (Operand.TypeGPR.HighBits ? 1 : 0), Src);
|
||||
}
|
||||
}
|
||||
@@ -5067,7 +5148,7 @@ void OpDispatchBuilder::GenerateFlags_ADC(FEXCore::X86Tables::DecodedOp Op, Orde
|
||||
case 64:
|
||||
AndOp1 = _Bfe(1, 63, AndOp1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown BFESize: %d", Size); break;
|
||||
default: LOGMAN_MSG_A("Unknown BFESize: %d", Size); break;
|
||||
}
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_OF_LOC>(AndOp1);
|
||||
}
|
||||
@@ -5135,7 +5216,7 @@ void OpDispatchBuilder::GenerateFlags_SBB(FEXCore::X86Tables::DecodedOp Op, Orde
|
||||
case 8:
|
||||
AndOp1 = _Bfe(1, 63, AndOp1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown BFESize: %d", GetSrcSize(Op)); break;
|
||||
default: LOGMAN_MSG_A("Unknown BFESize: %d", GetSrcSize(Op)); break;
|
||||
}
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_OF_LOC>(AndOp1);
|
||||
}
|
||||
@@ -5258,7 +5339,7 @@ void OpDispatchBuilder::GenerateFlags_ADD(FEXCore::X86Tables::DecodedOp Op, Orde
|
||||
case 8:
|
||||
AndOp1 = _Bfe(1, 63, AndOp1);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown BFESize: %d", GetSrcSize(Op)); break;
|
||||
default: LOGMAN_MSG_A("Unknown BFESize: %d", GetSrcSize(Op)); break;
|
||||
}
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_OF_LOC>(AndOp1);
|
||||
}
|
||||
@@ -5815,7 +5896,7 @@ void OpDispatchBuilder::ALUOp(OpcodeArgs) {
|
||||
break;
|
||||
default:
|
||||
IROp = FEXCore::IR::IROps::OP_LAST;
|
||||
LogMan::Msg::A("Unknown ALU Op: 0x%x", Op->OP);
|
||||
LOGMAN_MSG_A("Unknown ALU Op: 0x%x", Op->OP);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5857,7 +5938,7 @@ void OpDispatchBuilder::ALUOp(OpcodeArgs) {
|
||||
Result = _Xor(Dest, Src);
|
||||
break;
|
||||
}
|
||||
default: LogMan::Msg::A("Unknown Atomic IR Op: %d", IROp); break;
|
||||
default: LOGMAN_MSG_A("Unknown Atomic IR Op: %d", IROp); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -5971,6 +6052,9 @@ void OpDispatchBuilder::PSRLDOp(OpcodeArgs) {
|
||||
OrderedNode *Result{};
|
||||
|
||||
if (Scalar) {
|
||||
// Incoming element size for the shift source is always 8
|
||||
auto MaxShift = _VectorImm(ElementSize * 8, 8, 8);
|
||||
Src = _VUMin(8, 8, MaxShift, Src);
|
||||
Result = _VUShrS(Size, ElementSize, Dest, Src);
|
||||
}
|
||||
else {
|
||||
@@ -5984,7 +6068,7 @@ template<size_t ElementSize>
|
||||
void OpDispatchBuilder::PSRLI(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t ShiftConstant = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
auto Size = GetSrcSize(Op);
|
||||
@@ -5997,7 +6081,7 @@ template<size_t ElementSize>
|
||||
void OpDispatchBuilder::PSLLI(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t ShiftConstant = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
auto Size = GetSrcSize(Op);
|
||||
@@ -6016,6 +6100,9 @@ void OpDispatchBuilder::PSLL(OpcodeArgs) {
|
||||
OrderedNode *Result{};
|
||||
|
||||
if (Scalar) {
|
||||
// Incoming element size for the shift source is always 8
|
||||
auto MaxShift = _VectorImm(ElementSize * 8, 8, 8);
|
||||
Src = _VUMin(8, 8, MaxShift, Src);
|
||||
Result = _VUShlS(Size, ElementSize, Dest, Src);
|
||||
}
|
||||
else {
|
||||
@@ -6035,6 +6122,9 @@ void OpDispatchBuilder::PSRAOp(OpcodeArgs) {
|
||||
OrderedNode *Result{};
|
||||
|
||||
if (Scalar) {
|
||||
// Incoming element size for the shift source is always 8
|
||||
auto MaxShift = _VectorImm(ElementSize * 8, 8, 8);
|
||||
Src = _VUMin(8, 8, MaxShift, Src);
|
||||
Result = _VSShrS(Size, ElementSize, Dest, Src);
|
||||
}
|
||||
else {
|
||||
@@ -6045,7 +6135,7 @@ void OpDispatchBuilder::PSRAOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PSRLDQ(OpcodeArgs) {
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
@@ -6057,7 +6147,7 @@ void OpDispatchBuilder::PSRLDQ(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PSLLDQ(OpcodeArgs) {
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
@@ -6070,7 +6160,7 @@ void OpDispatchBuilder::PSLLDQ(OpcodeArgs) {
|
||||
|
||||
template<size_t ElementSize>
|
||||
void OpDispatchBuilder::PSRAIOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
@@ -6412,7 +6502,7 @@ void OpDispatchBuilder::VFCMPOp(OpcodeArgs) {
|
||||
case 0x07: case 0x0F: case 0x17: case 0x1F: // Ordered
|
||||
Result = _VFCMPORD(Size, ElementSize, Src2, Src);
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown Comparison type: %d", CompType);
|
||||
default: LOGMAN_MSG_A("Unknown Comparison type: %d", CompType);
|
||||
}
|
||||
|
||||
if (Scalar) {
|
||||
@@ -7500,7 +7590,7 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) {
|
||||
Type = COMPARE_ZERO;
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::A("Unhandled FCMOV op: 0x%x", Opcode);
|
||||
LOGMAN_MSG_A("Unhandled FCMOV op: 0x%x", Opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8229,6 +8319,19 @@ void OpDispatchBuilder::FenceOp(OpcodeArgs) {
|
||||
_Fence({FenceType});
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::StoreFenceOrCLFlush(OpcodeArgs) {
|
||||
if (Op->ModRM == 0xF8) {
|
||||
// 0xF8 is SFENCE
|
||||
_Fence({FEXCore::IR::Fence_Store});
|
||||
}
|
||||
else {
|
||||
// This is a CLFlush
|
||||
OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1, false);
|
||||
DestMem = AppendSegmentOffset(DestMem, Op->Flags);
|
||||
_CacheLineClear(DestMem);
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PSADBW(OpcodeArgs) {
|
||||
// The documentation is actually incorrect in how this instruction operates
|
||||
// It strongly implies that the `abs(dest[i] - src[i])` operates in 8bit space
|
||||
@@ -8311,7 +8414,7 @@ void OpDispatchBuilder::AESDecLastOp(OpcodeArgs) {
|
||||
|
||||
void OpDispatchBuilder::AESKeyGenAssist(OpcodeArgs) {
|
||||
OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
|
||||
uint64_t RCON = Op->Src[1].TypeLiteral.Literal;
|
||||
|
||||
auto Res = _VAESKeyGenAssist(Src, RCON);
|
||||
@@ -8928,7 +9031,7 @@ constexpr uint16_t PF_F2 = 3;
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 3), 1, &OpDispatchBuilder::STMXCSR},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 5), 1, &OpDispatchBuilder::FenceOp<FEXCore::IR::Fence_Load.Val>}, //LFENCE
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 6), 1, &OpDispatchBuilder::FenceOp<FEXCore::IR::Fence_LoadStore.Val>}, //MFENCE
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 7), 1, &OpDispatchBuilder::FenceOp<FEXCore::IR::Fence_Store.Val>}, //SFENCE
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 7), 1, &OpDispatchBuilder::StoreFenceOrCLFlush}, //SFENCE
|
||||
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_F3, 0), 1, &OpDispatchBuilder::ReadSegmentReg<OpDispatchBuilder::Segment_FS>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_F3, 1), 1, &OpDispatchBuilder::ReadSegmentReg<OpDispatchBuilder::Segment_GS>},
|
||||
@@ -9304,7 +9407,7 @@ constexpr uint16_t PF_F2 = 3;
|
||||
auto OpNum = std::get<0>(Op);
|
||||
auto Dispatcher = std::get<2>(Op);
|
||||
for (uint8_t i = 0; i < std::get<1>(Op); ++i) {
|
||||
LogMan::Throw::A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
|
||||
LOGMAN_THROW_A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
|
||||
FinalTable[OpNum + i].OpcodeDispatcher = Dispatcher;
|
||||
if (Dispatcher)
|
||||
++NumInsts;
|
||||
@@ -9318,7 +9421,7 @@ constexpr uint16_t PF_F2 = 3;
|
||||
OpNum = OpNum & 0x7FF;
|
||||
auto Dispatcher = std::get<2>(Op);
|
||||
for (uint8_t i = 0; i < std::get<1>(Op); ++i) {
|
||||
LogMan::Throw::A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
|
||||
LOGMAN_THROW_A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
|
||||
FinalTable[OpNum + i].OpcodeDispatcher = Dispatcher;
|
||||
|
||||
// Flag to indicate if we need to repeat this op in {0x40, 0x80} ranges
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
|
||||
OrderedNode* GetNewJumpBlock(uint64_t RIP) {
|
||||
auto it = JumpTargets.find(RIP);
|
||||
LogMan::Throw::A(it != JumpTargets.end(), "Couldn't find block generated for 0x%lx", RIP);
|
||||
LOGMAN_THROW_A(it != JumpTargets.end(), "Couldn't find block generated for 0x%lx", RIP);
|
||||
return it->second.BlockEntry;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
it->second.HaveEmitted = true;
|
||||
|
||||
if (CurrentCodeBlock->Wrapped(ListData.Begin()).ID() == it->second.BlockEntry->Wrapped(ListData.Begin()).ID()) return;
|
||||
if (CurrentCodeBlock->Wrapped(DualListData.ListBegin()).ID() == it->second.BlockEntry->Wrapped(DualListData.ListBegin()).ID()) return;
|
||||
|
||||
// We have hit a RIP that is a jump target
|
||||
// Thus we need to end up in a new block
|
||||
@@ -81,14 +81,14 @@ public:
|
||||
// rdi, 0x8
|
||||
// cmp qword [rdi-8], 0
|
||||
// jne .label
|
||||
if (!BlockSetRIP) {
|
||||
if (LastOp && !BlockSetRIP) {
|
||||
auto it = JumpTargets.find(NextRIP);
|
||||
if (it == JumpTargets.end() && LastOp) {
|
||||
if (it == JumpTargets.end()) {
|
||||
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
// If we don't have a jump target to a new block then we have to leave
|
||||
// Set the RIP to the next instruction and leave
|
||||
auto RelocatedNextRIP = _EntrypointOffset(NextRIP - Current_Header->Entry, GPRSize);
|
||||
auto RelocatedNextRIP = _EntrypointOffset(NextRIP - Entry, GPRSize);
|
||||
_ExitFunction(RelocatedNextRIP);
|
||||
}
|
||||
else if (it != JumpTargets.end()) {
|
||||
@@ -104,6 +104,7 @@ public:
|
||||
OpDispatchBuilder(FEXCore::Context::Context *ctx);
|
||||
|
||||
void ResetWorkingList();
|
||||
void ResetDecodeFailure() { DecodeFailure = false; }
|
||||
bool HadDecodeFailure() { return DecodeFailure; }
|
||||
|
||||
void BeginFunction(uint64_t RIP, std::vector<FEXCore::Frontend::Decoder::DecodedBlocks> const *Blocks);
|
||||
@@ -458,6 +459,8 @@ public:
|
||||
template<uint8_t FenceType>
|
||||
void FenceOp(OpcodeArgs);
|
||||
|
||||
void StoreFenceOrCLFlush(OpcodeArgs);
|
||||
|
||||
void PSADBW(OpcodeArgs);
|
||||
|
||||
void AESImcOp(OpcodeArgs);
|
||||
|
||||
+5
-4
@@ -6,6 +6,7 @@ $end_info$
|
||||
*/
|
||||
|
||||
#include "Interface/Core/X86HelperGen.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
@@ -31,7 +32,7 @@ X86GeneratedCode::X86GeneratedCode() {
|
||||
}
|
||||
|
||||
X86GeneratedCode::~X86GeneratedCode() {
|
||||
munmap(CodePtr, CODE_SIZE);
|
||||
FEXCore::Allocator::munmap(CodePtr, CODE_SIZE);
|
||||
}
|
||||
|
||||
void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) {
|
||||
@@ -39,7 +40,7 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) {
|
||||
|
||||
if (Is64BitMode()) {
|
||||
// 64bit mode can have its sigret handler anywhere
|
||||
return mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
return FEXCore::Allocator::mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
// First 64bit page
|
||||
@@ -49,14 +50,14 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) {
|
||||
// We need to have the sigret handler in the lower 32bits of memory space
|
||||
// Scan top down and try to allocate a location
|
||||
for (size_t Location = 0xFFFF'E000; Location != 0x0; Location -= 0x1000) {
|
||||
void *Ptr = mmap(reinterpret_cast<void*>(Location), Size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
void *Ptr = FEXCore::Allocator::mmap(reinterpret_cast<void*>(Location), Size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (Ptr != MAP_FAILED &&
|
||||
reinterpret_cast<uintptr_t>(Ptr) >= LOCATION_MAX) {
|
||||
// Failed to map in the lower 32bits
|
||||
// Try again
|
||||
// Can happen in the case that host kernel ignores MAP_FIXED_NOREPLACE
|
||||
munmap(Ptr, Size);
|
||||
FEXCore::Allocator::munmap(Ptr, Size);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ static inline void GenerateTable(X86InstInfo *FinalTable, U8U8InfoStruct const *
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
FinalTable[OpNum + i] = Info;
|
||||
#ifndef NDEBUG
|
||||
++Total;
|
||||
@@ -50,7 +50,7 @@ static inline void GenerateTable(X86InstInfo *FinalTable, U16U8InfoStruct const
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
FinalTable[OpNum + i] = Info;
|
||||
#ifndef NDEBUG
|
||||
++Total;
|
||||
@@ -67,7 +67,7 @@ static inline void GenerateTableWithCopy(X86InstInfo *FinalTable, U8U8InfoStruct
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
if (Info.Type == TYPE_COPY_OTHER) {
|
||||
FinalTable[OpNum + i] = OtherLocal[OpNum + i];
|
||||
}
|
||||
@@ -89,7 +89,7 @@ static inline void GenerateX87Table(X86InstInfo *FinalTable, U16U8InfoStruct con
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
|
||||
if ((OpNum & 0b11'000'000) == 0b11'000'000) {
|
||||
// If the mod field is 0b11 then it is a regular op
|
||||
FinalTable[OpNum + i] = Info;
|
||||
@@ -97,7 +97,7 @@ static inline void GenerateX87Table(X86InstInfo *FinalTable, U16U8InfoStruct con
|
||||
else {
|
||||
// If the mod field is !0b11 then this instruction is duplicated through the whole mod [0b00, 0b10] range
|
||||
// and the modrm.rm space because that is used part of the instruction encoding
|
||||
LogMan::Throw::A((OpNum & 0b11'000'000) == 0, "Only support mod field of zero in this path");
|
||||
LOGMAN_THROW_A((OpNum & 0b11'000'000) == 0, "Only support mod field of zero in this path");
|
||||
for (uint16_t mod = 0b00'000'000; mod < 0b11'000'000; mod += 0b01'000'000) {
|
||||
for (uint16_t rm = 0b000; rm < 0b1'000; ++rm) {
|
||||
FinalTable[(OpNum | mod | rm) + i] = Info;
|
||||
|
||||
+11
-2
@@ -79,7 +79,6 @@
|
||||
"Blocks"
|
||||
],
|
||||
"Args": [
|
||||
"uint64_t", "Entry",
|
||||
"uint32_t", "BlockCount"
|
||||
]
|
||||
},
|
||||
@@ -793,6 +792,17 @@
|
||||
]
|
||||
},
|
||||
|
||||
"CacheLineClear": {
|
||||
"Desc": ["Does a 64 byte cacheline clear at the address specified"
|
||||
],
|
||||
"HasSideEffects": true,
|
||||
"OpClass": "Memory",
|
||||
"SSAArgs": "1",
|
||||
"SSANames": [
|
||||
"Addr"
|
||||
]
|
||||
},
|
||||
|
||||
"Add": {
|
||||
"Desc": [ "Integer Add",
|
||||
"Will truncate to 64 or 32bits"
|
||||
@@ -1563,7 +1573,6 @@
|
||||
"Depending on backend, may only support GPR printing"
|
||||
],
|
||||
"OpClass": "Misc",
|
||||
"DestSize": "GetOpSize(ssa0)",
|
||||
"SSAArgs": "1",
|
||||
"SSANames": [
|
||||
"Value"
|
||||
|
||||
@@ -167,7 +167,6 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationDa
|
||||
++CurrentIndent;
|
||||
AddIndent();
|
||||
*out << "(%ssa0) " << "IRHeader ";
|
||||
*out << "#0x" << std::hex << HeaderOp->Entry << ", ";
|
||||
*out << "%ssa" << HeaderOp->Blocks.ID() << ", ";
|
||||
*out << "#" << std::dec << HeaderOp->BlockCount << std::endl;
|
||||
|
||||
|
||||
+16
-17
@@ -9,18 +9,17 @@ $end_info$
|
||||
|
||||
namespace FEXCore::IR {
|
||||
void IREmitter::ResetWorkingList() {
|
||||
Data.Reset();
|
||||
ListData.Reset();
|
||||
DualListData.Reset();
|
||||
CodeBlocks.clear();
|
||||
CurrentWriteCursor = nullptr;
|
||||
// This is necessary since we do "null" pointer checks
|
||||
InvalidNode = reinterpret_cast<OrderedNode*>(ListData.Allocate(sizeof(OrderedNode)));
|
||||
InvalidNode = reinterpret_cast<OrderedNode*>(DualListData.ListAllocate(sizeof(OrderedNode)));
|
||||
memset(InvalidNode, 0, sizeof(OrderedNode));
|
||||
CurrentCodeBlock = nullptr;
|
||||
}
|
||||
|
||||
void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End) {
|
||||
uintptr_t ListBegin = ListData.Begin();
|
||||
uintptr_t ListBegin = DualListData.ListBegin();
|
||||
auto NodeId = Node->Wrapped(ListBegin).ID();
|
||||
|
||||
while (After != End) {
|
||||
@@ -45,8 +44,8 @@ void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode,
|
||||
}
|
||||
|
||||
void IREmitter::ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode *NewArg) {
|
||||
uintptr_t ListBegin = ListData.Begin();
|
||||
uintptr_t DataBegin = Data.Begin();
|
||||
uintptr_t ListBegin = DualListData.ListBegin();
|
||||
uintptr_t DataBegin = DualListData.DataBegin();
|
||||
|
||||
FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin);
|
||||
OrderedNodeWrapper OldArgWrapper = IROp->Args[Arg];
|
||||
@@ -57,8 +56,8 @@ void IREmitter::ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode
|
||||
}
|
||||
|
||||
void IREmitter::RemoveArgUses(OrderedNode *Node) {
|
||||
uintptr_t ListBegin = ListData.Begin();
|
||||
uintptr_t DataBegin = Data.Begin();
|
||||
uintptr_t ListBegin = DualListData.ListBegin();
|
||||
uintptr_t DataBegin = DualListData.DataBegin();
|
||||
|
||||
FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin);
|
||||
|
||||
@@ -72,7 +71,7 @@ void IREmitter::RemoveArgUses(OrderedNode *Node) {
|
||||
void IREmitter::Remove(OrderedNode *Node) {
|
||||
RemoveArgUses(Node);
|
||||
|
||||
Node->Unlink(ListData.Begin());
|
||||
Node->Unlink(DualListData.ListBegin());
|
||||
}
|
||||
|
||||
IREmitter::IRPair<IROp_CodeBlock> IREmitter::CreateNewCodeBlockAfter(OrderedNode* insertAfter) {
|
||||
@@ -83,14 +82,14 @@ IREmitter::IRPair<IROp_CodeBlock> IREmitter::CreateNewCodeBlockAfter(OrderedNode
|
||||
if (insertAfter) {
|
||||
LinkCodeBlocks(insertAfter, CodeNode);
|
||||
} else {
|
||||
LogMan::Throw::A(CurrentCodeBlock != nullptr, "CurrentCodeBlock must not be null here");
|
||||
|
||||
LOGMAN_THROW_A(CurrentCodeBlock != nullptr, "CurrentCodeBlock must not be null here");
|
||||
|
||||
// Find last block
|
||||
auto LastBlock = CurrentCodeBlock;
|
||||
|
||||
while (LastBlock->Header.Next.GetNode(ListData.Begin()) != InvalidNode)
|
||||
LastBlock = LastBlock->Header.Next.GetNode(ListData.Begin());
|
||||
|
||||
while (LastBlock->Header.Next.GetNode(DualListData.ListBegin()) != InvalidNode)
|
||||
LastBlock = LastBlock->Header.Next.GetNode(DualListData.ListBegin());
|
||||
|
||||
// Append it after the last block
|
||||
LinkCodeBlocks(LastBlock, CodeNode);
|
||||
}
|
||||
@@ -102,12 +101,12 @@ IREmitter::IRPair<IROp_CodeBlock> IREmitter::CreateNewCodeBlockAfter(OrderedNode
|
||||
|
||||
void IREmitter::SetCurrentCodeBlock(OrderedNode *Node) {
|
||||
CurrentCodeBlock = Node;
|
||||
LogMan::Throw::A(Node->Op(Data.Begin())->Op == OP_CODEBLOCK, "Node wasn't codeblock. It was '%s'", std::string(IR::GetName(Node->Op(Data.Begin())->Op)).c_str());
|
||||
SetWriteCursor(Node->Op(Data.Begin())->CW<IROp_CodeBlock>()->Begin.GetNode(ListData.Begin()));
|
||||
LOGMAN_THROW_A(Node->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Node wasn't codeblock. It was '%s'", std::string(IR::GetName(Node->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
SetWriteCursor(Node->Op(DualListData.DataBegin())->CW<IROp_CodeBlock>()->Begin.GetNode(DualListData.ListBegin()));
|
||||
}
|
||||
|
||||
void IREmitter::ReplaceWithConstant(OrderedNode *Node, uint64_t Value) {
|
||||
auto Header = Node->Op(Data.Begin());
|
||||
auto Header = Node->Op(DualListData.DataBegin());
|
||||
|
||||
if (IRSizes[Header->Op] >= sizeof(IROp_Constant)) {
|
||||
// Unlink any arguments the node currently has
|
||||
|
||||
+7
-9
@@ -497,13 +497,11 @@ class IRParser: public FEXCore::IR::IREmitter {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Entry = DecodeValue<uint64_t>(Def.Args[0]);
|
||||
auto CodeBlockCount = DecodeValue<uint64_t>(Def.Args[2]);
|
||||
auto CodeBlockCount = DecodeValue<uint64_t>(Def.Args[1]);
|
||||
|
||||
if (!CheckPrintError(Def, Entry.first)) return false;
|
||||
if (!CheckPrintError(Def, CodeBlockCount.first)) return false;
|
||||
|
||||
IRHeader = _IRHeader(InvalidNode, Entry.second, CodeBlockCount.second);
|
||||
IRHeader = _IRHeader(InvalidNode, CodeBlockCount.second);
|
||||
}
|
||||
|
||||
SetWriteCursor(nullptr); // isolate the header from everything following
|
||||
@@ -522,7 +520,7 @@ class IRParser: public FEXCore::IR::IREmitter {
|
||||
if (i == 1) {
|
||||
// First code block is the entry block
|
||||
// Link the header to the first block
|
||||
IRHeader.first->Blocks = CodeBlock.Node->Wrapped(ListData.Begin());
|
||||
IRHeader.first->Blocks = CodeBlock.Node->Wrapped(DualListData.ListBegin());
|
||||
}
|
||||
CodeBlocks.emplace_back(CodeBlock.Node);
|
||||
}
|
||||
@@ -555,7 +553,7 @@ class IRParser: public FEXCore::IR::IREmitter {
|
||||
}
|
||||
|
||||
CurrentBlock = Def.Node;
|
||||
CurrentBlockOp = CurrentBlock->Op(Data.Begin())->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
CurrentBlockOp = CurrentBlock->Op(DualListData.DataBegin())->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -573,7 +571,7 @@ class IRParser: public FEXCore::IR::IREmitter {
|
||||
if (!CheckPrintError(Def, Adjust.first)) return false;
|
||||
|
||||
Def.Node = _BeginBlock(Adjust.second);
|
||||
CurrentBlockOp->Begin = Def.Node->Wrapped(ListData.Begin());
|
||||
CurrentBlockOp->Begin = Def.Node->Wrapped(DualListData.ListBegin());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -590,7 +588,7 @@ class IRParser: public FEXCore::IR::IREmitter {
|
||||
if (!CheckPrintError(Def, Adjust.first)) return false;
|
||||
|
||||
Def.Node = _EndBlock(Adjust.second);
|
||||
CurrentBlockOp->Last = Def.Node->Wrapped(ListData.Begin());
|
||||
CurrentBlockOp->Last = Def.Node->Wrapped(DualListData.ListBegin());
|
||||
|
||||
CurrentBlock = nullptr;
|
||||
CurrentBlockOp = nullptr;
|
||||
@@ -617,7 +615,7 @@ class IRParser: public FEXCore::IR::IREmitter {
|
||||
}
|
||||
|
||||
if (Def.HasDefinition) {
|
||||
auto IROp = Def.Node->Op(Data.Begin());
|
||||
auto IROp = Def.Node->Op(DualListData.DataBegin());
|
||||
if (Def.Size.Elements()) {
|
||||
IROp->Size = Def.Size.Bytes() * Def.Size.Elements();
|
||||
IROp->ElementSize = Def.Size.Bytes();
|
||||
|
||||
@@ -19,6 +19,13 @@ void PassManager::AddDefaultPasses(bool InlineConstants, bool StaticRegisterAllo
|
||||
|
||||
if (!DisablePasses()) {
|
||||
InsertPass(CreateContextLoadStoreElimination());
|
||||
|
||||
if (Is64BitMode()) {
|
||||
// This needs to run after RCLSE
|
||||
// This only matters for 64-bit code since these instructions don't exist in 32-bit
|
||||
InsertPass(CreateLongDivideEliminationPass());
|
||||
}
|
||||
|
||||
InsertPass(CreateDeadStoreElimination());
|
||||
InsertPass(CreatePassDeadCodeElimination());
|
||||
InsertPass(CreateConstProp(InlineConstants));
|
||||
|
||||
@@ -6,6 +6,7 @@ $end_info$
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/IR/IntrusiveIRList.h>
|
||||
#include <FEXCore/IR/IREmitter.h>
|
||||
|
||||
@@ -83,6 +84,8 @@ private:
|
||||
ValidationPasses.emplace_back(Pass);
|
||||
}
|
||||
#endif
|
||||
|
||||
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ FEXCore::IR::Pass* CreatePassDeadCodeElimination();
|
||||
FEXCore::IR::Pass* CreateIRCompaction();
|
||||
FEXCore::IR::RegisterAllocationPass* CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA);
|
||||
FEXCore::IR::Pass* CreateStaticRegisterAllocationPass();
|
||||
FEXCore::IR::Pass* CreateLongDivideEliminationPass();
|
||||
|
||||
namespace Validation {
|
||||
FEXCore::IR::Pass* CreateIRValidation();
|
||||
|
||||
@@ -260,7 +260,7 @@ bool ConstProp::Run(IREmitter *IREmit) {
|
||||
auto ghf = IROp->CW<IR::IROp_GetHostFlag>();
|
||||
|
||||
auto fcmp = IREmit->GetOpHeader(ghf->GPR)->CW<IR::IROp_FCmp>();
|
||||
LogMan::Throw::A(fcmp->Header.Op == OP_FCMP || fcmp->Header.Op == OP_F80CMP, "Unexpected OP_GETHOSTFLAG source");
|
||||
LOGMAN_THROW_A(fcmp->Header.Op == OP_FCMP || fcmp->Header.Op == OP_F80CMP, "Unexpected OP_GETHOSTFLAG source");
|
||||
if(fcmp->Header.Op == OP_FCMP) {
|
||||
fcmp->Flags |= 1 << ghf->Flag;
|
||||
}
|
||||
@@ -463,7 +463,7 @@ bool ConstProp::Run(IREmitter *IREmit) {
|
||||
|
||||
if (IREmit->IsValueConstant(IROp->Args[0], &Constant1) &&
|
||||
IREmit->IsValueConstant(IROp->Args[1], &Constant2)) {
|
||||
LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
|
||||
LOGMAN_MSG_A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -479,7 +479,7 @@ bool ConstProp::Run(IREmitter *IREmit) {
|
||||
uint64_t Constant1;
|
||||
|
||||
if (IREmit->IsValueConstant(IROp->Args[0], &Constant1)) {
|
||||
LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
|
||||
LOGMAN_MSG_A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+8
-8
@@ -211,18 +211,18 @@ namespace {
|
||||
size_t ClassifiedStructSize{};
|
||||
ContextClassificationInfo->Lookup.reserve(sizeof(FEXCore::Core::CPUState));
|
||||
for (auto &it : *ContextClassification) {
|
||||
LogMan::Throw::A(it.Class.Offset == ContextClassificationInfo->Lookup.size(), "Offset missmatch %d %d", it.Class.Offset == ContextClassificationInfo->Lookup.size());
|
||||
LOGMAN_THROW_A(it.Class.Offset == ContextClassificationInfo->Lookup.size(), "Offset missmatch %d %d", it.Class.Offset == ContextClassificationInfo->Lookup.size());
|
||||
for (int i = 0; i < it.Class.Size; i++) {
|
||||
ContextClassificationInfo->Lookup.push_back(&it);
|
||||
}
|
||||
ClassifiedStructSize += it.Class.Size;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(ClassifiedStructSize == sizeof(FEXCore::Core::CPUState),
|
||||
LOGMAN_THROW_A(ClassifiedStructSize == sizeof(FEXCore::Core::CPUState),
|
||||
"Classified CPUStruct size doesn't match real CPUState struct size! %ld != %ld",
|
||||
ClassifiedStructSize, sizeof(FEXCore::Core::CPUState));
|
||||
|
||||
LogMan::Throw::A(ContextClassificationInfo->Lookup.size() == sizeof(FEXCore::Core::CPUState),
|
||||
LOGMAN_THROW_A(ContextClassificationInfo->Lookup.size() == sizeof(FEXCore::Core::CPUState),
|
||||
"Classified CPUStruct size doesn't match real CPUState struct size! %ld != %ld",
|
||||
ContextClassificationInfo->Lookup.size(), sizeof(FEXCore::Core::CPUState));
|
||||
}
|
||||
@@ -306,15 +306,15 @@ ContextMemberInfo *RCLSE::FindMemberInfo(ContextInfo *ContextClassificationInfo,
|
||||
}
|
||||
|
||||
ContextMemberInfo *RCLSE::RecordAccess(ContextMemberInfo *Info, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, LastAccessType AccessType, FEXCore::IR::OrderedNode *Node, FEXCore::IR::OrderedNode *StoreNode) {
|
||||
LogMan::Throw::A((Offset + Size) <= (Info->Class.Offset + Info->Class.Size), "Access to context item went over member size");
|
||||
LogMan::Throw::A(Info->Accessed != ACCESS_INVALID, "Tried to access invalid member");
|
||||
LOGMAN_THROW_A((Offset + Size) <= (Info->Class.Offset + Info->Class.Size), "Access to context item went over member size");
|
||||
LOGMAN_THROW_A(Info->Accessed != ACCESS_INVALID, "Tried to access invalid member");
|
||||
|
||||
// If we aren't fully overwriting the member then it is a partial write that we need to track
|
||||
if (Size < Info->Class.Size) {
|
||||
AccessType = AccessType == ACCESS_WRITE ? ACCESS_PARTIAL_WRITE : ACCESS_PARTIAL_READ;
|
||||
}
|
||||
if (Size > Info->Class.Size) {
|
||||
LogMan::Msg::A("Can't handle this");
|
||||
LOGMAN_MSG_A("Can't handle this");
|
||||
}
|
||||
|
||||
Info->Accessed = AccessType;
|
||||
@@ -500,7 +500,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) {
|
||||
else if (LastClass == GPRClass) {
|
||||
LastNode = IREmit->_Bfe(Info->AccessSize, TruncateSize * 8, 0, LastNode);
|
||||
} else {
|
||||
LogMan::Msg::A("Unhandled Register class");
|
||||
LOGMAN_MSG_A("Unhandled Register class");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) {
|
||||
if (LastStoreNode != nullptr)
|
||||
{
|
||||
IREmit->SetWriteCursor(CodeNode);
|
||||
RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + F, 1, ACCESS_WRITE, IREmit->_InlineConstant(0), CodeNode);
|
||||
RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + F, 1, ACCESS_WRITE, IREmit->_Constant(0), CodeNode);
|
||||
|
||||
IREmit->Remove(LastStoreNode);
|
||||
Changed = true;
|
||||
|
||||
@@ -106,7 +106,7 @@ uint64_t FPRBit(uint32_t Offset, uint32_t Size) {
|
||||
else if (Size == 4)
|
||||
return 1UL << (bitn);
|
||||
else
|
||||
LogMan::Msg::A("Unexpected FPR size %d", Size);
|
||||
LOGMAN_MSG_A("Unexpected FPR size %d", Size);
|
||||
|
||||
return 7UL << (bitn); // Return maximum on failure case
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
|
||||
|
||||
auto HeaderNode = CurrentIR.GetHeaderNode();
|
||||
auto HeaderOp = CurrentIR.GetHeader();
|
||||
LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
|
||||
LOGMAN_THROW_A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
|
||||
|
||||
// This compaction pass is something that we need to ensure correct ordering and distances between IROps
|
||||
// Later on we assume that an IROp's SSA value live range is its Node locations
|
||||
@@ -84,13 +84,13 @@ bool IRCompaction::Run(IREmitter *IREmit) {
|
||||
|
||||
// Zero is always zero(invalid)
|
||||
OldToNewRemap[0].NodeID = 0;
|
||||
auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->Entry, HeaderOp->BlockCount);
|
||||
auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->BlockCount);
|
||||
OldToNewRemap[CurrentIR.GetID(HeaderNode)].NodeID = LocalIR.GetID(LocalHeaderOp.Node);
|
||||
|
||||
{
|
||||
// Generate our codeblocks and link them together
|
||||
for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) {
|
||||
LogMan::Throw::A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
LOGMAN_THROW_A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
|
||||
auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now
|
||||
OldToNewRemap[CurrentIR.GetID(BlockNode)].NodeID = LocalIR.GetID(LocalBlockIRNode.Node);
|
||||
@@ -154,7 +154,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
|
||||
// Fixup the arguments of all the IROps
|
||||
for (auto &Block : GeneratedCodeBlocks) {
|
||||
auto BlockIROp = LocalIR.GetOp<FEXCore::IR::IROp_CodeBlock>(Block.NewNode);
|
||||
LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
LOGMAN_THROW_A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
|
||||
for (auto [LocalNode, LocalIROp] : LocalIR.GetCode(Block.NewNode)) {
|
||||
|
||||
@@ -165,7 +165,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
|
||||
for (uint8_t i = 0; i < NumArgs; ++i) {
|
||||
uint32_t OldArg = LocalIROp->Args[i].ID();
|
||||
#ifndef NDEBUG
|
||||
LogMan::Throw::A(OldToNewRemap[OldArg].NodeID != ~0U, "Tried remapping unfound node %%ssa%d", OldArg);
|
||||
LOGMAN_THROW_A(OldToNewRemap[OldArg].NodeID != ~0U, "Tried remapping unfound node %%ssa%d", OldArg);
|
||||
#endif
|
||||
LocalIROp->Args[i].NodeOffset = OldToNewRemap[OldArg].NodeID * sizeof(OrderedNode);
|
||||
}
|
||||
@@ -191,7 +191,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
|
||||
|
||||
// if (NewListSize > OldListSize ||
|
||||
// NewDataSize > OldDataSize) {
|
||||
// LogMan::Msg::A("Whoa. Compaction made the IR a different size when it shouldn't have. 0x%lx > 0x%lx or 0x%lx > 0x%lx",NewListSize, OldListSize, NewDataSize, OldDataSize);
|
||||
// LOGMAN_MSG_A("Whoa. Compaction made the IR a different size when it shouldn't have. 0x%lx > 0x%lx or 0x%lx > 0x%lx",NewListSize, OldListSize, NewDataSize, OldDataSize);
|
||||
// }
|
||||
|
||||
IREmit->CopyData(LocalBuilder);
|
||||
|
||||
@@ -55,7 +55,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
|
||||
std::vector<uint32_t> Uses(CurrentIR.GetSSACount(), 0);
|
||||
|
||||
auto HeaderOp = CurrentIR.GetHeader();
|
||||
LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
|
||||
LOGMAN_THROW_A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
|
||||
|
||||
IR::RegisterAllocationData * RAData{};
|
||||
if (Manager->HasRAPass()) {
|
||||
@@ -66,7 +66,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
|
||||
|
||||
for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) {
|
||||
auto BlockIROp = BlockHeader->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
LOGMAN_THROW_A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
|
||||
uint32_t BlockID = CurrentIR.GetID(BlockNode);
|
||||
|
||||
@@ -209,7 +209,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// LogMan::Msg::A("Unknown IR Op: %d(%s)", IROp->Op, FEXCore::IR::GetName(IROp->Op).data());
|
||||
// LOGMAN_MSG_A("Unknown IR Op: %d(%s)", IROp->Op, FEXCore::IR::GetName(IROp->Op).data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
$info$
|
||||
tags: ir|opts
|
||||
desc: Long divide elimination pass
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "Interface/IR/PassManager.h"
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
namespace FEXCore::IR {
|
||||
|
||||
class LongDivideEliminationPass final : public FEXCore::IR::Pass {
|
||||
public:
|
||||
bool Run(IREmitter *IREmit) override;
|
||||
private:
|
||||
bool IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper Arg);
|
||||
bool IsSextOp(IREmitter *IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper);
|
||||
};
|
||||
|
||||
bool LongDivideEliminationPass::IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper Arg) {
|
||||
auto IROp = IREmit->GetOpHeader(Arg);
|
||||
uint64_t Value;
|
||||
|
||||
// XOR based zero
|
||||
if (IROp->Op == OP_XOR) {
|
||||
return IROp->Args[0] == IROp->Args[1];
|
||||
}
|
||||
else if (IREmit->IsValueConstant(Arg, &Value)) {
|
||||
// Zero constant based zero op
|
||||
return Value == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LongDivideEliminationPass::IsSextOp(IREmitter *IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper) {
|
||||
// We need to check if the upper source is a sext of the lower source
|
||||
auto UpperIROp = IREmit->GetOpHeader(Upper);
|
||||
if (UpperIROp->Op == OP_SBFE) {
|
||||
auto Op = UpperIROp->C<IR::IROp_Sbfe>();
|
||||
if (Op->Width == 1 && Op->lsb == 63) {
|
||||
// CQO: OrderedNode *Upper = _Sbfe(1, Size * 8 - 1, Src);
|
||||
// If the lower is the upper in this case then it can be optimized
|
||||
return Op->Header.Args[0] == Lower;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LongDivideEliminationPass::Run(IREmitter *IREmit) {
|
||||
bool Changed = false;
|
||||
auto CurrentIR = IREmit->ViewIR();
|
||||
auto OriginalWriteCursor = IREmit->GetWriteCursor();
|
||||
|
||||
for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) {
|
||||
for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) {
|
||||
if (IROp->Size == 8) {
|
||||
if (IROp->Op == OP_LDIV ||
|
||||
IROp->Op == OP_LREM) {
|
||||
auto Op = IROp->C<IR::IROp_LDiv>();
|
||||
// Check upper Op to see if it came from a CQO
|
||||
// CQO: OrderedNode *Upper = _Sbfe(1, Size * 8 - 1, Src);
|
||||
// If it does then it we only need a 64bit SDIV
|
||||
if (IsSextOp(IREmit, Op->Lower, Op->Upper)) {
|
||||
IREmit->SetWriteCursor(CodeNode);
|
||||
OrderedNode *Lower = CurrentIR.GetNode(Op->Lower);
|
||||
OrderedNode *Divisor = CurrentIR.GetNode(Op->Divisor);
|
||||
OrderedNode *SDivOp{};
|
||||
if (IROp->Op == OP_LDIV) {
|
||||
SDivOp = IREmit->_Div(Lower, Divisor);
|
||||
}
|
||||
else {
|
||||
SDivOp = IREmit->_Rem(Lower, Divisor);
|
||||
}
|
||||
IREmit->ReplaceAllUsesWith(CodeNode, SDivOp);
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
else if (IROp->Op == OP_LUDIV ||
|
||||
IROp->Op == OP_LUREM) {
|
||||
auto Op = IROp->C<IR::IROp_LUDiv>();
|
||||
// Check upper Op to see if it came from a xor zeroing op
|
||||
// XOR: Result = _Xor(Dest, Src);
|
||||
// If it does then it we only need a 64bit UDIV
|
||||
if (IsZeroOp(IREmit, Op->Upper)) {
|
||||
IREmit->SetWriteCursor(CodeNode);
|
||||
OrderedNode *Lower = CurrentIR.GetNode(Op->Lower);
|
||||
OrderedNode *Divisor = CurrentIR.GetNode(Op->Divisor);
|
||||
OrderedNode *UDivOp{};
|
||||
if (IROp->Op == OP_LUDIV) {
|
||||
UDivOp = IREmit->_UDiv(Lower, Divisor);
|
||||
}
|
||||
else {
|
||||
UDivOp = IREmit->_URem(Lower, Divisor);
|
||||
}
|
||||
IREmit->ReplaceAllUsesWith(CodeNode, UDivOp);
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IREmit->SetWriteCursor(OriginalWriteCursor);
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
FEXCore::IR::Pass* CreateLongDivideEliminationPass() {
|
||||
return new LongDivideEliminationPass{};
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ $end_info$
|
||||
#include "Interface/IR/Passes/RegisterAllocationPass.h"
|
||||
#include "Interface/IR/Passes.h"
|
||||
#include "Interface/Core/OpcodeDispatcher.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_set>
|
||||
@@ -65,7 +66,7 @@ namespace {
|
||||
Enumerator(Item);
|
||||
|
||||
if (++i == Bucket->Size) {
|
||||
LogMan::Throw::A(Bucket->Next != nullptr, "Interference bug");
|
||||
LOGMAN_THROW_A(Bucket->Next != nullptr, "Interference bug");
|
||||
Bucket = Bucket->Next.get();
|
||||
i = 0;
|
||||
}
|
||||
@@ -86,7 +87,7 @@ namespace {
|
||||
return true;
|
||||
|
||||
if (++i == Bucket->Size) {
|
||||
LogMan::Throw::A(Bucket->Next != nullptr, "Bucket in bad state");
|
||||
LOGMAN_THROW_A(Bucket->Next != nullptr, "Bucket in bad state");
|
||||
Bucket = Bucket->Next.get();
|
||||
i = 0;
|
||||
}
|
||||
@@ -130,7 +131,7 @@ namespace {
|
||||
}
|
||||
else if (++i == Size) {
|
||||
i = 0;
|
||||
LogMan::Throw::A(that->Next != nullptr, "Bucket::Erase but element not contained");
|
||||
LOGMAN_THROW_A(that->Next != nullptr, "Bucket::Erase but element not contained");
|
||||
that = that->Next.get();
|
||||
}
|
||||
}
|
||||
@@ -262,7 +263,7 @@ namespace {
|
||||
Graph->Nodes.resize(NodeCount);
|
||||
Graph->VisitedNodePredecessors.clear();
|
||||
Graph->AllocData.reset();
|
||||
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
|
||||
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)FEXCore::Allocator::malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
|
||||
memset(&Graph->AllocData->Map[0], INVALID_REGCLASS.Raw, NodeCount);
|
||||
Graph->AllocData->MapCount = NodeCount;
|
||||
Graph->AllocData->IsShared = false; // not shared by default
|
||||
@@ -445,8 +446,8 @@ namespace FEXCore::IR {
|
||||
}
|
||||
|
||||
void ConstrainedRAPass::AllocateRegisterSet(uint32_t RegisterCount, uint32_t ClassCount) {
|
||||
LogMan::Throw::A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
|
||||
LogMan::Throw::A(ClassCount <= INVALID_CLASS, "Up to %d classes supported", INVALID_CLASS);
|
||||
LOGMAN_THROW_A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
|
||||
LOGMAN_THROW_A(ClassCount <= INVALID_CLASS, "Up to %d classes supported", INVALID_CLASS);
|
||||
|
||||
Graph = AllocateRegisterGraph(ClassCount);
|
||||
|
||||
@@ -459,7 +460,7 @@ namespace FEXCore::IR {
|
||||
}
|
||||
|
||||
void ConstrainedRAPass::AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) {
|
||||
LogMan::Throw::A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
|
||||
LOGMAN_THROW_A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
|
||||
|
||||
AllocatePhysicalRegisters(Graph, Class, RegisterCount);
|
||||
}
|
||||
@@ -486,7 +487,7 @@ namespace FEXCore::IR {
|
||||
|
||||
auto Op = IROp->C<IROp_CodeBlock>();
|
||||
|
||||
LogMan::Throw::A(Op->Header.Op == OP_CODEBLOCK, "Block not defined by codeblock?");
|
||||
LOGMAN_THROW_A(Op->Header.Op == OP_CODEBLOCK, "Block not defined by codeblock?");
|
||||
|
||||
LiveRange->Begin = std::min(LiveRange->Begin, Op->Begin.ID());
|
||||
LiveRange->End = std::max(LiveRange->End, Op->Begin.ID());
|
||||
@@ -514,7 +515,7 @@ namespace FEXCore::IR {
|
||||
|
||||
// If the destination hasn't yet been set then set it now
|
||||
if (IROp->HasDest) {
|
||||
LogMan::Throw::A(LiveRanges[Node].Begin == ~0U, "Node begin already defined?");
|
||||
LOGMAN_THROW_A(LiveRanges[Node].Begin == ~0U, "Node begin already defined?");
|
||||
LiveRanges[Node].Begin = Node;
|
||||
// Default to ending right where after it starts
|
||||
LiveRanges[Node].End = Node + 1;
|
||||
@@ -546,7 +547,7 @@ namespace FEXCore::IR {
|
||||
if (IR->GetOp<IROp_Header>(IROp->Args[i])->Op == OP_INLINEENTRYPOINTOFFSET) continue;
|
||||
if (IR->GetOp<IROp_Header>(IROp->Args[i])->Op == OP_IRHEADER) continue;
|
||||
uint32_t ArgNode = IROp->Args[i].ID();
|
||||
LogMan::Throw::A(LiveRanges[ArgNode].Begin != ~0U, "%%ssa%d used by %%ssa%d before defined?", ArgNode, Node);
|
||||
LOGMAN_THROW_A(LiveRanges[ArgNode].Begin != ~0U, "%%ssa%d used by %%ssa%d before defined?", ArgNode, Node);
|
||||
|
||||
auto ArgNodeBlockID = Graph->Nodes[ArgNode].Head.BlockID;
|
||||
if (ArgNodeBlockID == BlockNodeID) {
|
||||
@@ -600,7 +601,7 @@ namespace FEXCore::IR {
|
||||
} else if (StaticClass == FPRFixedClass) {
|
||||
return Size == 16;
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected static class %d", StaticClass);
|
||||
LOGMAN_THROW_A(false, "Unexpected static class %d", StaticClass);
|
||||
}
|
||||
return false; // Unknown
|
||||
};
|
||||
@@ -612,7 +613,7 @@ namespace FEXCore::IR {
|
||||
} else if (StaticClass == FPRFixedClass) {
|
||||
return (Size == 16 /*|| Size == 8 || Size == 4*/) && ((Offset & 15) == 0); // We need more meta info to support not-size-of-reg
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected static class %d", StaticClass);
|
||||
LOGMAN_THROW_A(false, "Unexpected static class %d", StaticClass);
|
||||
}
|
||||
return false; // Unknown
|
||||
};
|
||||
@@ -632,7 +633,7 @@ namespace FEXCore::IR {
|
||||
auto reg = (Offset - beginFpr) / 16;
|
||||
return PhysicalRegister(FPRFixedClass, reg);
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected Offset %d", Offset);
|
||||
LOGMAN_THROW_A(false, "Unexpected Offset %d", Offset);
|
||||
return INVALID_REGCLASS;
|
||||
}
|
||||
};
|
||||
@@ -656,7 +657,7 @@ namespace FEXCore::IR {
|
||||
auto reg = (Offset - beginFpr) / 16;
|
||||
return &StaticMaps[GprSize + reg];
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected offset %d", Offset);
|
||||
LOGMAN_THROW_A(false, "Unexpected offset %d", Offset);
|
||||
return (LiveRange**)nullptr;
|
||||
}
|
||||
};
|
||||
@@ -668,7 +669,7 @@ namespace FEXCore::IR {
|
||||
} else if (PhyReg.Class == FPRFixedClass.Val) {
|
||||
return &StaticMaps[GprSize + PhyReg.Reg];
|
||||
} else {
|
||||
LogMan::Throw::A(false, "Unexpected Class %d", PhyReg.Class);
|
||||
LOGMAN_THROW_A(false, "Unexpected Class %d", PhyReg.Class);
|
||||
return (LiveRange**)nullptr;
|
||||
}
|
||||
};
|
||||
@@ -807,7 +808,7 @@ namespace FEXCore::IR {
|
||||
|
||||
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
|
||||
auto BlockIROp = BlockHeader->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
LOGMAN_THROW_A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
|
||||
|
||||
BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(IR->GetID(BlockNode)).first->second;
|
||||
BlockInterferenceVector->reserve(BlockIROp->Last.ID() - BlockIROp->Begin.ID());
|
||||
@@ -910,7 +911,7 @@ namespace FEXCore::IR {
|
||||
SpanEnd.resize(NodeCount);
|
||||
for (uint32_t i = 0; i < NodeCount; ++i) {
|
||||
if (LiveRanges[i].Begin != ~0U) {
|
||||
LogMan::Throw::A(LiveRanges[i].Begin < LiveRanges[i].End , "Span must Begin before Ending");
|
||||
LOGMAN_THROW_A(LiveRanges[i].Begin < LiveRanges[i].End , "Span must Begin before Ending");
|
||||
|
||||
auto Class = GetClass(Graph->AllocData->Map[i]);
|
||||
SpanStart[LiveRanges[i].Begin].Append(INFO_MAKE(i, Class));
|
||||
@@ -938,7 +939,7 @@ namespace FEXCore::IR {
|
||||
});
|
||||
}
|
||||
|
||||
LogMan::Throw::A(Active.Items[0] == 0, "Interference bug");
|
||||
LOGMAN_THROW_A(Active.Items[0] == 0, "Interference bug");
|
||||
SpanStart.clear();
|
||||
SpanEnd.clear();
|
||||
}
|
||||
@@ -957,7 +958,7 @@ namespace FEXCore::IR {
|
||||
RegisterClass *RAClass = &Graph->Set.Classes[RegClass];
|
||||
|
||||
if (CurrentNode->Head.PhiPartner) {
|
||||
LogMan::Msg::A("Phi nodes not supported");
|
||||
LOGMAN_MSG_A("Phi nodes not supported");
|
||||
#if 0
|
||||
// In the case that we have a list of nodes that need the same register allocated we need to do something special
|
||||
// We need to gather the data from the forward linked list and make sure they all match the virtual register
|
||||
@@ -1156,7 +1157,7 @@ namespace FEXCore::IR {
|
||||
// This would ensure something will spill earlier if its previous use and next use are farther away
|
||||
auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter);
|
||||
auto InterferenceNodePrevUse = FindLastUseBefore(IREmit, InterferenceOrderedNode, InterferenceNodeOpBeginIter, NodeOpBeginIter);
|
||||
LogMan::Throw::A(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op");
|
||||
LOGMAN_THROW_A(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op");
|
||||
// If there is no use of the interference op prior to our op then it only has initial definition
|
||||
if (InterferenceNodePrevUse == IR::NodeIterator::Invalid()) InterferenceNodePrevUse = InterferenceNodeOpBeginIter;
|
||||
|
||||
@@ -1322,7 +1323,7 @@ namespace FEXCore::IR {
|
||||
LogMan::Msg::D("\tInt%d: %%ssa%d Remat: %d [%d, %d)", j++, InterferenceNode, InterferenceLiveRange->RematCost, InterferenceLiveRange->Begin, InterferenceLiveRange->End);
|
||||
});
|
||||
}
|
||||
LogMan::Throw::A(InterferenceIdToSpill != 0, "Couldn't find Node to spill");
|
||||
LOGMAN_THROW_A(InterferenceIdToSpill != 0, "Couldn't find Node to spill");
|
||||
|
||||
return InterferenceIdToSpill;
|
||||
}
|
||||
@@ -1357,7 +1358,7 @@ namespace FEXCore::IR {
|
||||
auto LastCursor = IREmit->GetWriteCursor();
|
||||
auto [CodeNode, IROp] = IR.at(SpillPointId)();
|
||||
|
||||
LogMan::Throw::A(IROp->HasDest, "Can't spill with no dest");
|
||||
LOGMAN_THROW_A(IROp->HasDest, "Can't spill with no dest");
|
||||
|
||||
uint32_t Node = IR.GetID(CodeNode);
|
||||
RegisterNode *CurrentNode = &Graph->Nodes[Node];
|
||||
@@ -1381,7 +1382,7 @@ namespace FEXCore::IR {
|
||||
// First op post Spill
|
||||
auto NextIter = IR.at(CodeNode);
|
||||
auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, NodeIterator::Invalid());
|
||||
LogMan::Throw::A(FirstUseLocation != IR::NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
|
||||
LOGMAN_THROW_A(FirstUseLocation != IR::NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
|
||||
if (FirstUseLocation != IR::NodeIterator::Invalid()) {
|
||||
--FirstUseLocation;
|
||||
auto [FirstUseOrderedNode, _] = FirstUseLocation();
|
||||
@@ -1399,10 +1400,10 @@ namespace FEXCore::IR {
|
||||
FEXCore::IR::RegisterClassType InterferenceRegClass = FEXCore::IR::RegisterClassType{Graph->AllocData->Map[InterferenceNode].Class};
|
||||
uint32_t SpillSlot = FindSpillSlot(InterferenceNode, InterferenceRegClass);
|
||||
RegisterNode *InterferenceRegisterNode = &Graph->Nodes[InterferenceNode];
|
||||
LogMan::Throw::A(SpillSlot != ~0U, "Interference Node doesn't have a spill slot!");
|
||||
//LogMan::Throw::A(InterferenceRegisterNode->Head.RegAndClass.Reg != INVALID_REG, "Interference node never assigned a register?");
|
||||
LogMan::Throw::A(InterferenceRegClass != ~0U, "Interference node never assigned a register class?");
|
||||
LogMan::Throw::A(InterferenceRegisterNode->Head.PhiPartner == nullptr, "We don't support spilling PHI nodes currently");
|
||||
LOGMAN_THROW_A(SpillSlot != ~0U, "Interference Node doesn't have a spill slot!");
|
||||
//LOGMAN_THROW_A(InterferenceRegisterNode->Head.RegAndClass.Reg != INVALID_REG, "Interference node never assigned a register?");
|
||||
LOGMAN_THROW_A(InterferenceRegClass != ~0U, "Interference node never assigned a register class?");
|
||||
LOGMAN_THROW_A(InterferenceRegisterNode->Head.PhiPartner == nullptr, "We don't support spilling PHI nodes currently");
|
||||
|
||||
// This is the op that we need to dump
|
||||
auto [InterferenceOrderedNode, InterferenceIROp] = IR.at(InterferenceNode)();
|
||||
@@ -1435,7 +1436,7 @@ namespace FEXCore::IR {
|
||||
++FirstIter;
|
||||
auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, NodeIterator::Invalid());
|
||||
|
||||
LogMan::Throw::A(FirstUseLocation != NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
|
||||
LOGMAN_THROW_A(FirstUseLocation != NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
|
||||
if (FirstUseLocation != IR::NodeIterator::Invalid()) {
|
||||
// We want to fill just before the first use
|
||||
--FirstUseLocation;
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@ bool IsStaticAllocGpr(uint32_t Offset, RegisterClassType Class) {
|
||||
|
||||
if (Offset >= begin && Offset < end) {
|
||||
auto reg = (Offset - begin) / 8;
|
||||
LogMan::Throw::A(Class == IR::GPRClass, "unexpected Class %d", Class);
|
||||
LOGMAN_THROW_A(Class == IR::GPRClass, "unexpected Class %d", Class);
|
||||
|
||||
rv = reg < 16; // 0..15 -> 16 in total
|
||||
}
|
||||
@@ -37,7 +37,7 @@ bool IsStaticAllocFpr(uint32_t Offset, RegisterClassType Class, bool AllowGpr) {
|
||||
|
||||
if (Offset >= begin && Offset < end) {
|
||||
auto reg = (Offset - begin)/16;
|
||||
LogMan::Throw::A(Class == IR::FPRClass || (AllowGpr && Class == IR::GPRClass), "unexpected Class %d, AllowGpr %d", Class, AllowGpr);
|
||||
LOGMAN_THROW_A(Class == IR::FPRClass || (AllowGpr && Class == IR::GPRClass), "unexpected Class %d, AllowGpr %d", Class, AllowGpr);
|
||||
|
||||
rv = reg < 16; // 0..15 -> 16 in total
|
||||
}
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
#include "Utils/Allocator/HostAllocator.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <sys/mman.h>
|
||||
#include <jemalloc/jemalloc.h>
|
||||
#include <memory>
|
||||
|
||||
extern "C" {
|
||||
extern void *__libc_malloc(size_t size);
|
||||
extern void *__libc_realloc(void *ptr, size_t size);
|
||||
extern void __libc_free(void *ptr);
|
||||
|
||||
typedef void* (*mmap_hook_type)(
|
||||
void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset);
|
||||
typedef int (*munmap_hook_type)(void *addr, size_t length);
|
||||
|
||||
extern mmap_hook_type __mmap_hook;
|
||||
extern munmap_hook_type __munmap_hook;
|
||||
}
|
||||
|
||||
namespace FEXCore::Allocator {
|
||||
MMAP_Hook mmap {::mmap};
|
||||
MUNMAP_Hook munmap {::munmap};
|
||||
MALLOC_Hook malloc {::__libc_malloc};
|
||||
REALLOC_Hook realloc {::__libc_realloc};
|
||||
FREE_Hook free {::__libc_free};
|
||||
|
||||
std::unique_ptr<Alloc::HostAllocator> Alloc64{};
|
||||
|
||||
void *FEX_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
|
||||
void *Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset);
|
||||
if (Result >= (void*)-4096) {
|
||||
errno = -(uint64_t)Result;
|
||||
return (void*)-1;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
int FEX_munmap(void *addr, size_t length) {
|
||||
int Result = Alloc64->Munmap(addr, length);
|
||||
|
||||
if (Result != 0) {
|
||||
errno = -Result;
|
||||
return -1;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void *FEX_malloc_hook(size_t size, const void *caller) {
|
||||
return ::je_malloc(size);
|
||||
}
|
||||
|
||||
void *FEX_realloc_hook(void *ptr, size_t size, const void *caller) {
|
||||
return ::je_realloc(ptr, size);
|
||||
}
|
||||
|
||||
void FEX_free_hook(void *ptr, const void *caller) {
|
||||
return ::je_free(ptr);
|
||||
}
|
||||
|
||||
void SetupHooks() {
|
||||
Alloc64.reset(Alloc::OSAllocator::Create64BitAllocator());
|
||||
__mmap_hook = FEX_mmap;
|
||||
__munmap_hook = FEX_munmap;
|
||||
FEXCore::Allocator::mmap = FEX_mmap;
|
||||
FEXCore::Allocator::munmap = FEX_munmap;
|
||||
FEXCore::Allocator::malloc = ::je_malloc;
|
||||
FEXCore::Allocator::realloc = ::je_realloc;
|
||||
FEXCore::Allocator::free = ::je_free;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// Override the global functions
|
||||
void *malloc(size_t size) { return FEXCore::Allocator::malloc(size); }
|
||||
void *realloc(void *ptr, size_t size) { return FEXCore::Allocator::realloc(ptr, size); }
|
||||
void free(void *ptr) { return FEXCore::Allocator::free(ptr); }
|
||||
}
|
||||
@@ -0,0 +1,715 @@
|
||||
#include "Utils/Allocator/FlexBitSet.h"
|
||||
#include "Utils/Allocator/HostAllocator.h"
|
||||
#include "Utils/Allocator/IntrusiveArenaAllocator.h"
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <malloc.h>
|
||||
#include <mutex>
|
||||
#include <stdio.h>
|
||||
#include <set>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/resource.h>
|
||||
#include <syscall.h>
|
||||
#include <vector>
|
||||
|
||||
static constexpr uint64_t PAGE_SHIFT = 12;
|
||||
static constexpr uint64_t PAGE_MASK = (1 << PAGE_SHIFT) - 1;
|
||||
|
||||
namespace Alloc::OSAllocator {
|
||||
class OSAllocator_64Bit final : public Alloc::HostAllocator {
|
||||
public:
|
||||
OSAllocator_64Bit();
|
||||
virtual ~OSAllocator_64Bit();
|
||||
void *AllocateSlab(size_t Size) override { return nullptr; }
|
||||
void DeallocateSlab(void *Ptr, size_t Size) override {}
|
||||
|
||||
void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override;
|
||||
int Munmap(void *addr, size_t length) override;
|
||||
|
||||
private:
|
||||
constexpr static uint64_t PAGE_SIZE = 4096;
|
||||
// Upper bound is the maximum virtual address space of the host processor
|
||||
uintptr_t UPPER_BOUND = (1ULL << 57);
|
||||
|
||||
// Lower bound is the starting of the range just past the lower 32bits
|
||||
constexpr static uintptr_t LOWER_BOUND = 0x1'0000'0000ULL;
|
||||
|
||||
uintptr_t UPPER_BOUND_PAGE = UPPER_BOUND / PAGE_SIZE;
|
||||
constexpr static uintptr_t LOWER_BOUND_PAGE = LOWER_BOUND / PAGE_SIZE;
|
||||
|
||||
struct ReservedVMARegion {
|
||||
uintptr_t Base;
|
||||
// Could be number of pages if we want to pack this in to 12 bytes
|
||||
uint64_t RegionSize;
|
||||
};
|
||||
|
||||
bool MergeReservedRegionIfPossible(ReservedVMARegion *Region, uintptr_t NextPtr, uint64_t NextSize) {
|
||||
constexpr uint64_t MaxReservedRegionSize = 64ULL * 1024 * 1024 * 1024; // 64GB
|
||||
uintptr_t RegionEnd = Region->Base + Region->RegionSize;
|
||||
uint64_t NewRegionSize = Region->RegionSize + NextSize;
|
||||
if (RegionEnd == NextPtr &&
|
||||
NewRegionSize <= MaxReservedRegionSize) {
|
||||
// Append the contiguous region
|
||||
Region->RegionSize = NewRegionSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct LiveVMARegion {
|
||||
ReservedVMARegion *SlabInfo;
|
||||
uint64_t FreeSpace{};
|
||||
uint32_t LastPageAllocation{};
|
||||
FlexBitSet<uint64_t> UsedPages;
|
||||
|
||||
// This returns the size of the LiveVMARegion in addition to the flex set that tracks the used data
|
||||
// The LiveVMARegion lives at the start of the VMA region which means on initialization we need to set that
|
||||
// tracked ranged as used immediately
|
||||
static size_t GetSizeWithFlexSet(size_t Size) {
|
||||
// One element per page
|
||||
|
||||
// 0x10'0000'0000 bytes
|
||||
// 0x100'0000 Pages
|
||||
// 1 bit per page for tracking means 0x20'0000 (Pages / 8) bytes of flex space
|
||||
// Which is 2MB of tracking
|
||||
uint64_t NumElements = (Size >> PAGE_SHIFT) * sizeof(uint64_t);
|
||||
return sizeof(LiveVMARegion) + FlexBitSet<uint64_t>::Size(NumElements);
|
||||
}
|
||||
|
||||
static void InitializeVMARegionUsed(LiveVMARegion *Region, size_t AdditionalSize) {
|
||||
size_t SizeOfLiveRegion = AlignUp(LiveVMARegion::GetSizeWithFlexSet(Region->SlabInfo->RegionSize), PAGE_SIZE);
|
||||
size_t SizePlusManagedData = SizeOfLiveRegion + AdditionalSize;
|
||||
|
||||
Region->FreeSpace = Region->SlabInfo->RegionSize - SizePlusManagedData;
|
||||
|
||||
size_t NumPages = SizePlusManagedData >> PAGE_SHIFT;
|
||||
// Memset the full tracking to zero to state nothing used
|
||||
Region->UsedPages.MemSet(Region->SlabInfo->RegionSize >> PAGE_SHIFT);
|
||||
// Set our reserved pages
|
||||
for (size_t i = 0; i < NumPages; ++i) {
|
||||
// Set our used pages
|
||||
Region->UsedPages.Set(i);
|
||||
}
|
||||
Region->LastPageAllocation = NumPages;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_trivially_copyable<LiveVMARegion>::value, "Needs to be trivially copyable");
|
||||
static_assert(offsetof(LiveVMARegion, UsedPages) == sizeof(LiveVMARegion), "FlexBitSet needs to be at the end");
|
||||
|
||||
using ReservedRegionListType = std::pmr::list<ReservedVMARegion*>;
|
||||
using LiveRegionListType = std::pmr::list<LiveVMARegion*>;
|
||||
ReservedRegionListType *ReservedRegions{};
|
||||
LiveRegionListType *LiveRegions{};
|
||||
|
||||
Alloc::ForwardOnlyIntrusiveArenaAllocator *ObjectAlloc{};
|
||||
std::mutex AllocationMutex{};
|
||||
void DetermineVASize();
|
||||
|
||||
LiveVMARegion *MakeRegionActive(ReservedRegionListType::iterator ReservedIterator, uint64_t UsedSize) {
|
||||
ReservedVMARegion *ReservedRegion = *ReservedIterator;
|
||||
|
||||
ReservedRegions->erase(ReservedIterator);
|
||||
// mprotect the new region we've allocated
|
||||
size_t SizeOfLiveRegion = AlignUp(LiveVMARegion::GetSizeWithFlexSet(ReservedRegion->RegionSize), PAGE_SIZE);
|
||||
size_t SizePlusManagedData = UsedSize + SizeOfLiveRegion;
|
||||
|
||||
mprotect(reinterpret_cast<void*>(ReservedRegion->Base), SizePlusManagedData, PROT_READ | PROT_WRITE);
|
||||
|
||||
LiveVMARegion *LiveRange = new (reinterpret_cast<void*>(ReservedRegion->Base)) LiveVMARegion();
|
||||
|
||||
// Copy over the reserved data
|
||||
LiveRange->SlabInfo = ReservedRegion;
|
||||
// Initialize VMA
|
||||
LiveVMARegion::InitializeVMARegionUsed(LiveRange, UsedSize);
|
||||
|
||||
// Add to our active tracked ranges
|
||||
auto LiveIter = LiveRegions->emplace_back(LiveRange);
|
||||
|
||||
return LiveIter;
|
||||
}
|
||||
|
||||
// 32-bit old kernel workarounds
|
||||
struct PtrCache {
|
||||
uint32_t Ptr;
|
||||
uint32_t Size;
|
||||
};
|
||||
PtrCache *Steal32BitIfOldKernel();
|
||||
void Clear32BitOnOldKernel(PtrCache *Base);
|
||||
};
|
||||
|
||||
void OSAllocator_64Bit::DetermineVASize() {
|
||||
const std::vector<uintptr_t> TLBSizes = {{
|
||||
1ULL << 57,
|
||||
1ULL << 52,
|
||||
1ULL << 48,
|
||||
1ULL << 47,
|
||||
1ULL << 42,
|
||||
1ULL << 39,
|
||||
1ULL << 36,
|
||||
}};
|
||||
|
||||
for (auto Size : TLBSizes) {
|
||||
// Just try allocating
|
||||
// We can't actually determine VA size on ARM safely
|
||||
auto Find = [](uintptr_t Size) -> bool {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
// Try grabbing a some of the top pages of the range
|
||||
// x86 allocates some high pages in the top end
|
||||
void *Ptr = ::mmap(reinterpret_cast<void*>(Size - PAGE_SIZE * i), PAGE_SIZE, PROT_NONE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (Ptr != (void*)~0ULL) {
|
||||
::munmap(Ptr, PAGE_SIZE);
|
||||
if (Ptr == (void*)(Size - PAGE_SIZE * i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (Find(Size)) {
|
||||
UPPER_BOUND = Size;
|
||||
UPPER_BOUND_PAGE = UPPER_BOUND / PAGE_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
|
||||
if (addr != 0 &&
|
||||
addr < reinterpret_cast<void*>(LOWER_BOUND)) {
|
||||
// If we are asked to allocate something outside of the 64-bit space
|
||||
// Then we need to just hand this to the OS
|
||||
return ::mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
uint64_t Addr = reinterpret_cast<uint64_t>(addr);
|
||||
// Addr must be page aligned
|
||||
if (Addr & PAGE_MASK) {
|
||||
return reinterpret_cast<void*>(-EINVAL);
|
||||
}
|
||||
|
||||
// If FD is provided then offset must also be page aligned
|
||||
if (fd != -1 &&
|
||||
offset & PAGE_MASK) {
|
||||
return reinterpret_cast<void*>(-EINVAL);
|
||||
}
|
||||
|
||||
// 64bit address overflow
|
||||
if (Addr + length < Addr) {
|
||||
return reinterpret_cast<void*>(-EOVERFLOW);
|
||||
}
|
||||
|
||||
bool Fixed = (flags & MAP_FIXED) || (flags & MAP_FIXED_NOREPLACE);
|
||||
length = AlignUp(length, PAGE_SIZE);
|
||||
|
||||
uint64_t AddrEnd = Addr + length;
|
||||
size_t NumberOfPages = length / PAGE_SIZE;
|
||||
|
||||
// This needs a mutex to be thread safe
|
||||
std::scoped_lock<std::mutex> lk{AllocationMutex};
|
||||
|
||||
uint64_t AllocatedOffset{};
|
||||
LiveVMARegion *LiveRegion{};
|
||||
|
||||
if (Fixed || Addr != 0) {
|
||||
// Check active slabs to see if we can fit this
|
||||
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
|
||||
uintptr_t RegionBegin = (*it)->SlabInfo->Base;
|
||||
uintptr_t RegionEnd = RegionBegin + (*it)->SlabInfo->RegionSize;
|
||||
|
||||
if (Addr >= RegionBegin &&
|
||||
Addr < RegionEnd) {
|
||||
LiveRegion = *it;
|
||||
// Leave our loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't find an active region that fit
|
||||
// Check reserved regions
|
||||
if (!LiveRegion) {
|
||||
// Didn't have a slab that fit this range
|
||||
// Check our reserved regions to see if we have one that fits
|
||||
for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) {
|
||||
ReservedVMARegion *ReservedRegion = *it;
|
||||
uintptr_t RegionEnd = ReservedRegion->Base + ReservedRegion->RegionSize;
|
||||
if (Addr >= ReservedRegion->Base &&
|
||||
AddrEnd < RegionEnd) {
|
||||
// Found one, let's make it active
|
||||
LiveRegion = MakeRegionActive(it, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
again:
|
||||
|
||||
auto CheckIfRangeFits = [&AllocatedOffset](LiveVMARegion *Region, uint64_t length, int prot, int flags, int fd, off_t offset, uint64_t StartingPosition = 0) -> std::pair<LiveVMARegion*, void*> {
|
||||
uint64_t AllocatedPage{};
|
||||
uint64_t NumberOfPages = length >> PAGE_SHIFT;
|
||||
|
||||
if (Region->FreeSpace >= length) {
|
||||
uint64_t LastAllocation =
|
||||
StartingPosition ?
|
||||
(StartingPosition - Region->SlabInfo->Base) >> PAGE_SHIFT
|
||||
: Region->LastPageAllocation;
|
||||
size_t RegionNumberOfPages = Region->SlabInfo->RegionSize >> PAGE_SHIFT;
|
||||
try_again:
|
||||
for (size_t CurrentPage = LastAllocation;
|
||||
CurrentPage < (RegionNumberOfPages - NumberOfPages);) {
|
||||
// If we have enough free space, check if we have enough free pages that are contiguous
|
||||
size_t Remaining = NumberOfPages;
|
||||
|
||||
assert((CurrentPage + Remaining - 1) < RegionNumberOfPages);
|
||||
while (Remaining) {
|
||||
if (Region->UsedPages[CurrentPage + Remaining - 1]) {
|
||||
// Has an intersecting range
|
||||
break;
|
||||
}
|
||||
--Remaining;
|
||||
}
|
||||
|
||||
if (Remaining) {
|
||||
// Didn't find a slab range
|
||||
CurrentPage += Remaining;
|
||||
}
|
||||
else {
|
||||
// We have a slab range
|
||||
AllocatedPage = CurrentPage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllocatedPage && LastAllocation != 0) {
|
||||
// Try again but starting from the beginning
|
||||
LastAllocation = 0;
|
||||
// Using goto so we don't have recursive mutex shenanigans
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (AllocatedPage) {
|
||||
AllocatedOffset = Region->SlabInfo->Base + AllocatedPage * PAGE_SIZE;
|
||||
|
||||
// We need to setup protections for this
|
||||
void *MMapResult = ::mmap(reinterpret_cast<void*>(AllocatedOffset),
|
||||
length,
|
||||
prot,
|
||||
(flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED,
|
||||
fd, offset);
|
||||
|
||||
if (MMapResult == MAP_FAILED) {
|
||||
return std::make_pair(Region, reinterpret_cast<void*>(-errno));
|
||||
}
|
||||
return std::make_pair(Region, MMapResult);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(nullptr, nullptr);
|
||||
};
|
||||
|
||||
if (Fixed) {
|
||||
// Found a region let's allocate to it
|
||||
if (LiveRegion) {
|
||||
// Found a slab that fits this
|
||||
if (flags & MAP_FIXED_NOREPLACE) {
|
||||
auto Fits = CheckIfRangeFits(LiveRegion, length, prot, flags, fd, offset, Addr);
|
||||
if (Fits.first && Fits.second == reinterpret_cast<void*>(Addr)) {
|
||||
// We fit correctly
|
||||
AllocatedOffset = Addr;
|
||||
}
|
||||
else {
|
||||
// Intersected with something that already existed
|
||||
return reinterpret_cast<void*>(-EEXIST);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to mmap the file to this location
|
||||
void *MMapResult = ::mmap(reinterpret_cast<void*>(Addr),
|
||||
length,
|
||||
prot,
|
||||
(flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED,
|
||||
fd, offset);
|
||||
|
||||
if (MMapResult == MAP_FAILED) {
|
||||
return reinterpret_cast<void*>(-errno);
|
||||
}
|
||||
|
||||
AllocatedOffset = Addr;
|
||||
}
|
||||
// Fall through to live region tracking
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Check our active slabs to see if we can fit the allocation
|
||||
// Slightly different than fixed since it doesn't need exact placement
|
||||
if (LiveRegion && Addr != 0) {
|
||||
// We found a LiveRegion that could hold this address. Let's try to place it
|
||||
// Check if this area is free
|
||||
auto Fits = CheckIfRangeFits(LiveRegion, length, prot, flags, fd, offset, Addr);
|
||||
if (Fits.first && Fits.second == reinterpret_cast<void*>(Addr)) {
|
||||
// We fit correctly
|
||||
AllocatedOffset = Addr;
|
||||
}
|
||||
else {
|
||||
// Couldn't fit
|
||||
// We can continue past this point still
|
||||
LiveRegion = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!LiveRegion) {
|
||||
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
|
||||
auto Fits = CheckIfRangeFits(*it, length, prot, flags, fd, offset);
|
||||
if (Fits.first && Fits.second == reinterpret_cast<void*>(AllocatedOffset)) {
|
||||
// We fit correctly
|
||||
LiveRegion = Fits.first;
|
||||
break;
|
||||
}
|
||||
|
||||
// Couldn't fit but mmap gave us an error
|
||||
if (!Fits.first && Fits.second) {
|
||||
return Fits.second;
|
||||
}
|
||||
|
||||
// nullptr on both means no error and couldn't fit
|
||||
}
|
||||
}
|
||||
|
||||
if (!LiveRegion) {
|
||||
// Couldn't find a fit in the live regions
|
||||
// Allocate a new reserved region
|
||||
size_t lengthOfLiveRegion = AlignUp(LiveVMARegion::GetSizeWithFlexSet(length), PAGE_SIZE);
|
||||
size_t lengthPlusManagedData = length + lengthOfLiveRegion;
|
||||
for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) {
|
||||
if ((*it)->RegionSize >= lengthPlusManagedData) {
|
||||
MakeRegionActive(it, 0);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LiveRegion) {
|
||||
// Mark the pages as used
|
||||
uintptr_t RegionBegin = LiveRegion->SlabInfo->Base;
|
||||
uintptr_t MappedBegin = (AllocatedOffset - RegionBegin) >> PAGE_SHIFT;
|
||||
|
||||
for (size_t i = 0; i < NumberOfPages; ++i) {
|
||||
LiveRegion->UsedPages.Set(MappedBegin + i);
|
||||
}
|
||||
|
||||
// Change our last allocation region
|
||||
LiveRegion->LastPageAllocation = MappedBegin + NumberOfPages;
|
||||
LiveRegion->FreeSpace -= length;
|
||||
}
|
||||
|
||||
if (!AllocatedOffset) {
|
||||
AllocatedOffset = -ENOMEM;
|
||||
}
|
||||
return reinterpret_cast<void*>(AllocatedOffset);
|
||||
}
|
||||
|
||||
int OSAllocator_64Bit::Munmap(void *addr, size_t length) {
|
||||
if (addr < reinterpret_cast<void*>(LOWER_BOUND)) {
|
||||
// If we are asked to allocate something outside of the 64-bit space
|
||||
// Then we need to just hand this to the OS
|
||||
return ::munmap(addr, length);
|
||||
}
|
||||
|
||||
uint64_t Addr = reinterpret_cast<uint64_t>(addr);
|
||||
|
||||
if (Addr & PAGE_MASK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (length & PAGE_MASK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (Addr + length < Addr) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
// This needs a mutex to be thread safe
|
||||
std::scoped_lock<std::mutex> lk{AllocationMutex};
|
||||
|
||||
length = AlignUp(length, PAGE_SIZE);
|
||||
|
||||
uintptr_t PtrBegin = reinterpret_cast<uintptr_t>(addr);
|
||||
uintptr_t PtrEnd = PtrBegin + length;
|
||||
// Walk all of the live ranges and find this slab then delete it
|
||||
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
|
||||
uintptr_t RegionBegin = (*it)->SlabInfo->Base;
|
||||
uintptr_t RegionEnd = RegionBegin + (*it)->SlabInfo->RegionSize;
|
||||
|
||||
if (RegionBegin <= PtrBegin &&
|
||||
RegionEnd > PtrEnd) {
|
||||
// Live region fully encompasses slab range
|
||||
|
||||
uint64_t FreedPages{};
|
||||
uint64_t SlabPageBegin = (PtrBegin - RegionBegin) >> PAGE_SHIFT;
|
||||
uint64_t PagesToFree = length >> PAGE_SHIFT;
|
||||
|
||||
for (size_t i = 0; i < PagesToFree; ++i) {
|
||||
FreedPages += (*it)->UsedPages.TestAndClear(SlabPageBegin + i) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (FreedPages != 0)
|
||||
{
|
||||
// If we were contiuous freeing then make sure to give back the physical address space
|
||||
// If the region was locked then madvise won't remove the physical backing
|
||||
// This woul be a bug in the frontend application
|
||||
// So be careful with mlock/munlock
|
||||
::madvise(addr, length, MADV_DONTNEED);
|
||||
::mmap(addr, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
}
|
||||
|
||||
(*it)->FreeSpace += FreedPages * 4096;
|
||||
|
||||
// XXX: Move region back to reserved list
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If it didn't match at all then no error
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSAllocator_64Bit::PtrCache *OSAllocator_64Bit::Steal32BitIfOldKernel() {
|
||||
// First calculate kernel version
|
||||
struct utsname buf{};
|
||||
if (uname(&buf) == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t Major{};
|
||||
int32_t Minor{};
|
||||
int32_t Patch{};
|
||||
char Tmp{};
|
||||
std::istringstream ss{buf.release};
|
||||
ss >> Major;
|
||||
ss.read(&Tmp, 1);
|
||||
ss >> Minor;
|
||||
ss.read(&Tmp, 1);
|
||||
ss >> Patch;
|
||||
ss.read(&Tmp, 1);
|
||||
uint32_t Version = (Major << 24) | (Minor << 16) | Patch;
|
||||
|
||||
if (Version >= ((4 << 24) | (17 << 16) | 0)) {
|
||||
// If the kernel is >= 4.17 then it supports MAP_FIXED_NOREPLACE
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OSAllocator_64Bit::PtrCache *Cache{};
|
||||
uint32_t CacheSize{};
|
||||
uint32_t CurrentCacheOffset = 0;
|
||||
constexpr std::array<size_t, 6> ReservedVMARegionSizes = {{
|
||||
1ULL * 1024 * 1024 * 1024, // 1GB
|
||||
512ULL * 1024 * 1024, // 512MB
|
||||
128ULL * 1024 * 1024, // 128MB
|
||||
32ULL * 1024 * 1024, // 32MB
|
||||
1ULL * 1024 * 1024, // 1MB
|
||||
4096ULL // One page
|
||||
}};
|
||||
constexpr size_t AllocationSizeMaxIndex = ReservedVMARegionSizes.size() - 1;
|
||||
uint64_t CurrentSizeIndex = 0;
|
||||
|
||||
constexpr size_t LOWER_BOUND_32 = 0x1'0000;
|
||||
constexpr size_t UPPER_BOUND_32 = LOWER_BOUND;
|
||||
|
||||
for (size_t MemoryOffset = LOWER_BOUND_32; MemoryOffset < UPPER_BOUND_32;) {
|
||||
size_t AllocationSize = ReservedVMARegionSizes[CurrentSizeIndex];
|
||||
size_t MemoryOffsetUpper = MemoryOffset + AllocationSize;
|
||||
|
||||
// If we would go above the upper bound on size then try the next size
|
||||
if (MemoryOffsetUpper > UPPER_BOUND_32) {
|
||||
++CurrentSizeIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
void *Ptr = ::mmap(reinterpret_cast<void*>(MemoryOffset), AllocationSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||
|
||||
// If we managed to allocate and not get the address we want then unmap it
|
||||
// This happens with kernels older than 4.17
|
||||
if (reinterpret_cast<uintptr_t>(Ptr) + AllocationSize > UPPER_BOUND_32) {
|
||||
munmap(Ptr, AllocationSize);
|
||||
Ptr = reinterpret_cast<void*>(~0ULL);
|
||||
}
|
||||
|
||||
// If we failed to allocate and we are on the smallest allocation size then just continue onward
|
||||
// This page was unmappable
|
||||
if (reinterpret_cast<uintptr_t>(Ptr) == ~0ULL && CurrentSizeIndex == AllocationSizeMaxIndex) {
|
||||
CurrentSizeIndex = 0;
|
||||
MemoryOffset += AllocationSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Congratulations we were able to map this bit
|
||||
// Reset and claim it was available
|
||||
if (reinterpret_cast<uintptr_t>(Ptr) != ~0ULL) {
|
||||
if (!Cache) {
|
||||
Cache = reinterpret_cast<OSAllocator_64Bit::PtrCache *>(Ptr);
|
||||
CacheSize = AllocationSize;
|
||||
}
|
||||
else {
|
||||
Cache[CurrentCacheOffset] = {
|
||||
.Ptr = static_cast<uint32_t>(reinterpret_cast<uint64_t>(Ptr)),
|
||||
.Size = static_cast<uint32_t>(AllocationSize)
|
||||
};
|
||||
++CurrentCacheOffset;
|
||||
}
|
||||
|
||||
CurrentSizeIndex = 0;
|
||||
MemoryOffset += AllocationSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Couldn't allocate at this size
|
||||
// Increase and continue
|
||||
++CurrentSizeIndex;
|
||||
}
|
||||
|
||||
Cache[CurrentCacheOffset] = {
|
||||
.Ptr = static_cast<uint32_t>(reinterpret_cast<uint64_t>(Cache)),
|
||||
.Size = CacheSize,
|
||||
};
|
||||
return Cache;
|
||||
}
|
||||
|
||||
void OSAllocator_64Bit::Clear32BitOnOldKernel(OSAllocator_64Bit::PtrCache *Base) {
|
||||
if (Base == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0;; ++i) {
|
||||
void *Ptr = reinterpret_cast<void*>(Base[i].Ptr);
|
||||
size_t Size = Base[i].Size;
|
||||
munmap(Ptr, Size);
|
||||
if (Ptr == Base) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OSAllocator_64Bit::OSAllocator_64Bit() {
|
||||
malloc_trim(0);
|
||||
DetermineVASize();
|
||||
auto ArrayPtr = Steal32BitIfOldKernel();
|
||||
|
||||
// On allocation try and steal the entire upper 64bits of address space for mapping
|
||||
constexpr std::array<size_t, 8> ReservedVMARegionSizes = {{
|
||||
// Anything larger than 64GB fails out
|
||||
64ULL * 1024 * 1024 * 1024, // 64GB
|
||||
32ULL * 1024 * 1024 * 1024, // 32GB
|
||||
16ULL * 1024 * 1024 * 1024, // 16GB
|
||||
4ULL * 1024 * 1024 * 1024, // 4GB
|
||||
1ULL * 1024 * 1024 * 1024, // 1GB
|
||||
512ULL * 1024 * 1024, // 512MB
|
||||
128ULL * 1024 * 1024, // 128MB
|
||||
4096ULL // One page
|
||||
}};
|
||||
|
||||
constexpr size_t AllocationSizeMaxIndex = ReservedVMARegionSizes.size() - 1;
|
||||
|
||||
// Have the first region only be 4GB VMA
|
||||
// Avoids conflicts with some tests
|
||||
uint64_t CurrentSizeIndex = 3;
|
||||
ReservedVMARegion *PrevReserved{};
|
||||
for (size_t MemoryOffset = LOWER_BOUND; MemoryOffset < UPPER_BOUND;) {
|
||||
size_t AllocationSize = ReservedVMARegionSizes[CurrentSizeIndex];
|
||||
size_t MemoryOffsetUpper = MemoryOffset + AllocationSize;
|
||||
|
||||
// If we would go above the upper bound on size then try the next size
|
||||
if (MemoryOffsetUpper > UPPER_BOUND) {
|
||||
++CurrentSizeIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
void *Ptr = ::mmap(reinterpret_cast<void*>(MemoryOffset), AllocationSize, PROT_NONE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||
|
||||
// If we managed to allocate and not get the address we want then unmap it
|
||||
// This happens with kernels older than 4.17
|
||||
if (reinterpret_cast<uintptr_t>(Ptr) != MemoryOffset &&
|
||||
reinterpret_cast<uintptr_t>(Ptr) < LOWER_BOUND) {
|
||||
munmap(Ptr, AllocationSize);
|
||||
Ptr = reinterpret_cast<void*>(~0ULL);
|
||||
}
|
||||
|
||||
// If we failed to allocate and we are on the smallest allocation size then just continue onward
|
||||
// This page was unmappable
|
||||
if (reinterpret_cast<uintptr_t>(Ptr) == ~0ULL && CurrentSizeIndex == AllocationSizeMaxIndex) {
|
||||
CurrentSizeIndex = 0;
|
||||
MemoryOffset += AllocationSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Congratulations we were able to map this bit
|
||||
// Reset and claim it was available
|
||||
if (reinterpret_cast<uintptr_t>(Ptr) != ~0ULL) {
|
||||
if (!ObjectAlloc) {
|
||||
// Steal the first allocation for an intrusive allocator
|
||||
// Will be mprotected correctly already
|
||||
int Result = mprotect(Ptr, AllocationSize, PROT_READ | PROT_WRITE);
|
||||
LogMan::Throw::A(Result == 0, "mprotect(%p, 0x%lx) -> %d (%s)", Ptr, AllocationSize, Result, strerror(errno));
|
||||
ObjectAlloc = new (Ptr) Alloc::ForwardOnlyIntrusiveArenaAllocator(Ptr, AllocationSize);
|
||||
ReservedRegions = ObjectAlloc->new_construct(ReservedRegions, ObjectAlloc);
|
||||
LiveRegions = ObjectAlloc->new_construct(LiveRegions, ObjectAlloc);
|
||||
}
|
||||
else {
|
||||
bool Merged = false;
|
||||
if (PrevReserved) {
|
||||
Merged = MergeReservedRegionIfPossible(PrevReserved, reinterpret_cast<uint64_t>(Ptr), AllocationSize);
|
||||
}
|
||||
|
||||
if (!Merged) {
|
||||
ReservedVMARegion *Region = ObjectAlloc->new_construct<ReservedVMARegion>();
|
||||
Region->Base = reinterpret_cast<uint64_t>(Ptr);
|
||||
Region->RegionSize = AllocationSize;
|
||||
ReservedRegions->emplace_back(Region);
|
||||
PrevReserved = Region;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentSizeIndex = 0;
|
||||
MemoryOffset += AllocationSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Couldn't allocate at this size
|
||||
// Increase and continue
|
||||
++CurrentSizeIndex;
|
||||
}
|
||||
|
||||
Clear32BitOnOldKernel(ArrayPtr);
|
||||
}
|
||||
|
||||
OSAllocator_64Bit::~OSAllocator_64Bit() {
|
||||
// For consistency, pull the mutex
|
||||
std::scoped_lock<std::mutex> lk{AllocationMutex};
|
||||
|
||||
// Walk the pages and deallocate
|
||||
// First walk the live regions
|
||||
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
|
||||
::munmap(reinterpret_cast<void*>((*it)->SlabInfo->Base), (*it)->SlabInfo->RegionSize);
|
||||
}
|
||||
|
||||
// Now walk the reserved regions
|
||||
for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) {
|
||||
::munmap(reinterpret_cast<void*>((*it)->Base), (*it)->RegionSize);
|
||||
}
|
||||
}
|
||||
|
||||
Alloc::HostAllocator *Create64BitAllocator() {
|
||||
return new OSAllocator_64Bit{};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include "HostAllocator.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T>
|
||||
struct FlexBitSet final {
|
||||
using ElementType = T;
|
||||
constexpr static size_t MinimumSize = sizeof(ElementType);
|
||||
constexpr static size_t MinimumSizeBits = sizeof(ElementType) * 8;
|
||||
|
||||
T Memory[];
|
||||
|
||||
bool Get(T Element) {
|
||||
return (Memory[Element / MinimumSizeBits] & (1ULL << (Element % MinimumSizeBits))) != 0;
|
||||
}
|
||||
bool TestAndClear(T Element) {
|
||||
bool Value = Get(Element);
|
||||
Memory[Element / MinimumSizeBits] &= ~(1ULL << (Element % MinimumSizeBits));
|
||||
return Value;
|
||||
}
|
||||
void Set(T Element) {
|
||||
Memory[Element / MinimumSizeBits] |= (1ULL << (Element % MinimumSizeBits));
|
||||
}
|
||||
void Clear(T Element) {
|
||||
Memory[Element / MinimumSizeBits] &= ~(1ULL << (Element % MinimumSizeBits));
|
||||
}
|
||||
void MemClear(size_t Elements) {
|
||||
memset(Memory, 0, Alloc::AlignUp(Elements / MinimumSizeBits, MinimumSizeBits));
|
||||
}
|
||||
void MemSet(size_t Elements) {
|
||||
memset(Memory, 0xFF, Alloc::AlignUp(Elements / MinimumSizeBits, MinimumSizeBits));
|
||||
}
|
||||
|
||||
// This very explicitly doesn't let you take an address
|
||||
// Is only a getter
|
||||
bool operator[](T Element) {
|
||||
return Get(Element);
|
||||
}
|
||||
|
||||
static size_t Size(T Elements) {
|
||||
return Alloc::AlignUp(Elements / MinimumSizeBits, MinimumSizeBits);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(FlexBitSet<uint64_t>) == 0, "This needs to be a flex member");
|
||||
static_assert(std::is_trivially_copyable<FlexBitSet<uint64_t>>::value, "Needsto be trivially copyable");
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
|
||||
constexpr static uint64_t PAGE_SIZE = 4096;
|
||||
|
||||
namespace Alloc {
|
||||
static inline uint64_t AlignUp(uint64_t value, uint64_t size) {
|
||||
return value + (size - value % size) % size;
|
||||
};
|
||||
|
||||
// HostAllocator is just a page pased slab allocator
|
||||
// Similar to mmap and munmap only mapping at the page level
|
||||
class HostAllocator {
|
||||
public:
|
||||
HostAllocator() = default;
|
||||
virtual ~HostAllocator() = default;
|
||||
virtual void *AllocateSlab(size_t Size) = 0;
|
||||
virtual void DeallocateSlab(void *Ptr, size_t Size) = 0;
|
||||
|
||||
virtual void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { return nullptr; }
|
||||
virtual int Munmap(void *addr, size_t length) { return -1; }
|
||||
};
|
||||
|
||||
class GlobalAllocator {
|
||||
public:
|
||||
HostAllocator *Alloc{};
|
||||
GlobalAllocator(HostAllocator *_Alloc)
|
||||
: Alloc {_Alloc} {}
|
||||
|
||||
virtual void *malloc(size_t Size) = 0;
|
||||
virtual void *calloc(size_t num, size_t size) = 0;
|
||||
virtual void *realloc(void *ptr, size_t size) = 0;
|
||||
virtual void *memalign(size_t alignment, size_t size) = 0;
|
||||
virtual void free(void *ptr) = 0;
|
||||
};
|
||||
|
||||
GlobalAllocator *CreateBasicAllocator(HostAllocator *Alloc);
|
||||
}
|
||||
|
||||
namespace Alloc::OSAllocator {
|
||||
Alloc::HostAllocator *Create64BitAllocator();
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
#include "FlexBitSet.h"
|
||||
#include "HostAllocator.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <memory_resource>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace Alloc {
|
||||
class ForwardOnlyIntrusiveArenaAllocator final : public std::pmr::memory_resource {
|
||||
public:
|
||||
ForwardOnlyIntrusiveArenaAllocator(void* Ptr, size_t _Size)
|
||||
: Begin {reinterpret_cast<uintptr_t>(Ptr)}
|
||||
, Size {_Size} {
|
||||
LastAllocation = sizeof(ForwardOnlyIntrusiveArenaAllocator);
|
||||
}
|
||||
|
||||
~ForwardOnlyIntrusiveArenaAllocator() = default;
|
||||
|
||||
template<class U, class... Args>
|
||||
U *new_construct(Args&&... args) {
|
||||
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
|
||||
return new (Ptr) U(args...);
|
||||
}
|
||||
|
||||
template<class U, class... Args>
|
||||
U *new_construct(U *Class, Args&&... args) {
|
||||
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
|
||||
return new (Ptr) U(args...);
|
||||
}
|
||||
|
||||
size_t AmountAllocated() const { return LastAllocation; }
|
||||
|
||||
private:
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) override {
|
||||
size_t PreviousAligned = Alloc::AlignUp(LastAllocation, alignment);
|
||||
size_t NewOffset = PreviousAligned + bytes;
|
||||
|
||||
if (NewOffset > Size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LastAllocation = NewOffset;
|
||||
|
||||
return reinterpret_cast<void*>(Begin + PreviousAligned);
|
||||
}
|
||||
|
||||
void do_deallocate(void*, std::size_t, std::size_t) override {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
|
||||
// Only if the allocator pointers are the same are they equal
|
||||
if (this == &other) {
|
||||
return true;
|
||||
}
|
||||
// We don't share state with another allocator so we can't share anything
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t Begin;
|
||||
size_t Size;
|
||||
size_t LastAllocation{};
|
||||
};
|
||||
|
||||
class IntrusiveArenaAllocator final : public std::pmr::memory_resource {
|
||||
public:
|
||||
IntrusiveArenaAllocator(void* Ptr, size_t _Size)
|
||||
: Begin {reinterpret_cast<uintptr_t>(Ptr)}
|
||||
, Size {_Size} {
|
||||
uint64_t NumberOfPages = _Size / PAGE_SIZE;
|
||||
uint64_t UsedBits = Alloc::AlignUp(sizeof(IntrusiveArenaAllocator) +
|
||||
Size / PAGE_SIZE / 8, PAGE_SIZE);
|
||||
for (size_t i = 0; i < UsedBits; ++i) {
|
||||
UsedPages.Set(i);
|
||||
}
|
||||
|
||||
FreePages = NumberOfPages - UsedBits;
|
||||
}
|
||||
|
||||
template<class U, class... Args>
|
||||
U *new_construct(Args&&... args) {
|
||||
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
|
||||
return new (Ptr) U(args...);
|
||||
}
|
||||
|
||||
template<class U, class... Args>
|
||||
U *new_construct(U *Class, Args&&... args) {
|
||||
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
|
||||
return new (Ptr) U(args...);
|
||||
}
|
||||
|
||||
uintptr_t GetSlabBase() const { return Begin; }
|
||||
uint64_t GetSlabSize() const { return Size; }
|
||||
uint64_t GetFreePages() const { return FreePages; }
|
||||
|
||||
private:
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) override {
|
||||
std::scoped_lock<std::mutex> lk{AllocationMutex};
|
||||
|
||||
size_t NumberPages = Alloc::AlignUp(bytes, PAGE_SIZE) / PAGE_SIZE;
|
||||
|
||||
uintptr_t AllocatedOffset{};
|
||||
|
||||
try_again:
|
||||
for (uintptr_t CurrentPage = LastAllocatedPageOffset; CurrentPage <= (Size - NumberPages);) {
|
||||
size_t Remaining = NumberPages;
|
||||
|
||||
while (Remaining) {
|
||||
if (UsedPages[CurrentPage + Remaining - 1]) {
|
||||
// Has an intersecting range
|
||||
break;
|
||||
}
|
||||
--Remaining;
|
||||
}
|
||||
|
||||
if (Remaining) {
|
||||
// Didn't find an allocation range
|
||||
CurrentPage += Remaining;
|
||||
}
|
||||
else {
|
||||
// We have a range to allocate
|
||||
AllocatedOffset = CurrentPage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AllocatedOffset && LastAllocatedPageOffset != 0) {
|
||||
// Try again but starting from the beginning
|
||||
LastAllocatedPageOffset = 0;
|
||||
// Using goto so we don't have recursive mutex shenanigans
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
// Allocated offset must be valid or zero at this point
|
||||
if (AllocatedOffset) {
|
||||
// Map the range as no longer available
|
||||
for (size_t i = 0; i < NumberPages; ++i) {
|
||||
UsedPages.Set(AllocatedOffset + i);
|
||||
}
|
||||
|
||||
LastAllocatedPageOffset = AllocatedOffset + NumberPages;
|
||||
|
||||
// Now convert this base page to a pointer and return it
|
||||
return reinterpret_cast<void*>(Begin + AllocatedOffset * PAGE_SIZE);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override {
|
||||
std::scoped_lock<std::mutex> lk{AllocationMutex};
|
||||
|
||||
uintptr_t PageOffset = (reinterpret_cast<uintptr_t>(p) - Begin) / PAGE_SIZE;
|
||||
size_t NumPages = AlignUp(bytes, PAGE_SIZE) / PAGE_SIZE;
|
||||
|
||||
// Walk the allocation list and deallocate
|
||||
uint64_t FreedPages{};
|
||||
for (size_t i = 0; i < NumPages; ++i) {
|
||||
FreedPages += UsedPages.TestAndClear(PageOffset + i) ? 1 : 0;
|
||||
}
|
||||
FreePages += FreedPages;
|
||||
}
|
||||
|
||||
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
|
||||
// Only if the allocator pointers are the same are they equal
|
||||
if (this == &other) {
|
||||
return true;
|
||||
}
|
||||
// We don't share state with another allocator so we can't share anything
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t Begin;
|
||||
size_t Size;
|
||||
uint64_t FreePages{};
|
||||
size_t LastAllocatedPageOffset{};
|
||||
std::mutex AllocationMutex{};
|
||||
// For up to 64GB regions this will require up to 2MB tracking
|
||||
// Needs to be the last element
|
||||
FlexBitSet<uint64_t> UsedPages;
|
||||
};
|
||||
}
|
||||
Vendored
+93
-29
@@ -6,7 +6,7 @@ $end_info$
|
||||
*/
|
||||
|
||||
#include <FEXCore/Utils/Common/MathUtils.h>
|
||||
#include <FEXCore/Utils/ELFLoader.h>
|
||||
#include <FEXCore/Utils/ELFContainer.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <cstring>
|
||||
#include <elf.h>
|
||||
@@ -134,7 +134,7 @@ ELFContainer::ELFContainer(std::string const &Filename, std::string const &RootF
|
||||
//PrintInitArray();
|
||||
//PrintDynamicTable();
|
||||
|
||||
//LogMan::Throw::A(InterpreterHeader == nullptr, "Can only handle static programs");
|
||||
//LOGMAN_THROW_A(InterpreterHeader == nullptr, "Can only handle static programs");
|
||||
}
|
||||
|
||||
ELFContainer::~ELFContainer() {
|
||||
@@ -196,8 +196,8 @@ bool ELFContainer::LoadELF_32() {
|
||||
|
||||
memcpy(&Header, reinterpret_cast<Elf32_Ehdr *>(&RawFile.at(0)),
|
||||
sizeof(Elf32_Ehdr));
|
||||
LogMan::Throw::A(Header._32.e_phentsize == sizeof(Elf32_Phdr), "PH Entry size wasn't correct size");
|
||||
LogMan::Throw::A(Header._32.e_shentsize == sizeof(Elf32_Shdr), "PH Entry size wasn't correct size");
|
||||
LOGMAN_THROW_A(Header._32.e_phentsize == sizeof(Elf32_Phdr), "PH Entry size wasn't correct size");
|
||||
LOGMAN_THROW_A(Header._32.e_shentsize == sizeof(Elf32_Shdr), "PH Entry size wasn't correct size");
|
||||
|
||||
if (Header._32.e_machine != EM_386) {
|
||||
LogMan::Msg::D("32bit ELF wasn't x86 based");
|
||||
@@ -237,8 +237,8 @@ bool ELFContainer::LoadELF_64() {
|
||||
|
||||
memcpy(&Header, reinterpret_cast<Elf64_Ehdr *>(&RawFile.at(0)),
|
||||
sizeof(Elf64_Ehdr));
|
||||
LogMan::Throw::A(Header._64.e_phentsize == 56, "PH Entry size wasn't 56");
|
||||
LogMan::Throw::A(Header._64.e_shentsize == 64, "PH Entry size wasn't 64");
|
||||
LOGMAN_THROW_A(Header._64.e_phentsize == 56, "PH Entry size wasn't 56");
|
||||
LOGMAN_THROW_A(Header._64.e_shentsize == 64, "PH Entry size wasn't 64");
|
||||
|
||||
if (Header._64.e_machine != EM_X86_64) {
|
||||
LogMan::Msg::D("64bit ELF wasn't x86-64 based");
|
||||
@@ -408,9 +408,9 @@ void ELFContainer::CalculateSymbols() {
|
||||
uint64_t NumSymTabSymbols = 0;
|
||||
uint64_t NumDynSymSymbols = 0;
|
||||
if (SymTabHeader) {
|
||||
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
"Symbol table string table section is wrong");
|
||||
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
||||
"Entry size doesn't match symbol entry");
|
||||
|
||||
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32;
|
||||
@@ -419,9 +419,9 @@ void ELFContainer::CalculateSymbols() {
|
||||
}
|
||||
|
||||
if (DynSymTabHeader) {
|
||||
LogMan::Throw::A(DynSymTabHeader->sh_link < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(DynSymTabHeader->sh_link < SectionHeaders.size(),
|
||||
"Symbol table string table section is wrong");
|
||||
LogMan::Throw::A(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
||||
LOGMAN_THROW_A(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
||||
"Entry size doesn't match symbol entry");
|
||||
|
||||
DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._32;
|
||||
@@ -477,6 +477,36 @@ void ELFContainer::CalculateSymbols() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32;
|
||||
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
||||
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
||||
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
|
||||
if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) {
|
||||
auto eh_frame_hdr = &RawFile.at(hdr->sh_offset);
|
||||
// we only handle this specific unwind table encoding
|
||||
if (eh_frame_hdr[0] == 1 && eh_frame_hdr[1] == 0x1B && eh_frame_hdr[2] == 0x3 && eh_frame_hdr[3] == 0x3b) {
|
||||
// ptr enc : 4 bytes, signed, pcrel
|
||||
// fde count : 4 bytes udata
|
||||
// table enc : 4 bytes, signed, datarel
|
||||
int fde_count = *(int*)(eh_frame_hdr + 8);
|
||||
UnwindEntries.clear();
|
||||
UnwindEntries.reserve(fde_count);
|
||||
|
||||
struct entry {
|
||||
int32_t pc;
|
||||
int32_t fde;
|
||||
};
|
||||
|
||||
entry *Table = (entry*)(eh_frame_hdr+12);
|
||||
for (int f = 0; f < fde_count; f++) {
|
||||
uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset);
|
||||
UnwindEntries.push_back(Entry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Elf64_Shdr const *SymTabHeader{nullptr};
|
||||
@@ -511,9 +541,9 @@ void ELFContainer::CalculateSymbols() {
|
||||
uint64_t NumSymTabSymbols = 0;
|
||||
uint64_t NumDynSymSymbols = 0;
|
||||
if (SymTabHeader) {
|
||||
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
"Symbol table string table section is wrong");
|
||||
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
||||
"Entry size doesn't match symbol entry");
|
||||
|
||||
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64;
|
||||
@@ -522,9 +552,9 @@ void ELFContainer::CalculateSymbols() {
|
||||
}
|
||||
|
||||
if (DynSymTabHeader) {
|
||||
LogMan::Throw::A(DynSymTabHeader->sh_link < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(DynSymTabHeader->sh_link < SectionHeaders.size(),
|
||||
"Symbol table string table section is wrong");
|
||||
LogMan::Throw::A(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
||||
LOGMAN_THROW_A(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
||||
"Entry size doesn't match symbol entry");
|
||||
|
||||
DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._64;
|
||||
@@ -580,6 +610,36 @@ void ELFContainer::CalculateSymbols() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
|
||||
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
||||
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
|
||||
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
|
||||
if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) {
|
||||
auto eh_frame_hdr = &RawFile.at(hdr->sh_offset);
|
||||
// we only handle this specific unwind table encoding
|
||||
if (eh_frame_hdr[0] == 1 && eh_frame_hdr[1] == 0x1B && eh_frame_hdr[2] == 0x3 && eh_frame_hdr[3] == 0x3b) {
|
||||
// ptr enc : 4 bytes, signed, pcrel
|
||||
// fde count : 4 bytes udata
|
||||
// table enc : 4 bytes, signed, datarel
|
||||
int fde_count = *(int*)(eh_frame_hdr + 8);
|
||||
UnwindEntries.clear();
|
||||
UnwindEntries.reserve(fde_count);
|
||||
|
||||
struct entry {
|
||||
int32_t pc;
|
||||
int32_t fde;
|
||||
};
|
||||
|
||||
entry *Table = (entry*)(eh_frame_hdr+12);
|
||||
for (int f = 0; f < fde_count; f++) {
|
||||
uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset);
|
||||
UnwindEntries.push_back(Entry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,6 +689,11 @@ void ELFContainer::AddSymbols(SymbolAdder Adder) {
|
||||
}
|
||||
}
|
||||
}
|
||||
void ELFContainer::AddUnwindEntries(UnwindAdder Adder) {
|
||||
for (auto Entry : UnwindEntries) {
|
||||
Adder(Entry);
|
||||
}
|
||||
}
|
||||
|
||||
void ELFContainer::PrintHeader() const {
|
||||
if (Mode == MODE_32BIT) {
|
||||
@@ -665,7 +730,7 @@ void ELFContainer::PrintHeader() const {
|
||||
|
||||
void ELFContainer::PrintSectionHeaders() const {
|
||||
if (Mode == MODE_32BIT) {
|
||||
LogMan::Throw::A(Header._32.e_shstrndx < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(Header._32.e_shstrndx < SectionHeaders.size(),
|
||||
"String index section is wrong index!");
|
||||
Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32;
|
||||
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
||||
@@ -685,7 +750,7 @@ void ELFContainer::PrintSectionHeaders() const {
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogMan::Throw::A(Header._64.e_shstrndx < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(Header._64.e_shstrndx < SectionHeaders.size(),
|
||||
"String index section is wrong index!");
|
||||
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
|
||||
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
|
||||
@@ -708,7 +773,7 @@ void ELFContainer::PrintSectionHeaders() const {
|
||||
|
||||
void ELFContainer::PrintProgramHeaders() const {
|
||||
if (Mode == MODE_32BIT) {
|
||||
LogMan::Throw::A(Header._32.e_shstrndx < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(Header._32.e_shstrndx < SectionHeaders.size(),
|
||||
"String index section is wrong index!");
|
||||
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
|
||||
Elf32_Phdr const *hdr = ProgramHeaders.at(i)._32;
|
||||
@@ -723,7 +788,7 @@ void ELFContainer::PrintProgramHeaders() const {
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogMan::Throw::A(Header._64.e_shstrndx < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(Header._64.e_shstrndx < SectionHeaders.size(),
|
||||
"String index section is wrong index!");
|
||||
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
|
||||
Elf64_Phdr const *hdr = ProgramHeaders.at(i)._64;
|
||||
@@ -757,9 +822,9 @@ void ELFContainer::PrintSymbolTable() const {
|
||||
return;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
"Symbol table string table section is wrong");
|
||||
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
|
||||
"Entry size doesn't match symbol entry");
|
||||
|
||||
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32;
|
||||
@@ -795,9 +860,9 @@ void ELFContainer::PrintSymbolTable() const {
|
||||
return;
|
||||
}
|
||||
|
||||
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
|
||||
"Symbol table string table section is wrong");
|
||||
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
||||
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
|
||||
"Entry size doesn't match symbol entry");
|
||||
|
||||
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64;
|
||||
@@ -842,12 +907,12 @@ void ELFContainer::PrintRelocationTable() const {
|
||||
LogMan::Msg::D("Relocation Section: '%s'", &SHStrings[RelaHeader->sh_name]);
|
||||
|
||||
if (RelaHeader->sh_info != 0) {
|
||||
LogMan::Throw::A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
|
||||
LOGMAN_THROW_A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
|
||||
GOTHeader = SectionHeaders.at(RelaHeader->sh_info)._64;
|
||||
}
|
||||
|
||||
if (RelaHeader->sh_link != 0) {
|
||||
LogMan::Throw::A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
|
||||
LOGMAN_THROW_A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
|
||||
DynSymHeader = SectionHeaders.at(RelaHeader->sh_link)._64;
|
||||
|
||||
StringTableHeader = SectionHeaders.at(DynSymHeader->sh_link)._64;
|
||||
@@ -865,7 +930,7 @@ void ELFContainer::PrintRelocationTable() const {
|
||||
LogMan::Msg::D("\toffset: 0x%lx", Entry->r_offset);
|
||||
LogMan::Msg::D("\tSym: 0x%lx", Sym);
|
||||
if (DynSymHeader && Sym != 0) {
|
||||
LogMan::Throw::A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
|
||||
LOGMAN_THROW_A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
|
||||
|
||||
uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize;
|
||||
Elf64_Sym const *Symbol =
|
||||
@@ -928,12 +993,12 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol
|
||||
RelaHeader = hdr;
|
||||
|
||||
if (RelaHeader->sh_info != 0) {
|
||||
LogMan::Throw::A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
|
||||
LOGMAN_THROW_A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
|
||||
GOTHeader = SectionHeaders.at(RelaHeader->sh_info)._64;
|
||||
}
|
||||
|
||||
if (RelaHeader->sh_link != 0) {
|
||||
LogMan::Throw::A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
|
||||
LOGMAN_THROW_A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
|
||||
DynSymHeader = SectionHeaders.at(RelaHeader->sh_link)._64;
|
||||
|
||||
StringTableHeader = SectionHeaders.at(DynSymHeader->sh_link)._64;
|
||||
@@ -950,7 +1015,7 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol
|
||||
Elf64_Sym const *EntrySymbol {nullptr};
|
||||
char const *EntrySymbolName {nullptr};
|
||||
if (DynSymHeader && Sym != 0) {
|
||||
LogMan::Throw::A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
|
||||
LOGMAN_THROW_A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
|
||||
|
||||
uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize;
|
||||
EntrySymbol =
|
||||
@@ -1286,5 +1351,4 @@ void ELFContainer::GetInitLocations(uint64_t GuestELFBase, std::vector<uint64_t>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace ELFLoader
|
||||
+5
-4
@@ -6,6 +6,7 @@ $end_info$
|
||||
*/
|
||||
|
||||
#include <FEXCore/Utils/ELFSymbolDatabase.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/Common/MathUtils.h>
|
||||
|
||||
@@ -82,7 +83,7 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file)
|
||||
if (NameToELF.find(Lib) == NameToELF.end()) {
|
||||
std::string LibraryPath;
|
||||
bool Found = FindLibraryFile(&LibraryPath, Lib.c_str());
|
||||
LogMan::Throw::A(Found, "Couldn't find library '%s'", Lib.c_str());
|
||||
LOGMAN_THROW_A(Found, "Couldn't find library '%s'", Lib.c_str());
|
||||
auto Info = DynamicELFInfo.emplace_back(new ELFInfo{});
|
||||
Info->Name = Lib;
|
||||
Info->Container = new ::ELFLoader::ELFContainer(LibraryPath, {}, true);
|
||||
@@ -110,7 +111,7 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file)
|
||||
FillSymbols();
|
||||
|
||||
if (LocalInfo.Container->WasDynamic() && File->GetMode() == ELFContainer::MODE_64BIT) {
|
||||
ELFBase = mmap(nullptr, ELFMemorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
ELFBase = FEXCore::Allocator::mmap(nullptr, ELFMemorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
FillMemoryLayouts(reinterpret_cast<uintptr_t>(ELFBase));
|
||||
FillInitializationOrder();
|
||||
FillSymbols();
|
||||
@@ -121,7 +122,7 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file)
|
||||
|
||||
ELFSymbolDatabase::~ELFSymbolDatabase() {
|
||||
if (ELFBase) {
|
||||
munmap(ELFBase, ELFMemorySize);
|
||||
FEXCore::Allocator::munmap(ELFBase, ELFMemorySize);
|
||||
ELFBase = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -164,7 +165,7 @@ void ELFSymbolDatabase::FillMemoryLayouts(uint64_t DefinedBase) {
|
||||
uint64_t CurrentELFAlignedSize = AlignUp(std::get<2>(LocalInfo.CustomLayout), 4096);
|
||||
if (CurrentELFBase < 0x10000) {
|
||||
// We can't allocate memory in the first 16KB, Hopefully no elfs require this.
|
||||
LogMan::Msg::A("Elf requires memory mapped in the first 16kb");
|
||||
LOGMAN_MSG_A("Elf requires memory mapped in the first 16kb");
|
||||
}
|
||||
|
||||
std::get<2>(LocalInfo.CustomLayout) = CurrentELFAlignedSize;
|
||||
|
||||
+68
-1
@@ -1,15 +1,59 @@
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/Threads.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <deque>
|
||||
|
||||
namespace FEXCore::Threads {
|
||||
// Stack pool handling
|
||||
struct StackPoolItem {
|
||||
void *Ptr;
|
||||
size_t Size;
|
||||
};
|
||||
std::mutex StackPoolMutex{};
|
||||
std::deque<StackPoolItem> StackPool;
|
||||
|
||||
void *AllocateStackObject(size_t Size) {
|
||||
std::unique_lock<std::mutex> lk{StackPoolMutex};
|
||||
if (StackPool.size() == 0) {
|
||||
// Nothing in the pool, just allocate
|
||||
return FEXCore::Allocator::mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
|
||||
}
|
||||
|
||||
// Keep the first item in the stack pool
|
||||
auto Result = StackPool.front().Ptr;
|
||||
StackPool.pop_front();
|
||||
|
||||
// Erase the rest as a garbage collection step
|
||||
for (auto &Item : StackPool) {
|
||||
FEXCore::Allocator::munmap(Item.Ptr, Item.Size);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void AddStackToPool(void *Ptr, size_t Size) {
|
||||
std::unique_lock<std::mutex> lk{StackPoolMutex};
|
||||
StackPool.emplace_back(StackPoolItem{Ptr, Size});
|
||||
}
|
||||
|
||||
void *InitializeThread(void *Ptr);
|
||||
|
||||
class PThread final : public Thread {
|
||||
public:
|
||||
PThread(FEXCore::Threads::ThreadFunc Func, void *Arg) {
|
||||
PThread(FEXCore::Threads::ThreadFunc Func, void *Arg)
|
||||
: UserFunc {Func}
|
||||
, UserArg {Arg} {
|
||||
pthread_attr_t Attr{};
|
||||
Stack = AllocateStackObject(STACK_SIZE);
|
||||
pthread_attr_init(&Attr);
|
||||
pthread_attr_setstack(&Attr, Stack, STACK_SIZE);
|
||||
pthread_create(&Thread, &Attr, Func, Arg);
|
||||
|
||||
pthread_attr_destroy(&Attr);
|
||||
}
|
||||
|
||||
bool joinable() override {
|
||||
@@ -38,10 +82,33 @@ namespace FEXCore::Threads {
|
||||
return self == Thread;
|
||||
}
|
||||
|
||||
void *Execute() {
|
||||
return UserFunc(UserArg);
|
||||
}
|
||||
|
||||
void FreeStack() {
|
||||
AddStackToPool(Stack, STACK_SIZE);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_t Thread;
|
||||
FEXCore::Threads::ThreadFunc UserFunc;
|
||||
void *UserArg;
|
||||
void *Stack{};
|
||||
constexpr static size_t STACK_SIZE = 8 * 1024 * 1024;
|
||||
};
|
||||
|
||||
void *InitializeThread(void *Ptr) {
|
||||
PThread *Thread{reinterpret_cast<PThread*>(Ptr)};
|
||||
|
||||
// Run the user function
|
||||
void *Result = Thread->Execute();
|
||||
|
||||
// Put the stack back in to the stack pool
|
||||
Thread->FreeStack();
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::unique_ptr<FEXCore::Threads::Thread> CreateThread_PThread(
|
||||
ThreadFunc Func,
|
||||
void* Arg) {
|
||||
|
||||
+21
-20
@@ -54,15 +54,15 @@ namespace Type {
|
||||
#undef P
|
||||
}
|
||||
|
||||
std::string GetDataDirectory();
|
||||
std::string GetConfigDirectory(bool Global);
|
||||
std::string GetConfigFileLocation();
|
||||
std::string GetApplicationConfig(std::string &Filename, bool Global);
|
||||
__attribute__((visibility("default"))) std::string GetDataDirectory();
|
||||
__attribute__((visibility("default"))) std::string GetConfigDirectory(bool Global);
|
||||
__attribute__((visibility("default"))) std::string GetConfigFileLocation();
|
||||
__attribute__((visibility("default"))) std::string GetApplicationConfig(std::string &Filename, bool Global);
|
||||
|
||||
using LayerValue = std::list<std::string>;
|
||||
using LayerOptions = std::unordered_map<ConfigOption, LayerValue>;
|
||||
|
||||
class Layer {
|
||||
class __attribute__((visibility("default"))) Layer {
|
||||
public:
|
||||
explicit Layer(const LayerType _Type);
|
||||
virtual ~Layer();
|
||||
@@ -102,35 +102,36 @@ namespace Type {
|
||||
OptionMap[Option].emplace_back(Data);
|
||||
}
|
||||
|
||||
void Erase(ConfigOption Option) {
|
||||
OptionMap.erase(Option);
|
||||
}
|
||||
|
||||
const LayerType GetLayerType() const { return Type; }
|
||||
const LayerOptions &GetOptionMap() { return OptionMap; }
|
||||
|
||||
protected:
|
||||
const LayerType Type;
|
||||
LayerOptions OptionMap;
|
||||
|
||||
void Erase(ConfigOption Option) {
|
||||
OptionMap.erase(Option);
|
||||
}
|
||||
};
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
__attribute__((visibility("default"))) void Initialize();
|
||||
__attribute__((visibility("default"))) void Shutdown();
|
||||
|
||||
void Load();
|
||||
void ReloadMetaLayer();
|
||||
__attribute__((visibility("default"))) void Load();
|
||||
__attribute__((visibility("default"))) void ReloadMetaLayer();
|
||||
|
||||
void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer);
|
||||
__attribute__((visibility("default"))) void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer);
|
||||
|
||||
bool Exists(ConfigOption Option);
|
||||
std::optional<LayerValue*> All(ConfigOption Option);
|
||||
std::optional<std::string*> Get(ConfigOption Option);
|
||||
__attribute__((visibility("default"))) bool Exists(ConfigOption Option);
|
||||
__attribute__((visibility("default"))) std::optional<LayerValue*> All(ConfigOption Option);
|
||||
__attribute__((visibility("default"))) std::optional<std::string*> Get(ConfigOption Option);
|
||||
|
||||
void Set(ConfigOption Option, std::string Data);
|
||||
void EraseSet(ConfigOption Option, std::string Data);
|
||||
__attribute__((visibility("default"))) void Set(ConfigOption Option, std::string Data);
|
||||
__attribute__((visibility("default"))) void Erase(ConfigOption Option);
|
||||
__attribute__((visibility("default"))) void EraseSet(ConfigOption Option, std::string Data);
|
||||
|
||||
template<typename T>
|
||||
class Value {
|
||||
class __attribute__((visibility("default"))) Value {
|
||||
public:
|
||||
template <typename TT = T,
|
||||
typename std::enable_if<!std::is_same<TT, std::string>::value, int>::type = 0>
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class LLVMCore;
|
||||
* @return An executable function pointer that is theoretically compiled from this point.
|
||||
* Is actually a function pointer of type `void (FEXCore::Core::ThreadState *Thread)
|
||||
*/
|
||||
virtual void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) = 0;
|
||||
virtual void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) = 0;
|
||||
|
||||
/**
|
||||
* @brief Function for mapping memory in to the CPUBackend's visible space. Allows setting up virtual mappings if required
|
||||
|
||||
+7
-36
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FEXCore {
|
||||
@@ -20,53 +21,23 @@ public:
|
||||
* @brief CPU Core uses this to choose what the stack size should be for this code
|
||||
*/
|
||||
virtual uint64_t StackSize() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Allows the code loader to set up the stack the way it wants
|
||||
*
|
||||
* @param HostPtr The host facing pointer to the base of the stack.
|
||||
* Size of memory will be at least the size that StackSize() returns
|
||||
*
|
||||
* @param GuestPtr The guest facing memory location where the base of the stack lives
|
||||
*
|
||||
* @return The location that the guest stack pointer register should be set to
|
||||
*
|
||||
* Probably will be GuestPtr + StackSize() - <Some amount>
|
||||
* Returns the initial stack pointer
|
||||
*/
|
||||
virtual uint64_t SetupStack() = 0;
|
||||
virtual uint64_t GetStackPointer() = 0;
|
||||
|
||||
/**
|
||||
* @brief Function to return the guest RIP that the code should start out at
|
||||
*/
|
||||
virtual uint64_t DefaultRIP() const = 0;
|
||||
|
||||
virtual void GetInitLocations(std::vector<uint64_t> *Locations) {}
|
||||
|
||||
/**
|
||||
* @brief Allows the loader to map memory regions that it needs
|
||||
*
|
||||
* Code loader is expected to call the Mapper function with a memory offset and size for mapping
|
||||
*
|
||||
* @param Mapper Returns the host facing pointer for memory setup if the codfe loader needs to do things to it
|
||||
* @brief Maps and copies the executable, also sets up stack
|
||||
*/
|
||||
virtual void MapMemoryRegion() {}
|
||||
virtual bool MapMemory(std::function<void *(void *addr, size_t length, int prot, int flags, int fd, off_t offset)> Mapper, std::function<int(void *addr, size_t length)> Unmapper) { return false; }
|
||||
|
||||
/**
|
||||
* @brief Memory writer function for loading code in to guest memory
|
||||
*
|
||||
* First argument = Data to write
|
||||
* Second argument = Guest memory data location
|
||||
* Third argument = Guest memory size
|
||||
*/
|
||||
virtual void LoadMemory() = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the final RIP we are supposed to end up on in a debugger
|
||||
*
|
||||
* @return When the debugger reaches this RIP then we know that we have completed
|
||||
*/
|
||||
virtual uint64_t GetFinalRIP() { return ~0ULL; }
|
||||
|
||||
virtual char const *FindSymbolNameInRange(uint64_t Address) { return nullptr; }
|
||||
virtual std::vector<std::string> const *GetApplicationArguments() { return nullptr; }
|
||||
virtual void GetExecveArguments(std::vector<char const*> *Args) {}
|
||||
|
||||
virtual void GetAuxv(uint64_t& addr, uint64_t& size) {}
|
||||
|
||||
+43
-37
@@ -9,6 +9,7 @@
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace FEXCore {
|
||||
class CodeLoader;
|
||||
@@ -49,7 +50,7 @@ namespace FEXCore::Context {
|
||||
/**
|
||||
* @brief This initializes internal FEXCore state that is shared between contexts and requires overhead to setup
|
||||
*/
|
||||
void InitializeStaticTables(OperatingMode Mode = MODE_64BIT);
|
||||
__attribute__((visibility("default"))) void InitializeStaticTables(OperatingMode Mode = MODE_64BIT);
|
||||
|
||||
/**
|
||||
* @brief [[threadsafe]] Create a new FEXCore context object
|
||||
@@ -58,7 +59,7 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return a new context object
|
||||
*/
|
||||
FEXCore::Context::Context *CreateNewContext();
|
||||
__attribute__((visibility("default"))) FEXCore::Context::Context *CreateNewContext();
|
||||
|
||||
/**
|
||||
* @brief Post creation context initialization
|
||||
@@ -68,14 +69,14 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return true if we managed to initialize correctly
|
||||
*/
|
||||
bool InitializeContext(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) bool InitializeContext(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Destroy the context object
|
||||
*
|
||||
* @param CTX
|
||||
*/
|
||||
void DestroyContext(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) void DestroyContext(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Allows setting up in memory code and other things prior to launchign code execution
|
||||
@@ -85,17 +86,17 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return true if we loaded code
|
||||
*/
|
||||
bool InitCore(FEXCore::Context::Context *CTX, FEXCore::CodeLoader *Loader);
|
||||
__attribute__((visibility("default"))) bool InitCore(FEXCore::Context::Context *CTX, FEXCore::CodeLoader *Loader);
|
||||
|
||||
void SetExitHandler(FEXCore::Context::Context *CTX, std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> handler);
|
||||
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> GetExitHandler(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) void SetExitHandler(FEXCore::Context::Context *CTX, std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> handler);
|
||||
__attribute__((visibility("default"))) std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> GetExitHandler(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Pauses execution on the CPU core
|
||||
*
|
||||
* Blocks until all threads have paused.
|
||||
*/
|
||||
void Pause(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) void Pause(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Starts (or continues) the CPU core
|
||||
@@ -104,7 +105,7 @@ namespace FEXCore::Context {
|
||||
* Use RunUntilExit() for synchonous executions
|
||||
*
|
||||
*/
|
||||
void Run(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) void Run(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Runs the CPU core until it exits
|
||||
@@ -116,7 +117,9 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return The ExitReason for the parentthread.
|
||||
*/
|
||||
ExitReason RunUntilExit(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) ExitReason RunUntilExit(FEXCore::Context::Context *CTX);
|
||||
|
||||
__attribute__((visibility("default"))) void CompileRIP(FEXCore::Context::Context *CTX, uint64_t GuestRIP);
|
||||
|
||||
/**
|
||||
* @brief Gets the program exit status
|
||||
@@ -126,21 +129,21 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return The program exit status
|
||||
*/
|
||||
int GetProgramStatus(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) int GetProgramStatus(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Tells the core to shutdown
|
||||
*
|
||||
* Blocks until shutdown
|
||||
*/
|
||||
void Stop(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) void Stop(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Executes one instruction
|
||||
*
|
||||
* Returns once execution is complete.
|
||||
*/
|
||||
void Step(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) void Step(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief [[threadsafe]] Returns the ExitReason of the parent thread. Typically used for async result status
|
||||
@@ -149,7 +152,7 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return The ExitReason for the parentthread
|
||||
*/
|
||||
ExitReason GetExitReason(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) ExitReason GetExitReason(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief [[theadsafe]] Checks if the Context is either done working or paused(in the case of single stepping)
|
||||
@@ -160,7 +163,7 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return true if the core is done or paused
|
||||
*/
|
||||
bool IsDone(FEXCore::Context::Context *CTX);
|
||||
__attribute__((visibility("default"))) bool IsDone(FEXCore::Context::Context *CTX);
|
||||
|
||||
/**
|
||||
* @brief Gets a copy the CPUState of the parent thread
|
||||
@@ -168,7 +171,7 @@ namespace FEXCore::Context {
|
||||
* @param CTX The context that we created
|
||||
* @param State The state object to populate
|
||||
*/
|
||||
void GetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
|
||||
__attribute__((visibility("default"))) void GetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
|
||||
|
||||
/**
|
||||
* @brief Copies the CPUState provided to the parent thread
|
||||
@@ -176,7 +179,7 @@ namespace FEXCore::Context {
|
||||
* @param CTX The context that we created
|
||||
* @param State The satate object to copy from
|
||||
*/
|
||||
void SetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
|
||||
__attribute__((visibility("default"))) void SetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
|
||||
|
||||
/**
|
||||
* @brief Allows the frontend to pass in a custom CPUBackend creation factory
|
||||
@@ -186,7 +189,7 @@ namespace FEXCore::Context {
|
||||
* @param CTX The context that we created
|
||||
* @param Factory The factory that the context will call if the DefaultCore config ise set to CUSTOM
|
||||
*/
|
||||
void SetCustomCPUBackendFactory(FEXCore::Context::Context *CTX, CustomCPUFactoryType Factory);
|
||||
__attribute__((visibility("default"))) void SetCustomCPUBackendFactory(FEXCore::Context::Context *CTX, CustomCPUFactoryType Factory);
|
||||
|
||||
/**
|
||||
* @brief Sets up memory regions on the guest for mirroring within the guest's VM space
|
||||
@@ -197,7 +200,7 @@ namespace FEXCore::Context {
|
||||
*
|
||||
* @return true when successfully mapped. false if there was an error adding
|
||||
*/
|
||||
bool AddVirtualMemoryMapping(FEXCore::Context::Context *CTX, uint64_t VirtualAddress, uint64_t PhysicalAddress, uint64_t Size);
|
||||
__attribute__((visibility("default"))) bool AddVirtualMemoryMapping(FEXCore::Context::Context *CTX, uint64_t VirtualAddress, uint64_t PhysicalAddress, uint64_t Size);
|
||||
|
||||
/**
|
||||
* @brief Allows the frontend to set a custom syscall handler
|
||||
@@ -207,26 +210,29 @@ namespace FEXCore::Context {
|
||||
* @param Syscall Which syscall ID to install a visitor to
|
||||
* @param Visitor The Visitor to install
|
||||
*/
|
||||
void RegisterExternalSyscallVisitor(FEXCore::Context::Context *CTX, uint64_t Syscall, FEXCore::HLE::SyscallVisitor *Visitor);
|
||||
__attribute__((visibility("default"))) void RegisterExternalSyscallVisitor(FEXCore::Context::Context *CTX, uint64_t Syscall, FEXCore::HLE::SyscallVisitor *Visitor);
|
||||
|
||||
void HandleCallback(FEXCore::Context::Context *CTX, uint64_t RIP);
|
||||
__attribute__((visibility("default"))) void HandleCallback(FEXCore::Context::Context *CTX, uint64_t RIP);
|
||||
|
||||
void RegisterHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
|
||||
void RegisterFrontendHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
|
||||
__attribute__((visibility("default"))) void RegisterHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
|
||||
__attribute__((visibility("default"))) void RegisterFrontendHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
|
||||
|
||||
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
|
||||
void InitializeThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void RunThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void StopThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void DestroyThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void CleanupAfterFork(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
|
||||
void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
|
||||
FEXCore::CPUID::FunctionResults RunCPUIDFunction(FEXCore::Context::Context *CTX, uint32_t Function, uint32_t Leaf);
|
||||
__attribute__((visibility("default"))) FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
|
||||
__attribute__((visibility("default"))) void InitializeThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
__attribute__((visibility("default"))) void RunThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
__attribute__((visibility("default"))) void StopThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
__attribute__((visibility("default"))) void DestroyThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
__attribute__((visibility("default"))) void CleanupAfterFork(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
|
||||
__attribute__((visibility("default"))) void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
|
||||
__attribute__((visibility("default"))) void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
|
||||
__attribute__((visibility("default"))) FEXCore::CPUID::FunctionResults RunCPUIDFunction(FEXCore::Context::Context *CTX, uint32_t Function, uint32_t Leaf);
|
||||
|
||||
void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name);
|
||||
void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
|
||||
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader);
|
||||
bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
|
||||
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
|
||||
__attribute__((visibility("default"))) void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name);
|
||||
__attribute__((visibility("default"))) void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
|
||||
__attribute__((visibility("default"))) void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<int(const std::string&)> CacheReader);
|
||||
__attribute__((visibility("default"))) bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
|
||||
__attribute__((visibility("default"))) void WriteFilesWithCode(FEXCore::Context::Context *CTX, std::function<void(const std::string& fileid, const std::string& filename)> Writer);
|
||||
__attribute__((visibility("default"))) void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
|
||||
|
||||
__attribute__((visibility("default"))) void ConfigureAOTGen(FEXCore::Context::Context *CTX, std::set<uint64_t> *ExternalBranches, uint64_t SectionMaxAddress);
|
||||
}
|
||||
+2
-2
@@ -51,6 +51,6 @@ namespace FEXCore::Core {
|
||||
|
||||
constexpr uint64_t PAGE_SIZE = 4096;
|
||||
|
||||
std::string_view const& GetFlagName(unsigned Flag);
|
||||
std::string_view const& GetGRegName(unsigned Reg);
|
||||
__attribute__((visibility("default"))) std::string_view const& GetFlagName(unsigned Flag);
|
||||
__attribute__((visibility("default"))) std::string_view const& GetGRegName(unsigned Reg);
|
||||
}
|
||||
+18
-18
@@ -455,29 +455,29 @@ constexpr size_t MAX_XOP_GROUP_TABLE_SIZE = (1 << 6);
|
||||
|
||||
constexpr size_t MAX_EVEX_TABLE_SIZE = 256;
|
||||
|
||||
extern X86InstInfo BaseOps[MAX_PRIMARY_TABLE_SIZE];
|
||||
extern X86InstInfo SecondBaseOps[MAX_SECOND_TABLE_SIZE];
|
||||
extern X86InstInfo RepModOps[MAX_REP_MOD_TABLE_SIZE];
|
||||
extern X86InstInfo RepNEModOps[MAX_REPNE_MOD_TABLE_SIZE];
|
||||
extern X86InstInfo OpSizeModOps[MAX_OPSIZE_MOD_TABLE_SIZE];
|
||||
extern X86InstInfo PrimaryInstGroupOps[MAX_INST_GROUP_TABLE_SIZE];
|
||||
extern X86InstInfo SecondInstGroupOps[MAX_INST_SECOND_GROUP_TABLE_SIZE];
|
||||
extern X86InstInfo SecondModRMTableOps[MAX_SECOND_MODRM_TABLE_SIZE];
|
||||
extern X86InstInfo X87Ops[MAX_X87_TABLE_SIZE];
|
||||
extern X86InstInfo DDDNowOps[MAX_3DNOW_TABLE_SIZE];
|
||||
extern X86InstInfo H0F38TableOps[MAX_0F_38_TABLE_SIZE];
|
||||
extern X86InstInfo H0F3ATableOps[MAX_0F_3A_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo BaseOps[MAX_PRIMARY_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo SecondBaseOps[MAX_SECOND_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo RepModOps[MAX_REP_MOD_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo RepNEModOps[MAX_REPNE_MOD_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo OpSizeModOps[MAX_OPSIZE_MOD_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo PrimaryInstGroupOps[MAX_INST_GROUP_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo SecondInstGroupOps[MAX_INST_SECOND_GROUP_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo SecondModRMTableOps[MAX_SECOND_MODRM_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo X87Ops[MAX_X87_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo DDDNowOps[MAX_3DNOW_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo H0F38TableOps[MAX_0F_38_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo H0F3ATableOps[MAX_0F_3A_TABLE_SIZE];
|
||||
|
||||
// VEX
|
||||
extern X86InstInfo VEXTableOps[MAX_VEX_TABLE_SIZE];
|
||||
extern X86InstInfo VEXTableGroupOps[MAX_VEX_GROUP_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo VEXTableOps[MAX_VEX_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo VEXTableGroupOps[MAX_VEX_GROUP_TABLE_SIZE];
|
||||
|
||||
// XOP
|
||||
extern X86InstInfo XOPTableOps[MAX_XOP_TABLE_SIZE];
|
||||
extern X86InstInfo XOPTableGroupOps[MAX_XOP_GROUP_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo XOPTableOps[MAX_XOP_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo XOPTableGroupOps[MAX_XOP_GROUP_TABLE_SIZE];
|
||||
|
||||
// EVEX
|
||||
extern X86InstInfo EVEXTableOps[MAX_EVEX_TABLE_SIZE];
|
||||
extern __attribute__((visibility("default"))) X86InstInfo EVEXTableOps[MAX_EVEX_TABLE_SIZE];
|
||||
|
||||
void InitializeInfoTables(Context::OperatingMode Mode);
|
||||
__attribute__((visibility("default"))) void InitializeInfoTables(Context::OperatingMode Mode);
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FEXCore::HLE {
|
||||
#define INVALID_OP { LogMan::Msg::A("Tried to syscall with unknown number of registers"); return 0; }
|
||||
#define INVALID_OP { LOGMAN_MSG_A("Tried to syscall with unknown number of registers"); return 0; }
|
||||
class SyscallVisitor {
|
||||
public:
|
||||
SyscallVisitor(uint32_t Mask) : SyscallVisitor(Mask, false) {}
|
||||
|
||||
+2
-4
@@ -240,13 +240,11 @@ class OrderedNode final {
|
||||
}
|
||||
|
||||
static void SetPrevious(uintptr_t Base, value_type Node, value_type New) {
|
||||
if (Node.NodeOffset == 0) return;
|
||||
OrderedNode *RealNode = Node.GetNode(Base);
|
||||
RealNode->Header.Previous = New;
|
||||
}
|
||||
|
||||
static void SetNext(uintptr_t Base, value_type Node, value_type New) {
|
||||
if (Node.NodeOffset == 0) return;
|
||||
OrderedNode *RealNode = Node.GetNode(Base);
|
||||
RealNode->Header.Next = New;
|
||||
}
|
||||
@@ -465,8 +463,8 @@ public:
|
||||
class IRListView;
|
||||
class IREmitter;
|
||||
|
||||
void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData);
|
||||
IREmitter* Parse(std::istream *in);
|
||||
__attribute__((visibility("default"))) void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData);
|
||||
__attribute__((visibility("default"))) IREmitter* Parse(std::istream *in);
|
||||
|
||||
template<typename Type>
|
||||
inline uint32_t NodeWrapperBase<Type>::ID() const { return NodeOffset / sizeof(IR::OrderedNode); }
|
||||
|
||||
+63
-66
@@ -16,13 +16,12 @@ friend class FEXCore::IR::PassManager;
|
||||
|
||||
public:
|
||||
IREmitter()
|
||||
: Data {8 * 1024 * 1024}
|
||||
, ListData {8 * 1024 * 1024} {
|
||||
: DualListData {8 * 1024 * 1024} {
|
||||
ResetWorkingList();
|
||||
}
|
||||
|
||||
IRListView ViewIR() { return IRListView(&Data, &ListData, false); }
|
||||
IRListView *CreateIRCopy() { return new IRListView(&Data, &ListData, true); }
|
||||
IRListView ViewIR() { return IRListView(&DualListData, false); }
|
||||
IRListView *CreateIRCopy() { return new IRListView(&DualListData, true); }
|
||||
void ResetWorkingList();
|
||||
|
||||
/**
|
||||
@@ -54,7 +53,7 @@ friend class FEXCore::IR::PassManager;
|
||||
Op.first->Header.ElementSize = ElementSize;
|
||||
Op.first->Header.NumArgs = 1;
|
||||
Op.first->Header.HasDest = true;
|
||||
Op.first->Header.Args[0] = ssa0->Wrapped(ListData.Begin());
|
||||
Op.first->Header.Args[0] = ssa0->Wrapped(DualListData.ListBegin());
|
||||
ssa0->AddUse();
|
||||
return Op;
|
||||
}
|
||||
@@ -364,72 +363,72 @@ friend class FEXCore::IR::PassManager;
|
||||
void AddPhiValue(IR::IROp_Phi *Phi, OrderedNode *Value) {
|
||||
// Got to do some bookkeeping first
|
||||
Value->AddUse();
|
||||
auto ValueIROp = Value->Op(Data.Begin())->C<IR::IROp_PhiValue>()->Value.GetNode(ListData.Begin())->Op(Data.Begin());
|
||||
auto ValueIROp = Value->Op(DualListData.DataBegin())->C<IR::IROp_PhiValue>()->Value.GetNode(DualListData.ListBegin())->Op(DualListData.DataBegin());
|
||||
Phi->Header.Size = ValueIROp->Size;
|
||||
Phi->Header.ElementSize = ValueIROp->ElementSize;
|
||||
|
||||
if (!Phi->PhiBegin.ID()) {
|
||||
Phi->PhiBegin = Phi->PhiEnd = Value->Wrapped(ListData.Begin());
|
||||
Phi->PhiBegin = Phi->PhiEnd = Value->Wrapped(DualListData.ListBegin());
|
||||
return;
|
||||
}
|
||||
auto PhiValueEndNode = Phi->PhiEnd.GetNode(ListData.Begin());
|
||||
auto PhiValueEndOp = PhiValueEndNode->Op(Data.Begin())->CW<IR::IROp_PhiValue>();
|
||||
PhiValueEndOp->Next = Value->Wrapped(ListData.Begin());
|
||||
auto PhiValueEndNode = Phi->PhiEnd.GetNode(DualListData.ListBegin());
|
||||
auto PhiValueEndOp = PhiValueEndNode->Op(DualListData.DataBegin())->CW<IR::IROp_PhiValue>();
|
||||
PhiValueEndOp->Next = Value->Wrapped(DualListData.ListBegin());
|
||||
}
|
||||
|
||||
void SetJumpTarget(IR::IROp_Jump *Op, OrderedNode *Target) {
|
||||
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
|
||||
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
|
||||
"Tried setting Jump target to %%ssa%d %s",
|
||||
Target->Wrapped(ListData.Begin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
|
||||
Target->Wrapped(DualListData.ListBegin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
|
||||
Op->Header.Args[0].NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
|
||||
Op->Header.Args[0].NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
|
||||
}
|
||||
void SetTrueJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) {
|
||||
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
|
||||
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
|
||||
"Tried setting CondJump target to %%ssa%d %s",
|
||||
Target->Wrapped(ListData.Begin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
|
||||
Target->Wrapped(DualListData.ListBegin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
|
||||
Op->TrueBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
|
||||
Op->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
|
||||
}
|
||||
void SetFalseJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) {
|
||||
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
|
||||
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
|
||||
"Tried setting CondJump target to %%ssa%d %s",
|
||||
Target->Wrapped(ListData.Begin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
|
||||
Target->Wrapped(DualListData.ListBegin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
|
||||
Op->FalseBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
|
||||
Op->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
|
||||
}
|
||||
|
||||
void SetJumpTarget(IRPair<IROp_Jump> Op, OrderedNode *Target) {
|
||||
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
|
||||
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
|
||||
"Tried setting Jump target to %%ssa%d %s",
|
||||
Target->Wrapped(ListData.Begin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
|
||||
Target->Wrapped(DualListData.ListBegin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
|
||||
Op.first->Header.Args[0].NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
|
||||
Op.first->Header.Args[0].NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
|
||||
}
|
||||
void SetTrueJumpTarget(IRPair<IROp_CondJump> Op, OrderedNode *Target) {
|
||||
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
|
||||
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
|
||||
"Tried setting CondJump target to %%ssa%d %s",
|
||||
Target->Wrapped(ListData.Begin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
|
||||
Op.first->TrueBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
|
||||
Target->Wrapped(DualListData.ListBegin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
Op.first->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
|
||||
}
|
||||
void SetFalseJumpTarget(IRPair<IROp_CondJump> Op, OrderedNode *Target) {
|
||||
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
|
||||
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
|
||||
"Tried setting CondJump target to %%ssa%d %s",
|
||||
Target->Wrapped(ListData.Begin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
|
||||
Op.first->FalseBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
|
||||
Target->Wrapped(DualListData.ListBegin()).ID(),
|
||||
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
|
||||
Op.first->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
bool IsValueConstant(OrderedNodeWrapper ssa, uint64_t *Constant = nullptr) {
|
||||
OrderedNode *RealNode = ssa.GetNode(ListData.Begin());
|
||||
FEXCore::IR::IROp_Header *IROp = RealNode->Op(Data.Begin());
|
||||
OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin());
|
||||
FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin());
|
||||
if (IROp->Op == OP_CONSTANT) {
|
||||
auto Op = IROp->C<IR::IROp_Constant>();
|
||||
if (Constant) *Constant = Op->Constant;
|
||||
@@ -439,8 +438,8 @@ friend class FEXCore::IR::PassManager;
|
||||
}
|
||||
|
||||
bool IsValueInlineConstant(OrderedNodeWrapper ssa) {
|
||||
OrderedNode *RealNode = ssa.GetNode(ListData.Begin());
|
||||
FEXCore::IR::IROp_Header *IROp = RealNode->Op(Data.Begin());
|
||||
OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin());
|
||||
FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin());
|
||||
if (IROp->Op == OP_INLINECONSTANT) {
|
||||
return true;
|
||||
}
|
||||
@@ -448,20 +447,20 @@ friend class FEXCore::IR::PassManager;
|
||||
}
|
||||
|
||||
FEXCore::IR::IROp_Header *GetOpHeader(OrderedNodeWrapper ssa) {
|
||||
OrderedNode *RealNode = ssa.GetNode(ListData.Begin());
|
||||
return RealNode->Op(Data.Begin());
|
||||
OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin());
|
||||
return RealNode->Op(DualListData.DataBegin());
|
||||
}
|
||||
|
||||
OrderedNode *UnwrapNode(OrderedNodeWrapper ssa) {
|
||||
return ssa.GetNode(ListData.Begin());
|
||||
return ssa.GetNode(DualListData.ListBegin());
|
||||
}
|
||||
|
||||
OrderedNodeWrapper WrapNode(OrderedNode *node) {
|
||||
return node->Wrapped(ListData.Begin());
|
||||
return node->Wrapped(DualListData.ListBegin());
|
||||
}
|
||||
|
||||
NodeIterator GetIterator(OrderedNodeWrapper wrapper) {
|
||||
return NodeIterator(ListData.Begin(), Data.Begin(), wrapper);
|
||||
return NodeIterator(DualListData.ListBegin(), DualListData.DataBegin(), wrapper);
|
||||
}
|
||||
|
||||
// Overwrite a node with a constant
|
||||
@@ -472,22 +471,22 @@ friend class FEXCore::IR::PassManager;
|
||||
void ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End);
|
||||
|
||||
void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After) {
|
||||
ReplaceAllUsesWithRange(Node, NewNode, After, AllNodesIterator(ListData.Begin(), Data.Begin()));
|
||||
ReplaceAllUsesWithRange(Node, NewNode, After, AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin()));
|
||||
}
|
||||
|
||||
void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, OrderedNode *After) {
|
||||
auto Wrapped = Node->Wrapped(ListData.Begin());
|
||||
AllNodesIterator It = AllNodesIterator(ListData.Begin(), Data.Begin(), Wrapped);
|
||||
auto Wrapped = Node->Wrapped(DualListData.ListBegin());
|
||||
AllNodesIterator It = AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin(), Wrapped);
|
||||
|
||||
ReplaceUsesWithAfter(Node, NewNode, It);
|
||||
}
|
||||
|
||||
void ReplaceAllUsesWith(OrderedNode *Node, OrderedNode *NewNode) {
|
||||
auto Start = AllNodesIterator(ListData.Begin(), Data.Begin(), Node->Wrapped(ListData.Begin()));
|
||||
auto Start = AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin(), Node->Wrapped(DualListData.ListBegin()));
|
||||
|
||||
ReplaceUsesWithAfter(Node, NewNode, Start);
|
||||
|
||||
LogMan::Throw::A(Node->NumUses == 0, "Node still used");
|
||||
LOGMAN_THROW_A(Node->NumUses == 0, "Node still used");
|
||||
|
||||
// Since we have deleted ALL uses, we can safely delete the node.
|
||||
Remove(Node);
|
||||
@@ -501,15 +500,14 @@ friend class FEXCore::IR::PassManager;
|
||||
OrderedNode *GetPackedRFLAG(bool Lower8);
|
||||
|
||||
void CopyData(IREmitter const &rhs) {
|
||||
LogMan::Throw::A(rhs.Data.BackingSize() <= Data.BackingSize(), "Trying to take ownership of data that is too large");
|
||||
LogMan::Throw::A(rhs.ListData.BackingSize() <= ListData.BackingSize(), "Trying to take ownership of data that is too large");
|
||||
Data.CopyData(rhs.Data);
|
||||
ListData.CopyData(rhs.ListData);
|
||||
InvalidNode = rhs.InvalidNode->Wrapped(rhs.ListData.Begin()).GetNode(ListData.Begin());
|
||||
LOGMAN_THROW_A(rhs.DualListData.DataBackingSize() <= DualListData.DataBackingSize(), "Trying to take ownership of data that is too large");
|
||||
LOGMAN_THROW_A(rhs.DualListData.ListBackingSize() <= DualListData.ListBackingSize(), "Trying to take ownership of data that is too large");
|
||||
DualListData.CopyData(rhs.DualListData);
|
||||
InvalidNode = rhs.InvalidNode->Wrapped(rhs.DualListData.ListBegin()).GetNode(DualListData.ListBegin());
|
||||
CurrentWriteCursor = rhs.CurrentWriteCursor;
|
||||
CodeBlocks = rhs.CodeBlocks;
|
||||
for (auto& CodeBlock: CodeBlocks) {
|
||||
CodeBlock = CodeBlock->Wrapped(rhs.ListData.Begin()).GetNode(ListData.Begin());
|
||||
CodeBlock = CodeBlock->Wrapped(rhs.DualListData.ListBegin()).GetNode(DualListData.ListBegin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,10 +542,10 @@ friend class FEXCore::IR::PassManager;
|
||||
SetWriteCursor(nullptr);// Orphan from any future nodes
|
||||
|
||||
auto Begin = _BeginBlock(CodeNode);
|
||||
CodeNode.first->Begin = Begin.Node->Wrapped(ListData.Begin());
|
||||
CodeNode.first->Begin = Begin.Node->Wrapped(DualListData.ListBegin());
|
||||
|
||||
auto EndBlock = _EndBlock(CodeNode);
|
||||
CodeNode.first->Last = EndBlock.Node->Wrapped(ListData.Begin());
|
||||
CodeNode.first->Last = EndBlock.Node->Wrapped(DualListData.ListBegin());
|
||||
|
||||
return CodeNode;
|
||||
}
|
||||
@@ -564,10 +562,10 @@ friend class FEXCore::IR::PassManager;
|
||||
* @{ */
|
||||
/** @} */
|
||||
void LinkCodeBlocks(OrderedNode *CodeNode, OrderedNode *Next) {
|
||||
FEXCore::IR::IROp_CodeBlock *CurrentIROp = CodeNode->Op(Data.Begin())->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
LogMan::Throw::A(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid");
|
||||
FEXCore::IR::IROp_CodeBlock *CurrentIROp = CodeNode->Op(DualListData.DataBegin())->CW<FEXCore::IR::IROp_CodeBlock>();
|
||||
LOGMAN_THROW_A(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid");
|
||||
|
||||
CodeNode->append(ListData.Begin(), Next);
|
||||
CodeNode->append(DualListData.ListBegin(), Next);
|
||||
}
|
||||
|
||||
IRPair<IROp_CodeBlock> CreateNewCodeBlockAtEnd() { return CreateNewCodeBlockAfter(nullptr); }
|
||||
@@ -578,11 +576,11 @@ friend class FEXCore::IR::PassManager;
|
||||
void RemoveArgUses(OrderedNode *Node);
|
||||
|
||||
OrderedNode *CreateNode(IROp_Header *Op) {
|
||||
uintptr_t ListBegin = ListData.Begin();
|
||||
uintptr_t ListBegin = DualListData.ListBegin();
|
||||
size_t Size = sizeof(OrderedNode);
|
||||
void *Ptr = ListData.Allocate(Size);
|
||||
void *Ptr = DualListData.ListAllocate(Size);
|
||||
OrderedNode *Node = new (Ptr) OrderedNode();
|
||||
Node->Header.Value.SetOffset(Data.Begin(), reinterpret_cast<uintptr_t>(Op));
|
||||
Node->Header.Value.SetOffset(DualListData.DataBegin(), reinterpret_cast<uintptr_t>(Op));
|
||||
|
||||
if (CurrentWriteCursor) {
|
||||
CurrentWriteCursor->append(ListBegin, Node);
|
||||
@@ -592,14 +590,14 @@ friend class FEXCore::IR::PassManager;
|
||||
}
|
||||
|
||||
OrderedNode *GetNode(uint32_t SSANode) {
|
||||
uintptr_t ListBegin = ListData.Begin();
|
||||
uintptr_t ListBegin = DualListData.ListBegin();
|
||||
OrderedNode *Node = reinterpret_cast<OrderedNode *>(ListBegin + SSANode * sizeof(OrderedNode));
|
||||
return Node;
|
||||
}
|
||||
|
||||
OrderedNode *EmplaceOrphanedNode(OrderedNode *OldNode) {
|
||||
size_t Size = sizeof(OrderedNode);
|
||||
OrderedNode *Ptr = reinterpret_cast<OrderedNode*>(ListData.Allocate(Size));
|
||||
OrderedNode *Ptr = reinterpret_cast<OrderedNode*>(DualListData.ListAllocate(Size));
|
||||
memcpy(Ptr, OldNode, Size);
|
||||
return Ptr;
|
||||
}
|
||||
@@ -607,8 +605,7 @@ friend class FEXCore::IR::PassManager;
|
||||
OrderedNode *CurrentWriteCursor = nullptr;
|
||||
|
||||
// These could be combined with a little bit of work to be more efficient with memory usage. Isn't a big deal
|
||||
IntrusiveAllocator Data;
|
||||
IntrusiveAllocator ListData;
|
||||
DualIntrusiveAllocator DualListData;
|
||||
|
||||
OrderedNode *InvalidNode;
|
||||
OrderedNode *CurrentCodeBlock{};
|
||||
|
||||
+120
-72
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "FEXCore/IR/IR.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
#include <cassert>
|
||||
@@ -19,121 +20,161 @@ namespace FEXCore::IR {
|
||||
*
|
||||
* Can potentially support reallocation if we are smart and make sure to invalidate anything holding a true pointer
|
||||
*/
|
||||
class IntrusiveAllocator final {
|
||||
class DualIntrusiveAllocator final {
|
||||
public:
|
||||
IntrusiveAllocator() = delete;
|
||||
IntrusiveAllocator(IntrusiveAllocator &&) = delete;
|
||||
IntrusiveAllocator(size_t Size)
|
||||
DualIntrusiveAllocator() = delete;
|
||||
DualIntrusiveAllocator(DualIntrusiveAllocator &&) = delete;
|
||||
DualIntrusiveAllocator(size_t Size)
|
||||
: MemorySize {Size} {
|
||||
Data = reinterpret_cast<uintptr_t>(malloc(Size));
|
||||
Data = reinterpret_cast<uintptr_t>(FEXCore::Allocator::malloc(Size * 2));
|
||||
List = reinterpret_cast<uintptr_t>(Data + Size);
|
||||
}
|
||||
|
||||
~IntrusiveAllocator() {
|
||||
free(reinterpret_cast<void*>(Data));
|
||||
|
||||
~DualIntrusiveAllocator() {
|
||||
FEXCore::Allocator::free(reinterpret_cast<void*>(Data));
|
||||
}
|
||||
|
||||
bool CheckSize(size_t Size) {
|
||||
size_t NewOffset = CurrentOffset + Size;
|
||||
bool DataCheckSize(size_t Size) {
|
||||
size_t NewOffset = DataCurrentOffset + Size;
|
||||
return NewOffset <= MemorySize;
|
||||
}
|
||||
|
||||
void *Allocate(size_t Size) {
|
||||
assert(CheckSize(Size) &&
|
||||
"Ran out of space in IntrusiveAllocator during allocation");
|
||||
size_t NewOffset = CurrentOffset + Size;
|
||||
uintptr_t NewPointer = Data + CurrentOffset;
|
||||
CurrentOffset = NewOffset;
|
||||
bool ListCheckSize(size_t Size) {
|
||||
size_t NewOffset = ListCurrentOffset + Size;
|
||||
return NewOffset <= MemorySize;
|
||||
}
|
||||
|
||||
void *DataAllocate(size_t Size) {
|
||||
assert(DataCheckSize(Size) &&
|
||||
"Ran out of space in DualIntrusiveAllocator during allocation");
|
||||
size_t NewOffset = DataCurrentOffset + Size;
|
||||
uintptr_t NewPointer = Data + DataCurrentOffset;
|
||||
DataCurrentOffset = NewOffset;
|
||||
return reinterpret_cast<void*>(NewPointer);
|
||||
}
|
||||
|
||||
size_t Size() const { return CurrentOffset; }
|
||||
size_t BackingSize() const { return MemorySize; }
|
||||
void *ListAllocate(size_t Size) {
|
||||
assert(ListCheckSize(Size) &&
|
||||
"Ran out of space in DualIntrusiveAllocator during allocation");
|
||||
size_t NewOffset = ListCurrentOffset + Size;
|
||||
uintptr_t NewPointer = List + ListCurrentOffset;
|
||||
ListCurrentOffset = NewOffset;
|
||||
return reinterpret_cast<void*>(NewPointer);
|
||||
}
|
||||
|
||||
uintptr_t const Begin() const { return Data; }
|
||||
size_t DataSize() const { return DataCurrentOffset; }
|
||||
size_t DataBackingSize() const { return MemorySize; }
|
||||
|
||||
void Reset() { CurrentOffset = 0; }
|
||||
size_t ListSize() const { return ListCurrentOffset; }
|
||||
size_t ListBackingSize() const { return MemorySize; }
|
||||
|
||||
void CopyData(IntrusiveAllocator const &rhs) {
|
||||
CurrentOffset = rhs.CurrentOffset;
|
||||
memcpy(reinterpret_cast<void*>(Data), reinterpret_cast<void*>(rhs.Data), CurrentOffset);
|
||||
uintptr_t const DataBegin() const { return Data; }
|
||||
uintptr_t const ListBegin() const { return List; }
|
||||
|
||||
void Reset() { DataCurrentOffset = 0; ListCurrentOffset = 0; }
|
||||
|
||||
void CopyData(DualIntrusiveAllocator const &rhs) {
|
||||
DataCurrentOffset = rhs.DataCurrentOffset;
|
||||
ListCurrentOffset = rhs.ListCurrentOffset;
|
||||
memcpy(reinterpret_cast<void*>(Data), reinterpret_cast<void*>(rhs.Data), DataCurrentOffset);
|
||||
memcpy(reinterpret_cast<void*>(List), reinterpret_cast<void*>(rhs.List), ListCurrentOffset);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t CurrentOffset {0};
|
||||
size_t MemorySize;
|
||||
uintptr_t Data;
|
||||
uintptr_t List;
|
||||
size_t DataCurrentOffset {0};
|
||||
size_t ListCurrentOffset {0};
|
||||
size_t MemorySize;
|
||||
};
|
||||
|
||||
|
||||
class IRListView final {
|
||||
enum Flags {
|
||||
FLAG_IsCopy = 1,
|
||||
FLAG_Shared = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
IRListView() = delete;
|
||||
IRListView(IRListView &&) = delete;
|
||||
|
||||
IRListView(IntrusiveAllocator *Data, IntrusiveAllocator *List, bool _IsCopy) : IsCopy(_IsCopy) {
|
||||
DataSize = Data->Size();
|
||||
ListSize = List->Size();
|
||||
IRListView(DualIntrusiveAllocator *Data, bool _IsCopy) {
|
||||
SetCopy(_IsCopy);
|
||||
DataSize = Data->DataSize();
|
||||
ListSize = Data->ListSize();
|
||||
|
||||
if (IsCopy) {
|
||||
IRData = malloc(DataSize + ListSize);
|
||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||
memcpy(IRData, reinterpret_cast<void*>(Data->Begin()), DataSize);
|
||||
memcpy(ListData, reinterpret_cast<void*>(List->Begin()), ListSize);
|
||||
if (_IsCopy) {
|
||||
IRDataInternal = malloc(DataSize + ListSize);
|
||||
ListDataInternal = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRDataInternal) + DataSize);
|
||||
memcpy(IRDataInternal, reinterpret_cast<void*>(Data->DataBegin()), DataSize);
|
||||
memcpy(ListDataInternal, reinterpret_cast<void*>(Data->ListBegin()), ListSize);
|
||||
}
|
||||
else {
|
||||
// We are just pointing to the data
|
||||
IRData = reinterpret_cast<void*>(Data->Begin());
|
||||
ListData = reinterpret_cast<void*>(List->Begin());
|
||||
IRDataInternal = reinterpret_cast<void*>(Data->DataBegin());
|
||||
ListDataInternal = reinterpret_cast<void*>(Data->ListBegin());
|
||||
}
|
||||
}
|
||||
|
||||
IRListView(IRListView *Old, bool _IsCopy) : IsCopy(_IsCopy) {
|
||||
IRListView(IRListView *Old, bool _IsCopy) {
|
||||
SetCopy(_IsCopy);
|
||||
DataSize = Old->DataSize;
|
||||
ListSize = Old->ListSize;
|
||||
if (IsCopy) {
|
||||
IRData = malloc(DataSize + ListSize);
|
||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||
memcpy(IRData, Old->IRData, DataSize);
|
||||
memcpy(ListData, Old->ListData, ListSize);
|
||||
if (_IsCopy) {
|
||||
IRDataInternal = malloc(DataSize + ListSize);
|
||||
ListDataInternal = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRDataInternal) + DataSize);
|
||||
memcpy(IRDataInternal, Old->IRDataInternal, DataSize);
|
||||
memcpy(ListDataInternal, Old->ListDataInternal, ListSize);
|
||||
} else {
|
||||
IRData = Old->IRData;
|
||||
ListData = Old->ListData;
|
||||
IRDataInternal = Old->IRDataInternal;
|
||||
ListDataInternal = Old->ListDataInternal;
|
||||
}
|
||||
}
|
||||
|
||||
IRListView(std::istream& stream) : IsCopy(true) {
|
||||
stream.read((char*)&DataSize, sizeof(DataSize));
|
||||
stream.read((char*)&ListSize, sizeof(ListSize));
|
||||
|
||||
IRData = malloc(DataSize + ListSize);
|
||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||
stream.read((char*)IRData, DataSize);
|
||||
stream.read((char*)ListData, ListSize);
|
||||
}
|
||||
|
||||
~IRListView() {
|
||||
if (IsCopy) {
|
||||
free (IRData);
|
||||
if (IsCopy()) {
|
||||
free (IRDataInternal);
|
||||
// ListData is just offset from IRData
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize(std::ostream& stream) {
|
||||
void *nul = nullptr;
|
||||
//void *IRDataInternal;
|
||||
stream.write((char*)&nul, sizeof(nul));
|
||||
//void *ListDataInternal;
|
||||
stream.write((char*)&nul, sizeof(nul));
|
||||
//size_t DataSize;
|
||||
stream.write((char*)&DataSize, sizeof(DataSize));
|
||||
//size_t ListSize;
|
||||
stream.write((char*)&ListSize, sizeof(ListSize));
|
||||
stream.write((char*)IRData, DataSize);
|
||||
stream.write((char*)ListData, ListSize);
|
||||
//uint64_t Flags;
|
||||
uint64_t WrittenFlags = Flags | FLAG_Shared; //on disk format always has the Shared flag
|
||||
stream.write((char*)&WrittenFlags, sizeof(WrittenFlags));
|
||||
|
||||
// inline data
|
||||
stream.write((char*)GetData(), DataSize);
|
||||
stream.write((char*)GetListData(), ListSize);
|
||||
}
|
||||
|
||||
size_t GetInlineSize() {
|
||||
static_assert(sizeof(*this) == 40);
|
||||
return sizeof(*this) + DataSize + ListSize;
|
||||
}
|
||||
|
||||
IRListView *CreateCopy() {
|
||||
return new IRListView(this, true);
|
||||
}
|
||||
|
||||
uintptr_t const GetData() const { return reinterpret_cast<uintptr_t>(IRData); }
|
||||
uintptr_t const GetListData() const { return reinterpret_cast<uintptr_t>(ListData); }
|
||||
|
||||
size_t GetDataSize() const { return DataSize; }
|
||||
size_t GetListSize() const { return ListSize; }
|
||||
size_t GetSSACount() const { return ListSize / sizeof(OrderedNode); }
|
||||
bool IsCopy() const { return Flags & FLAG_IsCopy; }
|
||||
void SetCopy(bool Set) { if (Set) Flags |= FLAG_IsCopy; else Flags &= ~FLAG_IsCopy; }
|
||||
bool IsShared() const { return Flags & FLAG_Shared; }
|
||||
void SetShared(bool Set) { if (Set) Flags |= FLAG_Shared; else Flags &= ~FLAG_Shared; }
|
||||
|
||||
uint32_t GetID(OrderedNode *Node) const {
|
||||
return Node->Wrapped(GetListData()).ID();
|
||||
@@ -156,7 +197,7 @@ public:
|
||||
|
||||
// If we are casting to something narrower than just the header, check the opcode.
|
||||
if constexpr (!std::is_same<T, IROp_Header>::value) {
|
||||
LogMan::Throw::A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op));
|
||||
LOGMAN_THROW_A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op));
|
||||
}
|
||||
|
||||
return Op;
|
||||
@@ -172,7 +213,6 @@ public:
|
||||
return Wrapper.GetNode(GetListData());
|
||||
}
|
||||
|
||||
bool IsShared {false};
|
||||
private:
|
||||
struct BlockRange {
|
||||
using iterator = NodeIterator;
|
||||
@@ -223,7 +263,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
BlockRange GetBlocks() const {
|
||||
@@ -244,7 +283,7 @@ public:
|
||||
{
|
||||
OrderedNodeWrapper Wrapped;
|
||||
Wrapped.NodeOffset = sizeof(OrderedNode);
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,7 +295,7 @@ public:
|
||||
{
|
||||
OrderedNodeWrapper Wrapped;
|
||||
Wrapped.NodeOffset = 0;
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,31 +303,40 @@ public:
|
||||
* @return Iterator for this op
|
||||
*/
|
||||
iterator at(OrderedNodeWrapper Wrapped) const noexcept {
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
iterator at(uint32_t ID) const noexcept {
|
||||
OrderedNodeWrapper Wrapped;
|
||||
Wrapped.NodeOffset = ID * sizeof(OrderedNode);
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
iterator at(OrderedNode *Node) const noexcept {
|
||||
auto Wrapped = Node->Wrapped(reinterpret_cast<uintptr_t>(ListData));
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
auto Wrapped = Node->Wrapped(reinterpret_cast<uintptr_t>(GetListData()));
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
uintptr_t const GetData() const {
|
||||
return reinterpret_cast<uintptr_t>(IRDataInternal ? IRDataInternal : InlineData);
|
||||
}
|
||||
|
||||
uintptr_t const GetListData() const {
|
||||
return reinterpret_cast<uintptr_t>(ListDataInternal ? ListDataInternal : &InlineData[DataSize]);
|
||||
}
|
||||
|
||||
private:
|
||||
void *IRData;
|
||||
void *ListData;
|
||||
void *IRDataInternal;
|
||||
void *ListDataInternal;
|
||||
size_t DataSize;
|
||||
size_t ListSize;
|
||||
bool IsCopy;
|
||||
uint64_t Flags {0};
|
||||
uint8_t InlineData[0];
|
||||
};
|
||||
|
||||
struct IRListViewDeleter {
|
||||
void operator()(IRListView* r) {
|
||||
if (!r->IsShared) {
|
||||
if (!r->IsShared()) {
|
||||
delete r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "IR.h"
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
|
||||
namespace FEXCore::IR {
|
||||
|
||||
@@ -47,9 +48,9 @@ class RegisterAllocationData {
|
||||
struct RegisterAllocationDataDeleter {
|
||||
void operator()(RegisterAllocationData* r) {
|
||||
if (!r->IsShared) {
|
||||
free(r);
|
||||
FEXCore::Allocator::free(r);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace FEXCore::Allocator {
|
||||
using MMAP_Hook = void*(*)(void*, size_t, int, int, int, off_t);
|
||||
using MUNMAP_Hook = int(*)(void*, size_t);
|
||||
|
||||
using MALLOC_Hook = void*(*)(size_t);
|
||||
using REALLOC_Hook = void*(*)(void*, size_t);
|
||||
using FREE_Hook = void(*)(void*);
|
||||
|
||||
__attribute__((visibility("default"))) extern MMAP_Hook mmap;
|
||||
__attribute__((visibility("default"))) extern MUNMAP_Hook munmap;
|
||||
__attribute__((visibility("default"))) extern MALLOC_Hook malloc;
|
||||
__attribute__((visibility("default"))) extern REALLOC_Hook realloc;
|
||||
__attribute__((visibility("default"))) extern FREE_Hook free;
|
||||
|
||||
void SetupHooks();
|
||||
}
|
||||
+5
@@ -83,8 +83,12 @@ public:
|
||||
using SymbolAdder = std::function<void(ELFSymbol*)>;
|
||||
void AddSymbols(SymbolAdder Adder);
|
||||
|
||||
using UnwindAdder = std::function<void(uintptr_t)>;
|
||||
void AddUnwindEntries(UnwindAdder Adder);
|
||||
|
||||
void GetInitLocations(uint64_t GuestELFBase, std::vector<uint64_t> *Locations);
|
||||
|
||||
|
||||
bool HasTLS() const { return TLSHeader._64 != nullptr; }
|
||||
uint64_t GetTLSBase() const {
|
||||
if (GetMode() == ELFMode::MODE_64BIT) {
|
||||
@@ -151,6 +155,7 @@ private:
|
||||
std::vector<SectionHeader> SectionHeaders;
|
||||
std::vector<ProgramHeader> ProgramHeaders;
|
||||
std::vector<ELFSymbol> Symbols;
|
||||
std::vector<uintptr_t> UnwindEntries;
|
||||
std::unordered_map<std::string, ELFSymbol *> SymbolMap;
|
||||
std::map<uint64_t, ELFSymbol *> SymbolMapByAddress;
|
||||
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <elf.h>
|
||||
#include <fstream>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ELFContainer.h"
|
||||
|
||||
/*
|
||||
Simpler elf parser, checks for the elf MAGIC COOKIE
|
||||
and loads the phdrs
|
||||
Also keeps an fd open
|
||||
*/
|
||||
|
||||
struct ELFParser {
|
||||
Elf64_Ehdr ehdr;
|
||||
std::vector<Elf64_Phdr> phdrs;
|
||||
::ELFLoader::ELFContainer::ELFType type {::ELFLoader::ELFContainer::TYPE_NONE};
|
||||
|
||||
std::string InterpreterElf;
|
||||
int fd {-1};
|
||||
|
||||
bool ReadElf(const std::string &file) {
|
||||
Closefd();
|
||||
static_assert(EI_CLASS == 4);
|
||||
|
||||
type = ::ELFLoader::ELFContainer::TYPE_NONE;
|
||||
|
||||
std::ifstream elf(file);
|
||||
|
||||
fd = ::open(file.c_str(), O_RDONLY);
|
||||
|
||||
if (fd == -1) {
|
||||
LogMan::Msg::E("Failed to open '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to open (C++) '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t header[5];
|
||||
elf.read((char*)header, sizeof(header));
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to read elf header from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header[0] != ELFMAG0 || header[1] != ELFMAG1 || header[2] != ELFMAG2 || header[3] != ELFMAG3) {
|
||||
LogMan::Msg::E("Elf header from '%s' doesn't match ELF MAGIC", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
type = ::ELFLoader::ELFContainer::TYPE_OTHER_ELF;
|
||||
|
||||
// go to the beggining of the file
|
||||
elf.seekg(0);
|
||||
|
||||
if (header[EI_CLASS] == ELFCLASS32) {
|
||||
Elf32_Ehdr hdr32;
|
||||
elf.read((char*)&hdr32, sizeof(hdr32));
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to read Ehdr32 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// do the sizes match up as expected?
|
||||
|
||||
// check elf header
|
||||
if (hdr32.e_ehsize != sizeof(hdr32)) {
|
||||
LogMan::Msg::E("Invalid e_ehsize32 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// check program header
|
||||
if (hdr32.e_phentsize != sizeof(Elf32_Phdr)) {
|
||||
LogMan::Msg::E("Invalid e_phentsize32 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to 64 bit header
|
||||
for (int i = 0; i < EI_NIDENT; i++)
|
||||
ehdr.e_ident[i] = hdr32.e_ident[i];
|
||||
|
||||
#define COPY(name) ehdr.name = hdr32.name
|
||||
COPY(e_type);
|
||||
COPY(e_machine);
|
||||
COPY(e_version);
|
||||
COPY(e_entry);
|
||||
COPY(e_phoff);
|
||||
COPY(e_shoff);
|
||||
COPY(e_flags);
|
||||
COPY(e_ehsize);
|
||||
COPY(e_phentsize);
|
||||
COPY(e_phnum);
|
||||
COPY(e_shentsize);
|
||||
COPY(e_shnum);
|
||||
COPY(e_shstrndx);
|
||||
#undef COPY
|
||||
|
||||
if (ehdr.e_machine != EM_386) {
|
||||
LogMan::Msg::E("Invalid e_machine from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
type = ::ELFLoader::ELFContainer::TYPE_X86_32;
|
||||
|
||||
} else if (header[EI_CLASS] == ELFCLASS64) {
|
||||
elf.read((char*)&ehdr, sizeof(ehdr));
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to read Ehdr64 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// do the sizes match up as expected?
|
||||
|
||||
// check elf header
|
||||
if (ehdr.e_ehsize != sizeof(ehdr)) {
|
||||
LogMan::Msg::E("Invalid e_ehsize64 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// check program header
|
||||
if (ehdr.e_phentsize != sizeof(Elf64_Phdr)) {
|
||||
LogMan::Msg::E("Invalid e_phentsize64 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ehdr.e_machine != EM_X86_64) {
|
||||
LogMan::Msg::E("Invalid e_machine64 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
type = ::ELFLoader::ELFContainer::TYPE_X86_64;
|
||||
|
||||
} else {
|
||||
// Unexpected elf type
|
||||
LogMan::Msg::E("Unexpected elf type from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// seek to the program header offset
|
||||
elf.seekg(ehdr.e_phoff);
|
||||
|
||||
// sanity check program header count
|
||||
if (ehdr.e_phnum < 1 || ehdr.e_phnum > 65536 / ehdr.e_phentsize) {
|
||||
LogMan::Msg::E("Too many program headers '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == ::ELFLoader::ELFContainer::TYPE_X86_32) {
|
||||
Elf32_Phdr phdrs32[ehdr.e_phnum];
|
||||
elf.read((char*)phdrs32, sizeof(Elf32_Phdr) * ehdr.e_phnum);
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to read phdr32 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to 64 bit program headers
|
||||
phdrs.resize(ehdr.e_phnum);
|
||||
|
||||
for (int i = 0; i < ehdr.e_phnum; i++) {
|
||||
#define COPY(name) phdrs[i].name = phdrs32[i].name
|
||||
|
||||
COPY(p_type);
|
||||
COPY(p_offset);
|
||||
COPY(p_vaddr);
|
||||
COPY(p_paddr);
|
||||
COPY(p_filesz);
|
||||
COPY(p_memsz);
|
||||
COPY(p_flags);
|
||||
COPY(p_align);
|
||||
|
||||
#undef COPY
|
||||
}
|
||||
} else {
|
||||
phdrs.resize(ehdr.e_phnum);
|
||||
|
||||
elf.read((char*)&phdrs[0], sizeof(Elf64_Phdr) * ehdr.e_phnum);
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to read phdr64 from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto phdr : phdrs) {
|
||||
if (phdr.p_type == PT_INTERP) {
|
||||
elf.seekg(phdr.p_offset);
|
||||
InterpreterElf.resize(phdr.p_filesz);
|
||||
|
||||
elf.read(&InterpreterElf[0], phdr.p_filesz);
|
||||
|
||||
if (!elf.good()) {
|
||||
LogMan::Msg::E("Failed to read interpreter from '%s'", file.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Closefd() {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
~ELFParser() {
|
||||
Closefd();
|
||||
}
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "ELFLoader.h"
|
||||
#include "ELFContainer.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ELFLoader {
|
||||
class ELFSymbolDatabase final {
|
||||
class __attribute__((visibility("default"))) ELFSymbolDatabase final {
|
||||
public:
|
||||
ELFSymbolDatabase(::ELFLoader::ELFContainer *file);
|
||||
~ELFSymbolDatabase();
|
||||
|
||||
+9
-5
@@ -18,8 +18,8 @@ constexpr DebugLevels MSG_LEVEL = INFO;
|
||||
|
||||
namespace Throw {
|
||||
using ThrowHandler = void(*)(char const *Message);
|
||||
void InstallHandler(ThrowHandler Handler);
|
||||
void UnInstallHandlers();
|
||||
__attribute__((visibility("default"))) void InstallHandler(ThrowHandler Handler);
|
||||
__attribute__((visibility("default"))) void UnInstallHandlers();
|
||||
|
||||
[[noreturn]] void M(const char *fmt, va_list args);
|
||||
|
||||
@@ -32,18 +32,20 @@ static inline void A(bool Value, const char *fmt, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
#define LOGMAN_THROW_A(pred, ...) do { LogMan::Throw::A(pred, __VA_ARGS__); } while (0)
|
||||
#else
|
||||
static inline void A(bool, const char*, ...) {}
|
||||
#define LOGMAN_THROW_A(pred, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
} // namespace Throw
|
||||
|
||||
namespace Msg {
|
||||
using MsgHandler = void(*)(DebugLevels Level, char const *Message);
|
||||
void InstallHandler(MsgHandler Handler);
|
||||
void UnInstallHandlers();
|
||||
__attribute__((visibility("default"))) void InstallHandler(MsgHandler Handler);
|
||||
__attribute__((visibility("default"))) void UnInstallHandlers();
|
||||
|
||||
void M(DebugLevels Level, const char *fmt, va_list args);
|
||||
__attribute__((visibility("default"))) void M(DebugLevels Level, const char *fmt, va_list args);
|
||||
|
||||
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
|
||||
static inline void A(const char *fmt, ...) {
|
||||
@@ -55,8 +57,10 @@ static inline void A(const char *fmt, ...) {
|
||||
}
|
||||
__builtin_trap();
|
||||
}
|
||||
#define LOGMAN_MSG_A(...) do { LogMan::Msg::A(__VA_ARGS__); } while (0)
|
||||
#else
|
||||
static inline void A(const char*, ...) {}
|
||||
#define LOGMAN_MSG_A(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
static inline void E(const char *fmt, ...) {
|
||||
|
||||
+1
Submodule External/jemalloc added at 2c7c069c8f.
Vendored
+1
-1
Submodule External/vixl updated: 6d8ced06a7...4d6c1d44a5.
Vendored
+1
-1
Submodule External/xbyak updated: 782a28238e...243d8bb609.
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
FEX=${1:-FEXLoader}
|
||||
echo Using $FEX
|
||||
for fileid in ~/.fex-emu/aotir/*.path; do
|
||||
filename=`cat "$fileid"`
|
||||
args=""
|
||||
if [ "${fileid: -6 : 1}" == "P" ]; then
|
||||
args="$args --no-abinopf"
|
||||
else
|
||||
args="$args --abinopf"
|
||||
fi
|
||||
|
||||
if [ "${fileid: -7 : 1}" == "L" ]; then
|
||||
args="$args --abilocalflags"
|
||||
else
|
||||
args="$args --no-abilocalflags"
|
||||
fi
|
||||
|
||||
if [ "${fileid: -8 : 1}" == "T" ]; then
|
||||
args="$args --tsoenabled"
|
||||
else
|
||||
args="$args --no-tsoenabled"
|
||||
fi
|
||||
|
||||
if [ "${fileid: -9 : 1}" == "S" ]; then
|
||||
args="$args --smc=full"
|
||||
else
|
||||
args="$args --smc=mman"
|
||||
fi
|
||||
|
||||
if [ -f "${fileid%.path}.aotir" ]; then
|
||||
echo "`basename $fileid` has already been generated"
|
||||
else
|
||||
echo "Processing `basename $fileid` ($filename) with $args"
|
||||
$FEX --aotirgenerate $args "$filename"
|
||||
fi
|
||||
done
|
||||
+111
-15
@@ -16,6 +16,7 @@ class TypeDefinition:
|
||||
TYPE_STRUCT = 1
|
||||
TYPE_UNION = 2
|
||||
TYPE_FIELD = 3
|
||||
TYPE_VARDECL = 4
|
||||
|
||||
name: str
|
||||
type: int
|
||||
@@ -82,6 +83,19 @@ class FieldDefinition(TypeDefinition):
|
||||
self.OffsetOf = OffsetOf
|
||||
self.Alignment = Alignment
|
||||
|
||||
@dataclass
|
||||
class VarDeclDefinition(TypeDefinition):
|
||||
Size: int
|
||||
Aliases: list
|
||||
ExpectFEXMatch: bool
|
||||
Value: str
|
||||
|
||||
def __init__(self, Name, Size):
|
||||
super(VarDeclDefinition, self).__init__(Name, TypeDefinition.TYPE_VARDECL)
|
||||
self.Size = Size
|
||||
self.Aliases = []
|
||||
self.ExpectFEXMatch = False
|
||||
|
||||
@dataclass
|
||||
class ArchDB:
|
||||
Parsed: bool
|
||||
@@ -91,6 +105,7 @@ class ArchDB:
|
||||
TU: TranslationUnit
|
||||
Structs: dict
|
||||
Unions: dict
|
||||
VarDecls: dict
|
||||
FieldDecls: list
|
||||
def __init__(self, ArchName):
|
||||
self.Parsed = True
|
||||
@@ -100,6 +115,7 @@ class ArchDB:
|
||||
self.TU = None
|
||||
self.Structs = {}
|
||||
self.Unions = {}
|
||||
self.VarDecls = {}
|
||||
self.FieldDecls = []
|
||||
|
||||
class DBList:
|
||||
@@ -197,18 +213,62 @@ def HandleUnionDeclCursor(Arch, Cursor, NameOverride = ""):
|
||||
|
||||
return Arch
|
||||
|
||||
def HandleVarDeclCursor(Arch, Cursor):
|
||||
CursorName = Cursor.spelling
|
||||
DeclType = Cursor.type
|
||||
Def = Cursor.get_definition()
|
||||
|
||||
VarDecl = VarDeclDefinition(
|
||||
Name = CursorName,
|
||||
Size = DeclType.get_size())
|
||||
Arch.VarDecls[VarDecl.Name] = HandleVarDeclElements(Arch, VarDecl, Cursor)
|
||||
return Arch
|
||||
|
||||
def HandleVarDeclElements(Arch, VarDecl, Cursor):
|
||||
for Child in Cursor.get_children():
|
||||
|
||||
if (Child.kind == CursorKind.ANNOTATE_ATTR):
|
||||
if (Child.spelling.startswith("ioctl-alias-")):
|
||||
Sections = Child.spelling.split("-")
|
||||
if (Sections[2] == "x86_32"):
|
||||
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_X86_32))
|
||||
elif (Sections[2] == "x86_64"):
|
||||
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_X86_64))
|
||||
elif (Sections[2] == "aarch64"):
|
||||
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_AARCH64))
|
||||
elif (Sections[2] == "win32"):
|
||||
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_WIN32))
|
||||
elif (Sections[2] == "win64"):
|
||||
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_WIN64))
|
||||
else:
|
||||
logging.critical ("Can't handle alias type '{0}'".format(Child.spelling))
|
||||
Arch.Parsed = False
|
||||
elif (Child.spelling == "fex-match"):
|
||||
VarDecl.ExpectedFEXMatch = True
|
||||
else:
|
||||
# Unknown annotation
|
||||
pass
|
||||
elif (Child.kind == CursorKind.TYPE_REF or
|
||||
Child.kind == CursorKind.UNEXPOSED_EXPR or
|
||||
Child.kind == CursorKind.PAREN_EXPR or
|
||||
Child.kind == CursorKind.BINARY_OPERATOR
|
||||
):
|
||||
pass
|
||||
|
||||
return VarDecl
|
||||
|
||||
|
||||
def HandleTypeDefDeclCursor(Arch, Cursor):
|
||||
TypeDefType = Cursor.underlying_typedef_type
|
||||
CanonicalType = TypeDefType.get_canonical()
|
||||
|
||||
TypeDefName = Cursor.type.get_typedef_name()
|
||||
|
||||
if (TypeDefType.kind == TypeKind.ELABORATED and CanonicalType.kind == TypeKind.RECORD):
|
||||
TypeDefName = Cursor.type.get_typedef_name()
|
||||
if (len(TypeDefName) != 0):
|
||||
logging.info ("Found Typedef Decl'{0}'".format(TypeDefName))
|
||||
logging.info ("\tSize of type: {0}".format(CanonicalType.get_size()));
|
||||
HandleTypeDefDecl(Arch, Cursor, TypeDefName)
|
||||
|
||||
# Append namespace
|
||||
# Append namespace
|
||||
Arch.NamespaceScope.append(TypeDefName)
|
||||
SetNamespace(Arch)
|
||||
|
||||
@@ -225,11 +285,20 @@ def HandleTypeDefDeclCursor(Arch, Cursor):
|
||||
# Pop namespace off
|
||||
Arch.NamespaceScope.pop()
|
||||
SetNamespace(Arch)
|
||||
else:
|
||||
if (len(TypeDefName) != 0):
|
||||
Def = Cursor.get_definition()
|
||||
|
||||
VarDecl = VarDeclDefinition(
|
||||
Name = TypeDefName,
|
||||
Size = CanonicalType.get_size())
|
||||
Arch.VarDecls[VarDecl.Name] = HandleVarDeclElements(Arch, VarDecl, Cursor)
|
||||
|
||||
return Arch
|
||||
|
||||
def HandleStructElements(Arch, Struct, Cursor):
|
||||
for Child in Cursor.get_children():
|
||||
logging.info ("\t\tStruct/Union Children: Cursor \"{0}{1}\" of kind {2}".format(Arch.CurrentNamespace, Child.spelling, Child.kind))
|
||||
# logging.info ("\t\tStruct/Union Children: Cursor \"{0}{1}\" of kind {2}".format(Arch.CurrentNamespace, Child.spelling, Child.kind))
|
||||
if (Child.kind == CursorKind.ANNOTATE_ATTR):
|
||||
if (Child.spelling.startswith("alias-")):
|
||||
Sections = Child.spelling.split("-")
|
||||
@@ -245,6 +314,8 @@ def HandleStructElements(Arch, Struct, Cursor):
|
||||
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_WIN64))
|
||||
else:
|
||||
logging.critical ("Can't handle alias type '{0}'".format(Child.spelling))
|
||||
Arch.Parsed = False
|
||||
|
||||
elif (Child.spelling == "fex-match"):
|
||||
Struct.ExpectedFEXMatch = True
|
||||
else:
|
||||
@@ -259,10 +330,10 @@ def HandleStructElements(Arch, Struct, Cursor):
|
||||
OffsetOf = ParentType.get_offset(Child.spelling),
|
||||
Alignment = FieldType.get_align())
|
||||
|
||||
logging.info ("\t{0}".format(Child.spelling))
|
||||
logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
||||
logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
||||
logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
||||
#logging.info ("\t{0}".format(Child.spelling))
|
||||
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
||||
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
||||
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
||||
Struct.Members.append(Field)
|
||||
Arch.FieldDecls.append(Field)
|
||||
elif (Child.kind == CursorKind.STRUCT_DECL):
|
||||
@@ -274,10 +345,10 @@ def HandleStructElements(Arch, Struct, Cursor):
|
||||
OffsetOf = ParentType.get_offset(Child.spelling),
|
||||
Alignment = FieldType.get_align())
|
||||
|
||||
logging.info ("\t{0}".format(Child.spelling))
|
||||
logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
||||
logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
||||
logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
||||
#logging.info ("\t{0}".format(Child.spelling))
|
||||
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
|
||||
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
|
||||
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
|
||||
Struct.Members.append(Field)
|
||||
Arch.FieldDecls.append(Field)
|
||||
Arch = HandleStructDeclCursor(Arch, Child)
|
||||
@@ -333,7 +404,6 @@ def HandleCursor(Arch, Cursor):
|
||||
return
|
||||
|
||||
for Child in Cursor.get_children():
|
||||
logging.info ("\tCursor \"{0}\" of kind {1}".format(Child.spelling, Child.kind))
|
||||
if (Child.kind == CursorKind.TRANSLATION_UNIT):
|
||||
Arch = HandleCursor(Arch, Child)
|
||||
elif (Child.kind == CursorKind.FIELD_DECL):
|
||||
@@ -344,6 +414,8 @@ def HandleCursor(Arch, Cursor):
|
||||
Arch = HandleStructDeclCursor(Arch, Child)
|
||||
elif (Child.kind == CursorKind.TYPEDEF_DECL):
|
||||
Arch = HandleTypeDefDeclCursor(Arch, Child)
|
||||
elif (Child.kind == CursorKind.VAR_DECL):
|
||||
Arch = HandleVarDeclCursor(Arch, Child)
|
||||
elif (Child.kind == CursorKind.NAMESPACE):
|
||||
# Append namespace
|
||||
Arch.NamespaceScope.append(Child.spelling)
|
||||
@@ -455,7 +527,8 @@ def CompareAliases(DB, DBs):
|
||||
# XXX: Oops, shouldn't have anonymous structs
|
||||
continue
|
||||
|
||||
logging.info ("Comparing Aliases {0}".format(StructDef.Name))
|
||||
if (len(StructDef.Aliases) != 0):
|
||||
logging.info ("Comparing Aliases {0}".format(StructDef.Name))
|
||||
|
||||
for Alias in StructDef.Aliases:
|
||||
OtherDB = DBs.DBs[Alias.AliasType]
|
||||
@@ -469,6 +542,29 @@ def CompareAliases(DB, DBs):
|
||||
if not (ThisAlias):
|
||||
logging.error ("Couldn't Alias to Arch {0} successfully".format(OtherDB.ArchName))
|
||||
Passed &= ThisAlias
|
||||
|
||||
for VarDeclKey, VarDecl in DB.VarDecls.items():
|
||||
if (len(VarDeclKey) == 0):
|
||||
# XXX: Oops, shouldn't have anonymous vardecls
|
||||
continue
|
||||
|
||||
|
||||
for Alias in VarDecl.Aliases:
|
||||
OtherDB = DBs.DBs[Alias.AliasType]
|
||||
OtherAlias = OtherDB.VarDecls.get(Alias.Name)
|
||||
if (OtherAlias == None):
|
||||
logging.critical ("Couldn't find alias {0} in {1} DB".format(Alias.Name, OtherDB.ArchName))
|
||||
Passed = False
|
||||
continue
|
||||
|
||||
if (VarDecl.Size != OtherAlias.Size):
|
||||
logging.critical("VarDecl: {0}/{1} didn't match {2}/{3}: {4:08X} != {5:08X}".format(VarDeclKey, DB.ArchName, Alias.Name,
|
||||
OtherDB.ArchName,
|
||||
VarDecl.Size, OtherAlias.Size))
|
||||
Passed = False
|
||||
continue
|
||||
|
||||
|
||||
return Passed
|
||||
|
||||
def CompareCrossArch(DB1, DB2):
|
||||
|
||||
Loaded 100 of 192 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user