diff --git a/.ci/linux/build.sh b/.ci/linux/build.sh index 745f8244b7..093b30a7ea 100755 --- a/.ci/linux/build.sh +++ b/.ci/linux/build.sh @@ -36,15 +36,16 @@ case "$1" in ARCH=armv9 ARCH_FLAGS="-march=armv9-a -mtune=generic -w" ;; + *) + echo "Invalid target $1 specified, must be one of amd64, steamdeck, allyx, rog-ally, legacy, aarch64, armv9" + exit 1 + ;; esac export ARCH_FLAGS="$ARCH_FLAGS -O3" -NPROC="$2" if [ -z "$NPROC" ]; then NPROC="$(nproc)" -else - shift fi if [ "$1" != "" ]; then shift; fi @@ -60,11 +61,27 @@ if [ "$DEVEL" != "true" ]; then export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DENABLE_QT_UPDATE_CHECKER=ON) fi +if [ "$USE_WEBENGINE" = "true" ]; then + WEBENGINE=ON +else + WEBENGINE=OFF +fi + +if [ "$USE_MULTIMEDIA" = "false" ]; then + MULTIMEDIA=OFF +else + MULTIMEDIA=ON +fi + +if [ -z "$BUILD_TYPE" ]; then + export BUILD_TYPE="Release" +fi + export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) mkdir -p build && cd build cmake .. -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ -DENABLE_QT_TRANSLATION=ON \ -DUSE_DISCORD_PRESENCE=ON \ -DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \ @@ -74,8 +91,8 @@ cmake .. -G Ninja \ -DYUZU_USE_BUNDLED_SDL2=OFF \ -DYUZU_USE_EXTERNAL_SDL2=ON \ -DYUZU_TESTS=OFF \ - -DYUZU_USE_QT_MULTIMEDIA=ON \ - -DYUZU_USE_QT_WEB_ENGINE=ON \ + -DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \ + -DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \ -DYUZU_USE_FASTER_LD=ON \ -DYUZU_ENABLE_LTO=ON \ "${EXTRA_CMAKE_FLAGS[@]}" diff --git a/.ci/windows/build.sh b/.ci/windows/build.sh index 4e993b0488..d0c697655a 100644 --- a/.ci/windows/build.sh +++ b/.ci/windows/build.sh @@ -17,16 +17,32 @@ else export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DYUZU_USE_BUNDLED_QT=OFF) fi +if [ -z "$BUILD_TYPE" ]; then + export BUILD_TYPE="Release" +fi + if [ "$WINDEPLOYQT" == "" ]; then echo "You must supply the WINDEPLOYQT environment variable." exit 1 fi +if [ "$USE_WEBENGINE" = "true" ]; then + WEBENGINE=ON +else + WEBENGINE=OFF +fi + +if [ "$USE_MULTIMEDIA" = "false" ]; then + MULTIMEDIA=OFF +else + MULTIMEDIA=ON +fi + export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) mkdir -p build && cd build cmake .. -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ -DENABLE_QT_TRANSLATION=ON \ -DUSE_DISCORD_PRESENCE=ON \ -DYUZU_USE_BUNDLED_SDL2=OFF \ @@ -34,8 +50,8 @@ cmake .. -G Ninja \ -DYUZU_TESTS=OFF \ -DYUZU_CMD=OFF \ -DYUZU_ROOM_STANDALONE=OFF \ - -DYUZU_USE_QT_MULTIMEDIA=ON \ - -DYUZU_USE_QT_WEB_ENGINE=ON \ + -DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \ + -DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \ -DYUZU_ENABLE_LTO=ON \ "${EXTRA_CMAKE_FLAGS[@]}" diff --git a/.gitignore b/.gitignore index 7484a368e6..4417d3f132 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ CMakeLists.txt.user* # Visual Studio CMake settings CMakeSettings.json +.cache/ # OSX global filetypes # Created by Finder or Spotlight in directories for various OS functionality (indexing, etc) @@ -51,4 +52,3 @@ Thumbs.db eden-windows-msvc artifacts *.AppImage* -*.patch diff --git a/.patch/quazip/0001-strict.patch b/.patch/quazip/0001-strict.patch new file mode 100644 index 0000000000..8283497230 --- /dev/null +++ b/.patch/quazip/0001-strict.patch @@ -0,0 +1,80 @@ +diff --git a/quazip/quazipdir.cpp b/quazip/quazipdir.cpp +index d43f1c1..eb24bf1 100644 +--- a/quazip/quazipdir.cpp ++++ b/quazip/quazipdir.cpp +@@ -293,8 +293,8 @@ bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1, + } + + template +-bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, +- QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const ++bool QuaZipDirPrivate::entryInfoList(QStringList _nameFilters, ++ QDir::Filters _filter, QDir::SortFlags sort, TFileInfoList &result) const + { + QString basePath = simplePath(); + if (!basePath.isEmpty()) +@@ -305,12 +305,12 @@ bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, + if (!zip->goToFirstFile()) { + return zip->getZipError() == UNZ_OK; + } +- QDir::Filters fltr = filter; ++ QDir::Filters fltr = _filter; + if (fltr == QDir::NoFilter) + fltr = this->filter; + if (fltr == QDir::NoFilter) + fltr = QDir::AllEntries; +- QStringList nmfltr = nameFilters; ++ QStringList nmfltr = _nameFilters; + if (nmfltr.isEmpty()) + nmfltr = this->nameFilters; + QSet dirsFound; +diff --git a/quazip/quazipfile.cpp b/quazip/quazipfile.cpp +index 4a5f2f9..f7865f5 100644 +--- a/quazip/quazipfile.cpp ++++ b/quazip/quazipfile.cpp +@@ -241,14 +241,14 @@ void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs + p->caseSensitivity=cs; + } + +-void QuaZipFilePrivate::setZipError(int zipError) const ++void QuaZipFilePrivate::setZipError(int _zipError) const + { + QuaZipFilePrivate *fakeThis = const_cast(this); // non-const +- fakeThis->zipError=zipError; +- if(zipError==UNZ_OK) ++ fakeThis->zipError = _zipError; ++ if(_zipError == UNZ_OK) + q->setErrorString(QString()); + else +- q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError)); ++ q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(_zipError)); + } + + bool QuaZipFile::open(OpenMode mode) +diff --git a/quazip/unzip.c b/quazip/unzip.c +index a39365d..ee7b487 100644 +--- a/quazip/unzip.c ++++ b/quazip/unzip.c +@@ -1054,7 +1054,7 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file, + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { +- uLong uL; ++ uLong _uL; + + if(file_info.uncompressed_size == (ZPOS64_T)0xFFFFFFFFu) + { +@@ -1078,7 +1078,7 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file, + if(file_info.disk_num_start == 0xFFFFFFFFu) + { + /* Disk Start Number */ +- if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) ++ if (unz64local_getLong(&s->z_filefunc, s->filestream, &_uL) != UNZ_OK) + err=UNZ_ERRNO; + } + +@@ -2151,3 +2151,4 @@ int ZEXPORT unzClearFlags(unzFile file, unsigned flags) + s->flags &= ~flags; + return UNZ_OK; + } ++ diff --git a/.patch/quazip/0002-oldstyle.patch b/.patch/quazip/0002-oldstyle.patch new file mode 100644 index 0000000000..2694128f04 --- /dev/null +++ b/.patch/quazip/0002-oldstyle.patch @@ -0,0 +1,26 @@ +diff --git a/quazip/minizip_crypt.h b/quazip/minizip_crypt.h +index 2e833f7..ea9d277 100644 +--- a/quazip/minizip_crypt.h ++++ b/quazip/minizip_crypt.h +@@ -90,13 +90,14 @@ static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t FAR + # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ + # endif + +-static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) +- const char *passwd; /* password string */ +- unsigned char *buf; /* where to write header */ +- int bufSize; +- unsigned long* pkeys; +- const z_crc_t FAR * pcrc_32_tab; +- unsigned long crcForCrypting; ++static int crypthead( ++ const char *passwd, /* password string */ ++ unsigned char *buf, /* where to write header */ ++ int bufSize, ++ unsigned long* pkeys, ++ const z_crc_t FAR * pcrc_32_tab, ++ unsigned long crcForCrypting ++) + { + int n; /* index in random header */ + int t; /* temporary */ diff --git a/.patch/quazip/0003-predecls.patch b/.patch/quazip/0003-predecls.patch new file mode 100644 index 0000000000..ec3414c82a --- /dev/null +++ b/.patch/quazip/0003-predecls.patch @@ -0,0 +1,19 @@ +diff --git a/quazip/zip.c b/quazip/zip.c +index 7788b88..f4e21aa 100644 +--- a/quazip/zip.c ++++ b/quazip/zip.c +@@ -645,6 +645,14 @@ local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib + return relativeOffset; + } + ++// compilers hate this ONE SIMPLE TRICK! ++static int LoadCentralDirectoryRecord(zip64_internal* pziinit); ++static int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local, uLong version_to_extract); ++static int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip); ++static int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip); ++static int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip); ++static int Write_GlobalComment(zip64_internal* zi, const char* global_comment); ++ + int LoadCentralDirectoryRecord(zip64_internal* pziinit) + { + int err=ZIP_OK; diff --git a/.patch/quazip/0004-qt6-only.patch b/.patch/quazip/0004-qt6-only.patch new file mode 100644 index 0000000000..8906df2472 --- /dev/null +++ b/.patch/quazip/0004-qt6-only.patch @@ -0,0 +1,400 @@ +"Debloats" QuaZip by removing some unneeded stuff (Qt <6, bzip2, emscripten...) + +This is completely optional. + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b376fb2..4aac4ec 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -3,64 +3,16 @@ cmake_minimum_required(VERSION 3.15...3.18) + + project(QuaZip VERSION 1.5) + +-include(cmake/clone-repo.cmake) +- + set(QUAZIP_LIB_VERSION ${QuaZip_VERSION}) + set(QUAZIP_LIB_SOVERSION 1.5.0) + +-if(EMSCRIPTEN) +- #option(ZLIB_INCLUDE "Path to include dir" "") +- #option(ZLIB_LIBRARY "Path to library dir" "") +- option(BUILD_SHARED_LIBS "" OFF) +- option(QUAZIP_INSTALL "" OFF) +- option(QUAZIP_USE_QT_ZLIB "" OFF) +- option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF) +-else() +- option(BUILD_SHARED_LIBS "" ON) +- option(QUAZIP_INSTALL "" ON) +- option(QUAZIP_USE_QT_ZLIB "" OFF) +- option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF) +-endif() ++option(BUILD_SHARED_LIBS "" ON) ++option(QUAZIP_INSTALL "" ON) ++option(QUAZIP_ENABLE_TESTS "Build QuaZip tests" OFF) + + OPTION(ZLIB_CONST "Sets ZLIB_CONST preprocessor definition" OFF) + +-# Make BZIP2 optional +-option(QUAZIP_BZIP2 "Enables BZIP2 compression" ON) +-option(QUAZIP_BZIP2_STDIO "Output BZIP2 errors to stdio" ON) +- +-option(QUAZIP_FETCH_LIBS "Enables fetching third-party libraries if not found" ${WIN32}) +-option(QUAZIP_FORCE_FETCH_LIBS "Enables fetching third-party libraries always" OFF) +- +-if (QUAZIP_USE_QT_ZLIB AND BUILD_SHARED_LIBS) +- message(FATAL_ERROR "Using BUILD_SHARED_LIBS=ON together with QUAZIP_USE_QT_ZLIB=ON is not supported." ) +-endif() +- +-# Set the default value of `${QUAZIP_QT_MAJOR_VERSION}`. +-# We search quietly for Qt6, Qt5 and Qt4 in that order. +-# Qt6 and Qt5 provide config files for CMake. +-# Qt4 relies on `FindQt4.cmake`. +-find_package( +- QT NAMES Qt6 Qt5 +- QUIET COMPONENTS Core +-) +-if (NOT QT_FOUND) +- find_package(Qt4 QUIET COMPONENTS QtCore) +- if (Qt4_FOUND) +- set(QT_VERSION_MAJOR 4) +- else() +- # If neither 6, 5 nor 4 are found, we default to 5. +- # The setup will fail further down. +- set(QT_VERSION_MAJOR 5) +- endif() +-endif() +- +-set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}") +- +-if (QUAZIP_QT_MAJOR_VERSION EQUAL 6) +- set(CMAKE_CXX_STANDARD 17) +-else() +- set(CMAKE_CXX_STANDARD 14) +-endif() ++set(CMAKE_CXX_STANDARD 17) + + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RELEASE) +@@ -77,92 +29,17 @@ set(QUAZIP_LIB_TARGET_NAME QuaZip) + set(QUAZIP_DIR_NAME QuaZip-Qt${QUAZIP_QT_MAJOR_VERSION}-${QUAZIP_LIB_VERSION}) + set(QUAZIP_PACKAGE_NAME QuaZip-Qt${QUAZIP_QT_MAJOR_VERSION}) + +-message(STATUS "QUAZIP_QT_MAJOR_VERSION set to ${QUAZIP_QT_MAJOR_VERSION}") +-message(STATUS "CMAKE_CXX_STANDARD set to ${CMAKE_CXX_STANDARD}") +- +-if(QUAZIP_QT_MAJOR_VERSION EQUAL 6) +- find_package(Qt6 REQUIRED COMPONENTS Core Core5Compat +- OPTIONAL_COMPONENTS Network Test) +- message(STATUS "Found Qt version ${Qt6_VERSION} at ${Qt6_DIR}") +- set(QUAZIP_QT_ZLIB_COMPONENT BundledZLIB) +- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT ZlibPrivate) +- set(QUAZIP_LIB_LIBRARIES Qt6::Core Qt6::Core5Compat) +- set(QUAZIP_TEST_QT_LIBRARIES Qt6::Core Qt6::Core5Compat Qt6::Network Qt6::Test) +- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt6Core") +-elseif(QUAZIP_QT_MAJOR_VERSION EQUAL 5) +- find_package(Qt5 REQUIRED COMPONENTS Core +- OPTIONAL_COMPONENTS Network Test) +- message(STATUS "Found Qt version ${Qt5_VERSION} at ${Qt5_DIR}") +- set(QUAZIP_QT_ZLIB_COMPONENT Zlib) +- set(QUAZIP_LIB_LIBRARIES Qt5::Core) +- set(QUAZIP_TEST_QT_LIBRARIES Qt5::Core Qt5::Network Qt5::Test) +- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt5Core") +-elseif(QUAZIP_QT_MAJOR_VERSION EQUAL 4) +- find_package(Qt4 4.5.0 REQUIRED COMPONENTS QtCore +- OPTIONAL_COMPONENTS QtNetwork QtTest) +- set(QUAZIP_QT_ZLIB_COMPONENT Zlib) +- set(QUAZIP_LIB_LIBRARIES Qt4::QtCore) +- set(QUAZIP_TEST_QT_LIBRARIES Qt4::QtCore Qt4::QtNetwork Qt4::QtTest) +- set(QUAZIP_PKGCONFIG_REQUIRES "zlib, QtCore") +-else() +- message(FATAL_ERROR "Qt version ${QUAZIP_QT_MAJOR_VERSION} is not supported") +-endif() +- +-message(STATUS "Using Qt version ${QUAZIP_QT_MAJOR_VERSION}") +- +-set(QUAZIP_QT_ZLIB_USED OFF) +-if(QUAZIP_USE_QT_ZLIB) +- find_package(Qt${QUAZIP_QT_MAJOR_VERSION} OPTIONAL_COMPONENTS ${QUAZIP_QT_ZLIB_COMPONENT}) +- set(QUAZIP_QT_ZLIB_COMPONENT_FOUND Qt${QUAZIP_QT_MAJOR_VERSION}${QUAZIP_QT_ZLIB_COMPONENT}_FOUND) +- if (DEFINED QUAZIP_QT_ZLIB_HEADER_COMPONENT) +- find_package(Qt${QUAZIP_QT_MAJOR_VERSION} OPTIONAL_COMPONENTS ${QUAZIP_QT_ZLIB_HEADER_COMPONENT}) +- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND Qt${QUAZIP_QT_MAJOR_VERSION}${QUAZIP_QT_ZLIB_HEADER_COMPONENT}_FOUND) +- else() +- set(QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND ON) +- endif() +- if(QUAZIP_QT_ZLIB_COMPONENT_FOUND AND QUAZIP_QT_ZLIB_HEADER_COMPONENT_FOUND) +- message(STATUS "Qt component ${QUAZIP_QT_ZLIB_COMPONENT} found") +- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} Qt${QUAZIP_QT_MAJOR_VERSION}::${QUAZIP_QT_ZLIB_COMPONENT}) +- if(DEFINED QUAZIP_QT_ZLIB_HEADER_COMPONENT) +- message(STATUS "Qt component ${QUAZIP_QT_ZLIB_HEADER_COMPONENT} found") +- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} Qt${QUAZIP_QT_MAJOR_VERSION}::${QUAZIP_QT_ZLIB_HEADER_COMPONENT}) +- endif() +- set(QUAZIP_QT_ZLIB_USED ON) +- else() +- message(FATAL_ERROR "QUAZIP_USE_QT_ZLIB was set but bundled zlib was not found. Terminating to prevent accidental linking to system libraries.") +- endif() +-endif() +- +-if(QUAZIP_QT_ZLIB_USED AND QUAZIP_QT_ZLIB_COMPONENT STREQUAL BundledZLIB) +- # Qt's new BundledZLIB uses z-prefix in zlib +- add_compile_definitions(Z_PREFIX) +-endif() +- +-if(NOT QUAZIP_QT_ZLIB_USED) +- +- if(EMSCRIPTEN) +- if(NOT DEFINED ZLIB_LIBRARY) +- message(WARNING "ZLIB_LIBRARY is not set") +- endif() ++find_package(Qt6 REQUIRED COMPONENTS Core Core5Compat ++ OPTIONAL_COMPONENTS Network Test) ++message(STATUS "Found Qt version ${Qt6_VERSION} at ${Qt6_DIR}") ++set(QUAZIP_QT_ZLIB_COMPONENT BundledZLIB) ++set(QUAZIP_QT_ZLIB_HEADER_COMPONENT ZlibPrivate) ++set(QUAZIP_LIB_LIBRARIES Qt6::Core Qt6::Core5Compat) ++set(QUAZIP_TEST_QT_LIBRARIES Qt6::Core Qt6::Core5Compat Qt6::Network Qt6::Test) ++set(QUAZIP_PKGCONFIG_REQUIRES "zlib, Qt6Core") + +- if(NOT DEFINED ZLIB_INCLUDE) +- message(WARNING "ZLIB_INCLUDE is not set") +- else() +- include_directories(${ZLIB_INCLUDE}) +- endif() +- +- if(NOT DEFINED ZCONF_INCLUDE) +- message(WARNING "ZCONF_INCLUDE is not set") +- else() +- include_directories(${ZCONF_INCLUDE}) +- endif() +- +- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ${ZLIB_LIBRARY}) +- else() +- find_package(ZLIB REQUIRED) +- set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ZLIB::ZLIB) +- endif() +-endif() ++find_package(ZLIB REQUIRED) ++set(QUAZIP_LIB_LIBRARIES ${QUAZIP_LIB_LIBRARIES} ZLIB::ZLIB) + + if (ZLIB_CONST) + add_compile_definitions(ZLIB_CONST) +@@ -173,65 +50,4 @@ set(QUAZIP_INC) + set(QUAZIP_LIB) + set(QUAZIP_LBD) + +-if(QUAZIP_BZIP2) +- # Check if bzip2 is present +- set(QUAZIP_BZIP2 ON) +- +- if(NOT QUAZIP_FORCE_FETCH_LIBS) +- find_package(BZip2 QUIET) +- endif() +- +- if(BZIP2_FOUND AND NOT QUAZIP_FORCE_FETCH_LIBS) +- message(STATUS "Using BZIP2 ${BZIP2_VERSION_STRING}") +- +- list(APPEND QUAZIP_INC ${BZIP2_INCLUDE_DIRS}) +- list(APPEND QUAZIP_LIB ${BZIP2_LIBRARIES}) +- list(APPEND QUAZIP_LBD ${BZIP2_LIBRARY_DIRS}) +- +- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lbzip2") +- elseif(QUAZIP_FETCH_LIBS) +- clone_repo(bzip2 https://sourceware.org/git/bzip2.git) +- +- # BZip2 repository does not support cmake so we have to create +- # the bzip2 library ourselves +- set(BZIP2_SRC +- ${BZIP2_SOURCE_DIR}/blocksort.c +- ${BZIP2_SOURCE_DIR}/bzlib.c +- ${BZIP2_SOURCE_DIR}/compress.c +- ${BZIP2_SOURCE_DIR}/crctable.c +- ${BZIP2_SOURCE_DIR}/decompress.c +- ${BZIP2_SOURCE_DIR}/huffman.c +- ${BZIP2_SOURCE_DIR}/randtable.c) +- +- set(BZIP2_HDR +- ${BZIP2_SOURCE_DIR}/bzlib.h +- ${BZIP2_SOURCE_DIR}/bzlib_private.h) +- +- add_library(bzip2 STATIC ${BZIP2_SRC} ${BZIP2_HDR}) +- +- if(NOT QUAZIP_BZIP2_STDIO) +- target_compile_definitions(bzip2 PRIVATE -DBZ_NO_STDIO) +- endif() +- +- list(APPEND QUAZIP_DEP bzip2) +- list(APPEND QUAZIP_LIB bzip2) +- list(APPEND QUAZIP_INC ${BZIP2_SOURCE_DIR}) +- else() +- message(STATUS "BZip2 library not found") +- +- set(QUAZIP_BZIP2 OFF) +- endif() +- +- if(QUAZIP_BZIP2) +- find_package(BZip2) +- add_compile_definitions(HAVE_BZIP2) +- endif() +-endif() +- + add_subdirectory(quazip) +- +-if(QUAZIP_ENABLE_TESTS) +- message(STATUS "Building QuaZip tests") +- enable_testing() +- add_subdirectory(qztest) +-endif() +diff --git a/quazip/CMakeLists.txt b/quazip/CMakeLists.txt +index 6cfdf4e..66bc4cb 100644 +--- a/quazip/CMakeLists.txt ++++ b/quazip/CMakeLists.txt +@@ -46,10 +46,6 @@ set(QUAZIP_INCLUDE_PATH ${QUAZIP_DIR_NAME}/quazip) + set(QUAZIP_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake) + set(QUAZIP_PKGCONFIG_NAME quazip${QuaZip_VERSION_MAJOR}-qt${QUAZIP_QT_MAJOR_VERSION}) + +-if(EMSCRIPTEN) +- set(BUILD_SHARED_LIBS OFF) +-endif() +- + add_library(${QUAZIP_LIB_TARGET_NAME} ${QUAZIP_SOURCES}) + add_library(QuaZip::QuaZip ALIAS ${QUAZIP_LIB_TARGET_NAME}) + +diff --git a/quazip/quazip_qt_compat.h b/quazip/quazip_qt_compat.h +index 0dde011..41f9dd1 100644 +--- a/quazip/quazip_qt_compat.h ++++ b/quazip/quazip_qt_compat.h +@@ -14,16 +14,11 @@ + + // Legacy encodings are still everywhere, but the Qt team decided we + // don't need them anymore and moved them out of Core in Qt 6. +-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +-# include +-#else +-# include +-#endif ++#include + + // QSaveFile terribly breaks the is-a idiom (Liskov substitution principle): + // QSaveFile is-a QIODevice, but it makes close() private and aborts + // if you call it through the base class. Hence this ugly hack: +-#if (QT_VERSION >= 0x050100) + #include + inline bool quazip_close(QIODevice *device) { + QSaveFile *file = qobject_cast(device); +@@ -34,74 +29,35 @@ inline bool quazip_close(QIODevice *device) { + device->close(); + return true; + } +-#else +-inline bool quazip_close(QIODevice *device) { +- device->close(); +- return true; +-} +-#endif + +-// this is yet another stupid move and deprecation +-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + using Qt::SkipEmptyParts; +-#else +-#include +-const auto SkipEmptyParts = QString::SplitBehavior::SkipEmptyParts; +-#endif + + // and yet another... (why didn't they just make qSort delegate to std::sort?) + #include +-#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)) + #include + template + inline void quazip_sort(T begin, T end, C comparator) { + std::sort(begin, end, comparator); + } +-#else +-#include +-template +-inline void quazip_sort(T begin, T end, C comparator) { +- qSort(begin, end, comparator); +-} +-#endif + + // this is a stupid rename... + #include + #include +-#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + inline QDateTime quazip_ctime(const QFileInfo &fi) { + return fi.birthTime(); + } +-#else +-inline QDateTime quazip_ctime(const QFileInfo &fi) { +- return fi.created(); +-} +-#endif + + // this is just a slightly better alternative + #include +-#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + inline bool quazip_is_symlink(const QFileInfo &fi) { + return fi.isSymbolicLink(); + } +-#else +-inline bool quazip_is_symlink(const QFileInfo &fi) { +- // also detects *.lnk on Windows, but better than nothing +- return fi.isSymLink(); +-} +-#endif + + // I'm not even sure what this one is, but nevertheless + #include +-#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) + inline QString quazip_symlink_target(const QFileInfo &fi) { + return fi.symLinkTarget(); + } +-#else +-inline QString quazip_symlink_target(const QFileInfo &fi) { +- return fi.readLink(); // What's the difference? I've no idea. +-} +-#endif + + // deprecation + #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +@@ -125,40 +81,19 @@ inline QDateTime quazip_since_epoch_ntfs() { + + // this is not a deprecation but an improvement, for a change + #include +-#if (QT_VERSION >= 0x040700) + inline quint64 quazip_ntfs_ticks(const QDateTime &time, int fineTicks) { + QDateTime base = quazip_since_epoch_ntfs(); + return base.msecsTo(time) * 10000 + fineTicks; + } +-#else +-inline quint64 quazip_ntfs_ticks(const QDateTime &time, int fineTicks) { +- QDateTime base = quazip_since_epoch_ntfs(); +- QDateTime utc = time.toUTC(); +- return (static_cast(base.date().daysTo(utc.date())) +- * Q_INT64_C(86400000) +- + static_cast(base.time().msecsTo(utc.time()))) +- * Q_INT64_C(10000) + fineTicks; +-} +-#endif + + // yet another improvement... + #include +-#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // Yay! Finally a way to get time as qint64! + inline qint64 quazip_to_time64_t(const QDateTime &time) { + return time.toSecsSinceEpoch(); + } +-#else +-inline qint64 quazip_to_time64_t(const QDateTime &time) { +- return static_cast(time.toTime_t()); // 32 bits only, but better than nothing +-} +-#endif + + #include +-// and another stupid move +-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + const auto quazip_endl = Qt::endl; +-#else +-const auto quazip_endl = endl; +-#endif + + #endif // QUAZIP_QT_COMPAT_H ++ diff --git a/CMakeLists.txt b/CMakeLists.txt index 1efa94e45a..124a5ac80a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,10 +29,10 @@ elseif (TARGET SDL2::SDL2-shared) endif() # Set bundled sdl2/qt as dependent options. +# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF) if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - # On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "ENABLE_SDL2;NOT MSVC" OFF) else() CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF) @@ -60,7 +60,7 @@ endif() if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" OFF) else() - option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON) + option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON) endif() if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") @@ -79,6 +79,8 @@ option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) +set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries") + option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) @@ -465,12 +467,10 @@ if (ENABLE_QT) list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}") endif() - # QT6 Multimedia pulls in unneeded audio systems (ALSA, Pulseaudio) for FreeBSD - # ALSA is the default sound system on Linux, but FreeBSD uses OSS which works well enough - if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent) - else() - find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent) + find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent) + + if (YUZU_USE_QT_MULTIMEDIA) + find_package(Qt6 REQUIRED COMPONENTS Multimedia) endif() if (UNIX AND NOT APPLE) diff --git a/CMakeModules/CPM.cmake b/CMakeModules/CPM.cmake new file mode 100644 index 0000000000..84748734ce --- /dev/null +++ b/CMakeModules/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.42.0) +set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index a82d1d72a3..e65827290d 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -94,7 +94,7 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out else() set(host "linux") set(type "desktop") - set(arch "gcc_64") + set(arch "linux_gcc_64") set(arch_path "linux") endif() @@ -133,12 +133,26 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target}) else() set(prefix "${base_path}/${target}/${arch_path}") - set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt3d qt5compat qtactiveqt qtcharts qtconnectivity qtdatavis3d qtgraphs qtgrpc qthttpserver qtimageformats qtlanguageserver qtlocation qtlottie qtmultimedia qtnetworkauth qtpdf qtpositioning qtquick3d qtquick3dphysics qtquickeffectmaker qtquicktimeline qtremoteobjects qtscxml qtsensors qtserialbus qtserialport qtshadertools qtspeech qtvirtualkeyboard qtwebchannel qtwebengine qtwebsockets qtwebview) + set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qtbase) + + if (YUZU_USE_QT_MULTIMEDIA) + set(install_args ${install_args} qtmultimedia) + endif() + + if (YUZU_USE_QT_WEB_ENGINE) + set(install_args ${install_args} qtpositioning qtwebchannel qtwebengine) + endif() + + if (NOT ${YUZU_QT_MIRROR} STREQUAL "") + message(STATUS "Using Qt mirror ${YUZU_QT_MIRROR}") + set(install_args ${install_args} -b ${YUZU_QT_MIRROR}) + endif() endif() + message(STATUS "Install Args ${install_args}") if (NOT EXISTS "${prefix}") message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}") - set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.2.1") + set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0") if (WIN32) set(aqt_path "${base_path}/aqt.exe") if (NOT EXISTS "${aqt_path}") diff --git a/externals/dynarmic/CMakeLists.txt b/externals/dynarmic/CMakeLists.txt index efb5edf165..3db8d8077b 100644 --- a/externals/dynarmic/CMakeLists.txt +++ b/externals/dynarmic/CMakeLists.txt @@ -98,8 +98,7 @@ else() -Wextra -Wcast-qual -pedantic - -Wno-missing-braces - -Wstack-usage=4096) + -Wno-missing-braces) if (ARCHITECTURE STREQUAL "x86_64") list(APPEND DYNARMIC_CXX_FLAGS -mtune=core2) @@ -123,12 +122,15 @@ else() # GCC knows that the variable is actually a Reg64. isMEM() will never return true for a # Reg64, but GCC doesn't know that. list(APPEND DYNARMIC_CXX_FLAGS -Wno-array-bounds) + list(APPEND DYNARMIC_CXX_FLAGS -Wstack-usage=4096) endif() if (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang") # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. # And this in turns limits the size of a std::array. list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024) + # Clang mistakenly blames CMake for using unused arguments during compilation + list(APPEND DYNARMIC_CXX_FLAGS -Wno-unused-command-line-argument) endif() endif() diff --git a/externals/dynarmic/src/dynarmic/CMakeLists.txt b/externals/dynarmic/src/dynarmic/CMakeLists.txt index 9227951fcc..a43c9eae10 100644 --- a/externals/dynarmic/src/dynarmic/CMakeLists.txt +++ b/externals/dynarmic/src/dynarmic/CMakeLists.txt @@ -125,52 +125,6 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) frontend/A32/translate/a32_translate.h frontend/A32/translate/conditional_state.cpp frontend/A32/translate/conditional_state.h - frontend/A32/translate/impl/a32_branch.cpp - frontend/A32/translate/impl/a32_crc32.cpp - frontend/A32/translate/impl/a32_exception_generating.cpp - frontend/A32/translate/impl/a32_translate_impl.cpp - frontend/A32/translate/impl/a32_translate_impl.h - frontend/A32/translate/impl/asimd_load_store_structures.cpp - frontend/A32/translate/impl/asimd_misc.cpp - frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp - frontend/A32/translate/impl/asimd_three_regs.cpp - frontend/A32/translate/impl/asimd_two_regs_misc.cpp - frontend/A32/translate/impl/asimd_two_regs_scalar.cpp - frontend/A32/translate/impl/asimd_two_regs_shift.cpp - frontend/A32/translate/impl/barrier.cpp - frontend/A32/translate/impl/coprocessor.cpp - frontend/A32/translate/impl/data_processing.cpp - frontend/A32/translate/impl/divide.cpp - frontend/A32/translate/impl/extension.cpp - frontend/A32/translate/impl/hint.cpp - frontend/A32/translate/impl/load_store.cpp - frontend/A32/translate/impl/misc.cpp - frontend/A32/translate/impl/multiply.cpp - frontend/A32/translate/impl/packing.cpp - frontend/A32/translate/impl/parallel.cpp - frontend/A32/translate/impl/reversal.cpp - frontend/A32/translate/impl/saturated.cpp - frontend/A32/translate/impl/status_register_access.cpp - frontend/A32/translate/impl/synchronization.cpp - frontend/A32/translate/impl/thumb16.cpp - frontend/A32/translate/impl/thumb32_branch.cpp - frontend/A32/translate/impl/thumb32_control.cpp - frontend/A32/translate/impl/thumb32_coprocessor.cpp - frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp - frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp - frontend/A32/translate/impl/thumb32_data_processing_register.cpp - frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp - frontend/A32/translate/impl/thumb32_load_byte.cpp - frontend/A32/translate/impl/thumb32_load_halfword.cpp - frontend/A32/translate/impl/thumb32_load_store_dual.cpp - frontend/A32/translate/impl/thumb32_load_store_multiple.cpp - frontend/A32/translate/impl/thumb32_load_word.cpp - frontend/A32/translate/impl/thumb32_long_multiply.cpp - frontend/A32/translate/impl/thumb32_misc.cpp - frontend/A32/translate/impl/thumb32_multiply.cpp - frontend/A32/translate/impl/thumb32_parallel.cpp - frontend/A32/translate/impl/thumb32_store_single_data_item.cpp - frontend/A32/translate/impl/vfp.cpp frontend/A32/translate/translate_arm.cpp frontend/A32/translate/translate_thumb.cpp interface/A32/a32.h @@ -194,65 +148,6 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS) frontend/A64/decoder/a64.inc frontend/A64/translate/a64_translate.cpp frontend/A64/translate/a64_translate.h - frontend/A64/translate/impl/a64_branch.cpp - frontend/A64/translate/impl/a64_exception_generating.cpp - frontend/A64/translate/impl/data_processing_addsub.cpp - frontend/A64/translate/impl/data_processing_bitfield.cpp - frontend/A64/translate/impl/data_processing_conditional_compare.cpp - frontend/A64/translate/impl/data_processing_conditional_select.cpp - frontend/A64/translate/impl/data_processing_crc32.cpp - frontend/A64/translate/impl/data_processing_logical.cpp - frontend/A64/translate/impl/data_processing_multiply.cpp - frontend/A64/translate/impl/data_processing_pcrel.cpp - frontend/A64/translate/impl/data_processing_register.cpp - frontend/A64/translate/impl/data_processing_shift.cpp - frontend/A64/translate/impl/floating_point_compare.cpp - frontend/A64/translate/impl/floating_point_conditional_compare.cpp - frontend/A64/translate/impl/floating_point_conditional_select.cpp - frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp - frontend/A64/translate/impl/floating_point_conversion_integer.cpp - frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp - frontend/A64/translate/impl/floating_point_data_processing_three_register.cpp - frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp - frontend/A64/translate/impl/impl.cpp - frontend/A64/translate/impl/impl.h - frontend/A64/translate/impl/load_store_exclusive.cpp - frontend/A64/translate/impl/load_store_load_literal.cpp - frontend/A64/translate/impl/load_store_multiple_structures.cpp - frontend/A64/translate/impl/load_store_no_allocate_pair.cpp - frontend/A64/translate/impl/load_store_register_immediate.cpp - frontend/A64/translate/impl/load_store_register_pair.cpp - frontend/A64/translate/impl/load_store_register_register_offset.cpp - frontend/A64/translate/impl/load_store_register_unprivileged.cpp - frontend/A64/translate/impl/load_store_single_structure.cpp - frontend/A64/translate/impl/move_wide.cpp - frontend/A64/translate/impl/simd_across_lanes.cpp - frontend/A64/translate/impl/simd_aes.cpp - frontend/A64/translate/impl/simd_copy.cpp - frontend/A64/translate/impl/simd_crypto_four_register.cpp - frontend/A64/translate/impl/simd_crypto_three_register.cpp - frontend/A64/translate/impl/simd_extract.cpp - frontend/A64/translate/impl/simd_modified_immediate.cpp - frontend/A64/translate/impl/simd_permute.cpp - frontend/A64/translate/impl/simd_scalar_pairwise.cpp - frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp - frontend/A64/translate/impl/simd_scalar_three_same.cpp - frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp - frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp - frontend/A64/translate/impl/simd_sha.cpp - frontend/A64/translate/impl/simd_sha512.cpp - frontend/A64/translate/impl/simd_shift_by_immediate.cpp - frontend/A64/translate/impl/simd_table_lookup.cpp - frontend/A64/translate/impl/simd_three_different.cpp - frontend/A64/translate/impl/simd_three_same.cpp - frontend/A64/translate/impl/simd_three_same_extra.cpp - frontend/A64/translate/impl/simd_two_register_misc.cpp - frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp - frontend/A64/translate/impl/sys_dc.cpp - frontend/A64/translate/impl/sys_ic.cpp - frontend/A64/translate/impl/system.cpp - frontend/A64/translate/impl/system_flag_format.cpp - frontend/A64/translate/impl/system_flag_manipulation.cpp interface/A64/a64.h interface/A64/config.h ir/opt/a64_callback_config_pass.cpp diff --git a/externals/dynarmic/src/dynarmic/backend/arm64/abi.h b/externals/dynarmic/src/dynarmic/backend/arm64/abi.h index 609b06cd22..d3d5de963a 100644 --- a/externals/dynarmic/src/dynarmic/backend/arm64/abi.h +++ b/externals/dynarmic/src/dynarmic/backend/arm64/abi.h @@ -59,13 +59,12 @@ constexpr RegisterList ToRegList(oaknut::Reg reg) { } if (reg.index() == 31) { - throw std::out_of_range("ZR not allowed in reg list"); + ASSERT_FALSE("ZR not allowed in reg list"); } if (reg.index() == -1) { return RegisterList{1} << 31; } - return RegisterList{1} << reg.index(); } diff --git a/externals/dynarmic/src/dynarmic/backend/riscv64/code_block.h b/externals/dynarmic/src/dynarmic/backend/riscv64/code_block.h index 6ac014a51a..8f98fdf01f 100644 --- a/externals/dynarmic/src/dynarmic/backend/riscv64/code_block.h +++ b/externals/dynarmic/src/dynarmic/backend/riscv64/code_block.h @@ -14,29 +14,26 @@ namespace Dynarmic::Backend::RV64 { class CodeBlock { public: - explicit CodeBlock(std::size_t size) - : memsize(size) { + explicit CodeBlock(std::size_t size) noexcept : memsize(size) { mem = (u8*)mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); - if (mem == nullptr) - throw std::bad_alloc{}; + ASSERT_FALSE("out of memory"); } - ~CodeBlock() { + ~CodeBlock() noexcept { if (mem == nullptr) return; - munmap(mem, memsize); } template - T ptr() const { + T ptr() const noexcept { static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(mem); } protected: - u8* mem; + u8* mem = nullptr; size_t memsize = 0; }; } // namespace Dynarmic::Backend::RV64 diff --git a/externals/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/externals/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index ce38a52c73..740625c982 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -124,35 +124,36 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { EmitCondPrelude(ctx); - for (auto iter = block.begin(); iter != block.end(); ++iter) { - IR::Inst* inst = &*iter; - - // Call the relevant Emit* member function. - switch (inst->GetOpcode()) { -#define OPCODE(name, type, ...) \ - case IR::Opcode::name: \ - A32EmitX64::Emit##name(ctx, inst); \ - break; -#define A32OPC(name, type, ...) \ - case IR::Opcode::A32##name: \ - A32EmitX64::EmitA32##name(ctx, inst); \ - break; + auto const loop_all_inst = [this, &block, &ctx](auto const func) { + for (auto iter = block.begin(); iter != block.end(); ++iter) [[likely]] { + auto* inst = &*iter; + // Call the relevant Emit* member function. + switch (inst->GetOpcode()) { +#define OPCODE(name, type, ...) \ + case IR::Opcode::name: \ + A32EmitX64::Emit##name(ctx, inst); \ + break; +#define A32OPC(name, type, ...) \ + case IR::Opcode::A32##name: \ + A32EmitX64::EmitA32##name(ctx, inst);\ + break; #define A64OPC(...) #include "dynarmic/ir/opcodes.inc" #undef OPCODE #undef A32OPC #undef A64OPC - - default: - ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode()); - break; + default: [[unlikely]] ASSERT_FALSE("Invalid opcode: {}", inst->GetOpcode()); + } + reg_alloc.EndOfAllocScope(); + func(reg_alloc); } - - reg_alloc.EndOfAllocScope(); - - if (conf.very_verbose_debugging_output) { + }; + if (!conf.very_verbose_debugging_output) [[likely]] { + loop_all_inst([](auto&) { /*noop*/ }); + } else [[unlikely]] { + loop_all_inst([this](auto& reg_alloc) { EmitVerboseDebuggingOutput(reg_alloc); - } + }); } reg_alloc.AssertNoMoreUses(); @@ -229,7 +230,7 @@ void A32EmitX64::GenTerminalHandlers() { terminal_handler_pop_rsb_hint = code.getCurr(); calculate_location_descriptor(); code.mov(eax, dword[r15 + offsetof(A32JitState, rsb_ptr)]); - code.sub(eax, 1); + code.dec(eax); code.and_(eax, u32(A32JitState::RSBPtrMask)); code.mov(dword[r15 + offsetof(A32JitState, rsb_ptr)], eax); code.cmp(rbx, qword[r15 + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]); diff --git a/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index ad84e0ecc0..4d7bb0d7b1 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -198,18 +198,19 @@ void A64EmitX64::GenTerminalHandlers() { code.or_(rbx, rcx); }; - Xbyak::Label fast_dispatch_cache_miss, rsb_cache_miss; + Xbyak::Label fast_dispatch_cache_miss; + Xbyak::Label rsb_cache_miss; code.align(); terminal_handler_pop_rsb_hint = code.getCurr(); calculate_location_descriptor(); code.mov(eax, dword[r15 + offsetof(A64JitState, rsb_ptr)]); - code.sub(eax, 1); + code.dec(eax); code.and_(eax, u32(A64JitState::RSBPtrMask)); code.mov(dword[r15 + offsetof(A64JitState, rsb_ptr)], eax); code.cmp(rbx, qword[r15 + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]); if (conf.HasOptimization(OptimizationFlag::FastDispatch)) { - code.jne(rsb_cache_miss); + code.jne(rsb_cache_miss, code.T_NEAR); } else { code.jne(code.GetReturnFromRunCodeAddress()); } diff --git a/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp b/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp index 450b16d000..fe7dfa011f 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp @@ -33,13 +33,13 @@ void A64EmitX64::GenMemory128Accessors() { #ifdef _WIN32 Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCallWithReturnPointer(code, [&](Xbyak::Reg64 return_value_ptr, [[maybe_unused]] RegList args) { code.mov(code.ABI_PARAM3, code.ABI_PARAM2); - code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (8 + 16 + ABI_SHADOW_SPACE)]); code.lea(return_value_ptr, ptr[rsp + ABI_SHADOW_SPACE]); }); code.movups(xmm1, xword[code.ABI_RETURN]); code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE); #else - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCall(code); if (code.HasHostFeature(HostFeature::SSE41)) { code.movq(xmm1, code.ABI_RETURN); @@ -57,13 +57,13 @@ void A64EmitX64::GenMemory128Accessors() { code.align(); memory_write_128 = code.getCurr(); #ifdef _WIN32 - code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (8 + 16 + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); code.movaps(xword[code.ABI_PARAM3], xmm1); Devirtualize<&A64::UserCallbacks::MemoryWrite128>(conf.callbacks).EmitCall(code); code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE); #else - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); if (code.HasHostFeature(HostFeature::SSE41)) { code.movq(code.ABI_PARAM3, xmm1); code.pextrq(code.ABI_PARAM4, xmm1, 1); @@ -81,7 +81,7 @@ void A64EmitX64::GenMemory128Accessors() { code.align(); memory_exclusive_write_128 = code.getCurr(); #ifdef _WIN32 - code.sub(rsp, 8 + 32 + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (8 + 32 + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); code.lea(code.ABI_PARAM4, ptr[rsp + ABI_SHADOW_SPACE + 16]); code.movaps(xword[code.ABI_PARAM3], xmm1); @@ -89,7 +89,7 @@ void A64EmitX64::GenMemory128Accessors() { Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive128>(conf.callbacks).EmitCall(code); code.add(rsp, 8 + 32 + ABI_SHADOW_SPACE); #else - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); if (code.HasHostFeature(HostFeature::SSE41)) { code.movq(code.ABI_PARAM3, xmm1); code.pextrq(code.ABI_PARAM4, xmm1, 1); @@ -131,8 +131,8 @@ void A64EmitX64::GenFastmemFallbacks() { {64, Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive64>(conf.callbacks)}, }}; - for (bool ordered : {false, true}) { - for (int vaddr_idx : idxes) { + for (auto const ordered : {false, true}) { + for (auto const vaddr_idx : idxes) { if (vaddr_idx == 4 || vaddr_idx == 15) { continue; } diff --git a/externals/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/externals/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 22d9868fc5..e5fb25573b 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -63,7 +63,8 @@ public: uint8_t* alloc(size_t size) override { void* p = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); if (p == nullptr) { - throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC); + using Xbyak::Error; + XBYAK_THROW(Xbyak::ERR_CANT_ALLOC); } return static_cast(p); } @@ -95,7 +96,8 @@ public: void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0); if (p == MAP_FAILED) { - throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC); + using Xbyak::Error; + XBYAK_THROW(Xbyak::ERR_CANT_ALLOC); } std::memcpy(p, &size, sizeof(size_t)); return static_cast(p) + DYNARMIC_PAGE_SIZE; @@ -514,7 +516,8 @@ size_t BlockOfCode::GetTotalCodeSize() const { void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) { if (size_ + alloc_size >= maxSize_) { - throw Xbyak::Error(Xbyak::ERR_CODE_IS_TOO_BIG); + using Xbyak::Error; + XBYAK_THROW(Xbyak::ERR_CODE_IS_TOO_BIG); } EnsureMemoryCommitted(alloc_size); diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp index 8bd9102d0d..b9a705813f 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp @@ -104,7 +104,7 @@ void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, I } void EmitX64::EmitVerboseDebuggingOutput(RegAlloc& reg_alloc) { - code.sub(rsp, sizeof(RegisterData)); + code.lea(rsp, ptr[rsp - sizeof(RegisterData)]); code.stmxcsr(dword[rsp + offsetof(RegisterData, mxcsr)]); for (int i = 0; i < 16; i++) { if (rsp.getIdx() == i) { @@ -223,7 +223,7 @@ void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize); code.test(value, value); code.lahf(); - code.mov(al, 0); + code.xor_(al, al); ctx.reg_alloc.DefineValue(inst, nzcv); } @@ -270,7 +270,6 @@ void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) { code.shr(nzcv, 28); code.imul(nzcv, nzcv, NZCV::to_x64_multiplier); code.and_(nzcv, NZCV::x64_mask); - ctx.reg_alloc.DefineValue(inst, nzcv); } } @@ -331,10 +330,8 @@ Xbyak::Label EmitX64::EmitCond(IR::Cond cond) { code.jle(pass); break; default: - ASSERT_MSG(false, "Unknown cond {}", static_cast(cond)); - break; + UNREACHABLE(); } - return pass; } diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp index 98197c2db3..cb1afdec9e 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp @@ -992,7 +992,6 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit code.seto(overflow); ctx.reg_alloc.DefineValue(overflow_inst, overflow); } - ctx.reg_alloc.DefineValue(inst, result); } diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 182c887538..aeb4ceac3c 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -33,6 +33,23 @@ #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" +#define FCODE(NAME) \ + [&code](auto... args) { \ + if constexpr (fsize == 32) { \ + code.NAME##s(args...); \ + } else { \ + code.NAME##d(args...); \ + } \ + } +#define ICODE(NAME) \ + [&code](auto... args) { \ + if constexpr (fsize == 32) { \ + code.NAME##d(args...); \ + } else { \ + code.NAME##q(args...); \ + } \ + } + namespace Dynarmic::Backend::X64 { using namespace Xbyak::util; @@ -60,23 +77,6 @@ constexpr u64 f64_max_s32 = 0x41dfffffffc00000u; // 2147483647 as a double constexpr u64 f64_max_u32 = 0x41efffffffe00000u; // 4294967295 as a double constexpr u64 f64_max_s64_lim = 0x43e0000000000000u; // 2^63 as a double (actual maximum unrepresentable) -#define FCODE(NAME) \ - [&code](auto... args) { \ - if constexpr (fsize == 32) { \ - code.NAME##s(args...); \ - } else { \ - code.NAME##d(args...); \ - } \ - } -#define ICODE(NAME) \ - [&code](auto... args) { \ - if constexpr (fsize == 32) { \ - code.NAME##d(args...); \ - } else { \ - code.NAME##q(args...); \ - } \ - } - template void ForceDenormalsToZero(BlockOfCode& code, std::initializer_list to_daz) { if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) { @@ -473,7 +473,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { } template -static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { +static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) noexcept { using FPT = mcl::unsigned_integer_of_size; constexpr FPT default_nan = FP::FPInfo::DefaultNaN(); @@ -701,15 +701,14 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { // x64 rounds before flushing to zero // AArch64 rounds after flushing to zero // This difference of behaviour is noticable if something would round to a smallest normalized number - - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); code.movq(code.ABI_PARAM1, operand1); code.movq(code.ABI_PARAM2, operand2); code.movq(code.ABI_PARAM3, operand3); code.mov(code.ABI_PARAM4.cvt32(), ctx.FPCR().Value()); #ifdef _WIN32 - code.sub(rsp, 16 + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (16 + ABI_SHADOW_SPACE)]); code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(qword[rsp + ABI_SHADOW_SPACE], rax); code.CallFunction(fallback_fn); @@ -735,13 +734,13 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { code.vmovaps(xmm0, code.Const(xword, FP::FPInfo::mantissa_msb)); FCODE(ucomis)(operand2, operand3); - code.jp(has_nan); + code.jp(has_nan, code.T_NEAR); FCODE(ucomis)(operand1, operand1); - code.jnp(indeterminate); + code.jnp(indeterminate, code.T_NEAR); // AArch64 specifically emits a default NaN for the case when the addend is a QNaN and the two other arguments are {inf, zero} code.ptest(operand1, xmm0); - code.jz(op1_snan); + code.jz(op1_snan, code.T_NEAR); FCODE(vmuls)(xmm0, operand2, operand3); // check if {op2, op3} are {inf, zero}/{zero, inf} FCODE(ucomis)(xmm0, xmm0); code.jnp(*end); @@ -753,10 +752,10 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { code.L(has_nan); FCODE(ucomis)(operand1, operand1); - code.jnp(op1_done); + code.jnp(op1_done, code.T_NEAR); code.movaps(result, operand1); // this is done because of NaN behavior of vfmadd231s (priority of op2, op3, op1) code.ptest(operand1, xmm0); - code.jnz(op1_done); + code.jnz(op1_done, code.T_NEAR); code.L(op1_snan); code.vorps(result, operand1, xmm0); code.jmp(*end); @@ -774,9 +773,9 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { code.L(op2_done); FCODE(ucomis)(operand3, operand3); - code.jnp(op3_done); + code.jnp(op3_done, code.T_NEAR); code.ptest(operand3, xmm0); - code.jnz(op3_done); + code.jnz(op3_done, code.T_NEAR); code.vorps(result, operand3, xmm0); code.jmp(*end); code.L(op3_done); @@ -1019,7 +1018,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* ctx.deferred_emits.emplace_back([=, &code, &ctx] { code.L(*fallback); - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); code.movq(code.ABI_PARAM1, operand1); code.movq(code.ABI_PARAM2, operand2); @@ -1204,9 +1203,9 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i } // a > 0 && a < 0x00800000; - code.sub(tmp, 1); + code.dec(tmp); code.cmp(tmp, 0x007FFFFF); - code.jb(fallback); + code.jb(fallback, code.T_NEAR); //within -127,128 needs_fallback = true; } @@ -1235,17 +1234,17 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i code.ucomisd(value, result); if (ctx.FPCR().DN()) { - code.jc(default_nan); - code.je(zero); + code.jc(default_nan, code.T_NEAR); + code.je(zero, code.T_NEAR); } else { - code.jp(nan); - code.je(zero); - code.jc(default_nan); + code.jp(nan, code.T_NEAR); + code.je(zero, code.T_NEAR); + code.jc(default_nan, code.T_NEAR); } if (!ctx.FPCR().FZ()) { needs_fallback = true; - code.jmp(fallback); + code.jmp(fallback, code.T_NEAR); } else { // result = 0 code.jmp(*end, code.T_NEAR); @@ -1278,7 +1277,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i code.L(fallback); if (needs_fallback) { - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); code.movq(code.ABI_PARAM1, operand); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); @@ -1361,7 +1360,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* ctx.deferred_emits.emplace_back([=, &code, &ctx] { code.L(*fallback); - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); code.movq(code.ABI_PARAM1, operand1); code.movq(code.ABI_PARAM2, operand2); @@ -2132,3 +2131,6 @@ void EmitX64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(inst, result); } } // namespace Dynarmic::Backend::X64 + +#undef FCODE +#undef ICODE diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h index c99980d617..b25b33101c 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h @@ -161,8 +161,7 @@ template<> template<> [[maybe_unused]] Xbyak::RegExp EmitFastmemVAddr(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling, std::optional tmp) { - const size_t unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits; - + auto const unused_top_bits = 64 - ctx.conf.fastmem_address_space_bits; if (unused_top_bits == 0) { return r13 + vaddr; } else if (ctx.conf.silently_mirror_fastmem) { @@ -306,7 +305,7 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int code.L(loop); code.lock(); code.cmpxchg16b(xword[addr]); - code.jnz(loop); + code.jnz(loop, code.T_NEAR); break; } default: @@ -373,7 +372,7 @@ void EmitExclusiveTestAndClear(BlockOfCode& code, const UserConfig& conf, Xbyak: Xbyak::Label ok; code.mov(pointer, mcl::bit_cast(GetExclusiveMonitorAddressPointer(conf.global_monitor, processor_index))); code.cmp(qword[pointer], vaddr); - code.jne(ok); + code.jne(ok, code.T_NEAR); code.mov(qword[pointer], tmp); code.L(ok); } diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index b8aa3eb653..88d0786b03 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -33,13 +33,6 @@ #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" -namespace Dynarmic::Backend::X64 { - -using namespace Xbyak::util; -namespace mp = mcl::mp; - -namespace { - #define FCODE(NAME) \ [&code](auto... args) { \ if constexpr (fsize == 32) { \ @@ -57,6 +50,13 @@ namespace { } \ } +namespace Dynarmic::Backend::X64 { + +using namespace Xbyak::util; +namespace mp = mcl::mp; + +namespace { + template void MaybeStandardFPSCRValue(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, Lambda lambda) { const bool switch_mxcsr = ctx.FPCR(fpcr_controlled) != ctx.FPCR(); @@ -122,11 +122,11 @@ void HandleNaNs(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, std:: const Xbyak::Xmm result = xmms[0]; - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); const size_t stack_space = xmms.size() * 16; - code.sub(rsp, static_cast(stack_space + ABI_SHADOW_SPACE)); + code.lea(rsp, ptr[rsp - static_cast(stack_space + ABI_SHADOW_SPACE)]); for (size_t i = 0; i < xmms.size(); ++i) { code.movaps(xword[rsp + ABI_SHADOW_SPACE + i * 16], xmms[i]); } @@ -443,7 +443,7 @@ void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak const u32 fpcr = ctx.FPCR(fpcr_controlled).Value(); constexpr u32 stack_space = 2 * 16; - code.sub(rsp, stack_space + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.mov(code.ABI_PARAM3.cvt32(), fpcr); @@ -479,7 +479,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby #ifdef _WIN32 constexpr u32 stack_space = 4 * 16; - code.sub(rsp, stack_space + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]); @@ -488,7 +488,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby code.mov(qword[rsp + ABI_SHADOW_SPACE + 0], rax); #else constexpr u32 stack_space = 3 * 16; - code.sub(rsp, stack_space + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); @@ -536,7 +536,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya #ifdef _WIN32 constexpr u32 stack_space = 5 * 16; - code.sub(rsp, stack_space + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]); @@ -546,7 +546,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya code.mov(qword[rsp + ABI_SHADOW_SPACE + 8], rax); #else constexpr u32 stack_space = 4 * 16; - code.sub(rsp, stack_space + ABI_SHADOW_SPACE); + code.lea(rsp, ptr[rsp - (stack_space + ABI_SHADOW_SPACE)]); code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); @@ -1371,7 +1371,7 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { ctx.deferred_emits.emplace_back([=, &code, &ctx] { code.L(*fallback); - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); if (needs_rounding_correction && needs_nan_correction) { EmitFourOpFallbackWithoutRegAlloc(code, ctx, result, xmm_a, xmm_b, xmm_c, EmitFPVectorMulAddFallback, fpcr_controlled); @@ -1635,7 +1635,7 @@ static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in ctx.deferred_emits.emplace_back([=, &code, &ctx] { code.L(*fallback); - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); @@ -1812,7 +1812,7 @@ static void EmitRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* ins ctx.deferred_emits.emplace_back([=, &code, &ctx] { code.L(*bad_values); - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); EmitTwoOpFallbackWithoutRegAlloc(code, ctx, result, operand, fallback_fn, fpcr_controlled); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); @@ -1898,7 +1898,7 @@ static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* in ctx.deferred_emits.emplace_back([=, &code, &ctx] { code.L(*fallback); - code.sub(rsp, 8); + code.lea(rsp, ptr[rsp - 8]); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); EmitThreeOpFallbackWithoutRegAlloc(code, ctx, result, operand1, operand2, fallback_fn, fpcr_controlled); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); @@ -2180,3 +2180,6 @@ void EmitX64::EmitFPVectorToUnsignedFixed64(EmitContext& ctx, IR::Inst* inst) { } } // namespace Dynarmic::Backend::X64 + +#undef FCODE +#undef ICODE diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp index fb30549fb0..5bab9c93f4 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp @@ -338,3 +338,6 @@ void EmitX64::EmitVectorUnsignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst) } } // namespace Dynarmic::Backend::X64 + +#undef FCODE +#undef ICODE diff --git a/externals/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp b/externals/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp index a7f964337a..633e1aac9d 100644 --- a/externals/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp @@ -186,7 +186,7 @@ struct ExceptionHandler::Impl final { code.cmp(code.rax, static_cast(code.GetTotalCodeSize())); code.ja(exception_handler_without_cb); - code.sub(code.rsp, 8); + code.lea(code.rsp, code.ptr[code.rsp - 8]); code.mov(code.ABI_PARAM1, mcl::bit_cast(&cb)); code.mov(code.ABI_PARAM2, code.ABI_PARAM3); code.CallLambda( diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/a32_ir_emitter.h b/externals/dynarmic/src/dynarmic/frontend/A32/a32_ir_emitter.h index 9fde4f8775..38160f96d4 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/a32_ir_emitter.h +++ b/externals/dynarmic/src/dynarmic/frontend/A32/a32_ir_emitter.h @@ -15,7 +15,7 @@ namespace Dynarmic::A32 { -enum class ArchVersion; +enum class ArchVersion : std::uint8_t; enum class CoprocReg; enum class Exception; enum class ExtReg; @@ -27,12 +27,11 @@ enum class Reg; * The user of this class updates `current_location` as appropriate. */ class IREmitter : public IR::IREmitter { + IR::U64 ImmCurrentLocationDescriptor(); public: IREmitter(IR::Block& block, LocationDescriptor descriptor, ArchVersion arch_version) : IR::IREmitter(block), current_location(descriptor), arch_version(arch_version) {} - - LocationDescriptor current_location; - + size_t ArchVersion() const; u32 PC() const; @@ -107,10 +106,9 @@ public: IR::U64 CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, CoprocReg CRm); void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option); void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, CoprocReg CRd, const IR::U32& address, bool has_option, u8 option); - -private: +public: + LocationDescriptor current_location; enum ArchVersion arch_version; - IR::U64 ImmCurrentLocationDescriptor(); }; } // namespace Dynarmic::A32 diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h b/externals/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h index 16ae52e13a..e4cf4a2865 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h +++ b/externals/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h @@ -33,13 +33,11 @@ inline size_t ToFastLookupIndexArm(u32 instruction) { } // namespace detail template -ArmDecodeTable GetArmDecodeTable() { +constexpr ArmDecodeTable GetArmDecodeTable() { std::vector> list = { - #define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./arm.inc" #undef INST - }; // If a matcher has more bits in its mask it is more specific, so it should come first. @@ -62,9 +60,10 @@ ArmDecodeTable GetArmDecodeTable() { template std::optional>> DecodeArm(u32 instruction) { - static const auto table = GetArmDecodeTable(); - - const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); }; + alignas(64) static const auto table = GetArmDecodeTable(); + const auto matches_instruction = [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }; const auto& subtable = table[detail::ToFastLookupIndexArm(instruction)]; auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction); diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp index 97a7f11adf..2e69927ace 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp @@ -25,3 +25,51 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, } } // namespace Dynarmic::A32 + +// ls -l | awk '{print "#include \"dynarmic/frontend/A32/translate/impl/" $9 "\""}' +#include "dynarmic/frontend/A32/translate/impl/a32_branch.cpp" +#include "dynarmic/frontend/A32/translate/impl/a32_crc32.cpp" +#include "dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp" +#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp" +//#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp" +#include "dynarmic/frontend/A32/translate/impl/asimd_misc.cpp" +#include "dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp" +#include "dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp" +#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp" +#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp" +#include "dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp" +#include "dynarmic/frontend/A32/translate/impl/barrier.cpp" +#include "dynarmic/frontend/A32/translate/impl/coprocessor.cpp" +#include "dynarmic/frontend/A32/translate/impl/data_processing.cpp" +#include "dynarmic/frontend/A32/translate/impl/divide.cpp" +#include "dynarmic/frontend/A32/translate/impl/extension.cpp" +#include "dynarmic/frontend/A32/translate/impl/hint.cpp" +#include "dynarmic/frontend/A32/translate/impl/load_store.cpp" +#include "dynarmic/frontend/A32/translate/impl/misc.cpp" +#include "dynarmic/frontend/A32/translate/impl/multiply.cpp" +#include "dynarmic/frontend/A32/translate/impl/packing.cpp" +#include "dynarmic/frontend/A32/translate/impl/parallel.cpp" +#include "dynarmic/frontend/A32/translate/impl/reversal.cpp" +#include "dynarmic/frontend/A32/translate/impl/saturated.cpp" +#include "dynarmic/frontend/A32/translate/impl/status_register_access.cpp" +#include "dynarmic/frontend/A32/translate/impl/synchronization.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb16.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_branch.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_control.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_coprocessor.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_long_multiply.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_misc.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_multiply.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp" +#include "dynarmic/frontend/A32/translate/impl/thumb32_store_single_data_item.cpp" +#include "dynarmic/frontend/A32/translate/impl/vfp.cpp" diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp index 276f8384e7..c83529f343 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.cpp @@ -11,6 +11,10 @@ namespace Dynarmic::A32 { +bool TranslatorVisitor::arm_NOP() { + return true; +} + bool TranslatorVisitor::ArmConditionPassed(Cond cond) { return IsConditionPassed(*this, cond); } diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h index 44ac24503c..d33069c6e0 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h @@ -258,7 +258,7 @@ struct TranslatorVisitor final { bool arm_CLZ(Cond cond, Reg d, Reg m); bool arm_MOVT(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12); bool arm_MOVW(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12); - bool arm_NOP() { return true; } + bool arm_NOP(); bool arm_RBIT(Cond cond, Reg d, Reg m); bool arm_SBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n); bool arm_SEL(Cond cond, Reg n, Reg d, Reg m); diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp index a69f39bfb6..da8f43f2fb 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp @@ -6,6 +6,7 @@ #include #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { namespace { @@ -17,11 +18,6 @@ enum class Comparison { AbsoluteGT, }; -enum class AccumulateBehavior { - None, - Accumulate, -}; - enum class WidenBehaviour { Second, Both, diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp index 62b9af55a5..ddae1f420b 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp @@ -8,10 +8,11 @@ #include #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { namespace { -enum class Comparison { +enum class ComparisonATRM { EQ, GE, GT, @@ -19,7 +20,7 @@ enum class Comparison { LT, }; -bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, Comparison type) { +bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, ComparisonATRM type) { if (sz == 0b11 || (F && sz != 0b10)) { return v.UndefinedInstruction(); } @@ -36,15 +37,15 @@ bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, if (F) { switch (type) { - case Comparison::EQ: + case ComparisonATRM::EQ: return v.ir.FPVectorEqual(32, reg_m, zero, false); - case Comparison::GE: + case ComparisonATRM::GE: return v.ir.FPVectorGreaterEqual(32, reg_m, zero, false); - case Comparison::GT: + case ComparisonATRM::GT: return v.ir.FPVectorGreater(32, reg_m, zero, false); - case Comparison::LE: + case ComparisonATRM::LE: return v.ir.FPVectorGreaterEqual(32, zero, reg_m, false); - case Comparison::LT: + case ComparisonATRM::LT: return v.ir.FPVectorGreater(32, zero, reg_m, false); } @@ -67,11 +68,6 @@ bool CompareWithZero(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, return true; } -enum class AccumulateBehavior { - None, - Accumulate, -}; - bool PairedAddOperation(TranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool op, bool Q, bool M, size_t Vm, AccumulateBehavior accumulate) { if (sz == 0b11) { return v.UndefinedInstruction(); @@ -385,23 +381,23 @@ bool TranslatorVisitor::asimd_VQNEG(bool D, size_t sz, size_t Vd, bool Q, bool M } bool TranslatorVisitor::asimd_VCGT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { - return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GT); + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::GT); } bool TranslatorVisitor::asimd_VCGE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { - return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GE); + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::GE); } bool TranslatorVisitor::asimd_VCEQ_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { - return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::EQ); + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::EQ); } bool TranslatorVisitor::asimd_VCLE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { - return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LE); + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::LE); } bool TranslatorVisitor::asimd_VCLT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { - return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LT); + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, ComparisonATRM::LT); } bool TranslatorVisitor::asimd_VABS(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index b7300f91e4..cbdfea04ce 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -16,7 +16,7 @@ enum class Accumulating { Accumulate }; -enum class Rounding { +enum class RoundingATRS { None, Round, }; @@ -32,7 +32,7 @@ enum class Signedness { Unsigned }; -IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) { +IR::U128 PerformRoundingATRSCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) { const auto round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value)); const auto round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(original, round_const), round_const); return v.ir.VectorSub(esize, shifted, round_correction); @@ -58,7 +58,7 @@ std::pair ElementSizeAndShiftAmount(bool right_shift, bool L, si } } -bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, Accumulating accumulate, Rounding rounding) { +bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, Accumulating accumulate, RoundingATRS RoundingATRS) { if (!L && mcl::bit::get_bits<3, 5>(imm6) == 0) { return v.DecodeError(); } @@ -75,9 +75,9 @@ bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bo auto result = U ? v.ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)) : v.ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); - if (rounding == Rounding::Round) { + if (RoundingATRS == RoundingATRS::Round) { const u64 round_value = 1ULL << (shift_amount - 1); - result = PerformRoundingCorrection(v, esize, round_value, reg_m, result); + result = PerformRoundingATRSCorrection(v, esize, round_value, reg_m, result); } if (accumulate == Accumulating::Accumulate) { @@ -89,7 +89,7 @@ bool ShiftRight(TranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bo return true; } -bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, bool M, size_t Vm, Rounding rounding, Narrowing narrowing, Signedness signedness) { +bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, bool M, size_t Vm, RoundingATRS RoundingATRS, Narrowing narrowing, Signedness signedness) { if (mcl::bit::get_bits<3, 5>(imm6) == 0) { return v.DecodeError(); } @@ -113,9 +113,9 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, b return v.ir.VectorLogicalShiftRight(source_esize, reg_m, shift_amount); }(); - if (rounding == Rounding::Round) { + if (RoundingATRS == RoundingATRS::Round) { const u64 round_value = 1ULL << (shift_amount - 1); - wide_result = PerformRoundingCorrection(v, source_esize, round_value, reg_m, wide_result); + wide_result = PerformRoundingATRSCorrection(v, source_esize, round_value, reg_m, wide_result); } const auto result = [&] { @@ -141,22 +141,22 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool D, size_t imm6, size_t Vd, b bool TranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, - Accumulating::None, Rounding::None); + Accumulating::None, RoundingATRS::None); } bool TranslatorVisitor::asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, - Accumulating::Accumulate, Rounding::None); + Accumulating::Accumulate, RoundingATRS::None); } bool TranslatorVisitor::asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, - Accumulating::None, Rounding::Round); + Accumulating::None, RoundingATRS::Round); } bool TranslatorVisitor::asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, - Accumulating::Accumulate, Rounding::Round); + Accumulating::Accumulate, RoundingATRS::Round); } bool TranslatorVisitor::asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { @@ -271,32 +271,32 @@ bool TranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool bool TranslatorVisitor::asimd_VSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm, - Rounding::None, Narrowing::Truncation, Signedness::Unsigned); + RoundingATRS::None, Narrowing::Truncation, Signedness::Unsigned); } bool TranslatorVisitor::asimd_VRSHRN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm, - Rounding::Round, Narrowing::Truncation, Signedness::Unsigned); + RoundingATRS::Round, Narrowing::Truncation, Signedness::Unsigned); } bool TranslatorVisitor::asimd_VQRSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm, - Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Signed); + RoundingATRS::Round, Narrowing::SaturateToUnsigned, Signedness::Signed); } bool TranslatorVisitor::asimd_VQSHRUN(bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm, - Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Signed); + RoundingATRS::None, Narrowing::SaturateToUnsigned, Signedness::Signed); } bool TranslatorVisitor::asimd_VQSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm, - Rounding::None, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed); + RoundingATRS::None, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed); } bool TranslatorVisitor::asimd_VQRSHRN(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { return ShiftRightNarrowing(*this, D, imm6, Vd, M, Vm, - Rounding::Round, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed); + RoundingATRS::Round, U ? Narrowing::SaturateToUnsigned : Narrowing::SaturateToSigned, U ? Signedness::Unsigned : Signedness::Signed); } bool TranslatorVisitor::asimd_VSHLL(bool U, bool D, size_t imm6, size_t Vd, bool M, size_t Vm) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/common.h b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/common.h new file mode 100644 index 0000000000..39b2c4355c --- /dev/null +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/common.h @@ -0,0 +1,31 @@ +#pragma once + +#include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" + +namespace Dynarmic::A32 { + +static inline IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) noexcept { + return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result); +} + +static inline IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) noexcept { + return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result); +} + +static inline IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) noexcept { + const u8 rotate_by = static_cast(static_cast(rotate) * 8); + return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result; +} + +static inline bool ITBlockCheck(const A32::IREmitter& ir) noexcept { + return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock(); +} + +using ExtensionFunctionU16 = IR::U32 (IREmitter::*)(const IR::U16&); + +enum class AccumulateBehavior { + None, + Accumulate, +}; + +} diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/extension.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/extension.cpp index 3ee6a670f0..518f8b944e 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/extension.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/extension.cpp @@ -4,14 +4,10 @@ */ #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) { - const u8 rotate_by = static_cast(static_cast(rotate) * 8); - return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result; -} - // SXTAB , , {, } bool TranslatorVisitor::arm_SXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) { if (d == Reg::PC || m == Reg::PC) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/saturated.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/saturated.cpp index 41db115044..2371e54ae7 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/saturated.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/saturated.cpp @@ -4,17 +4,10 @@ */ #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) { - return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result); -} - -static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { - return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result); -} - // Saturation instructions // SSAT , #, {, } diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 1a6767dbee..14a3fef2d1 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -7,15 +7,9 @@ #include #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) { - return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result); -} - -static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { - return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result); -} using SaturationFunction = IR::ResultAndOverflow (IREmitter::*)(const IR::U32&, size_t); diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp index 1dda532d92..1498ac6c7b 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_register.cpp @@ -4,13 +4,10 @@ */ #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { namespace { -IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) { - const u8 rotate_by = static_cast(static_cast(rotate) * 8); - return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result; -} using ShiftFunction = IR::ResultAndCarry (IREmitter::*)(const IR::U32&, const IR::U8&, const IR::U1&); diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp index 42b2ebf4aa..d309d42d66 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp @@ -25,9 +25,9 @@ static bool PLIHandler(TranslatorVisitor& v) { return v.RaiseException(Exception::PreloadInstruction); } -using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U8&); +using ExtensionFunctionU8 = IR::U32 (IREmitter::*)(const IR::U8&); -static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunction ext_fn) { +static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunctionU8 ext_fn) { const u32 imm32 = imm12.ZeroExtend(); const u32 base = v.ir.AlignPC(4); const u32 address = U ? (base + imm32) : (base - imm32); @@ -37,7 +37,7 @@ static bool LoadByteLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, return true; } -static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) { +static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunctionU8 ext_fn) { if (m == Reg::PC) { return v.UnpredictableInstruction(); } @@ -52,7 +52,7 @@ static bool LoadByteRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re return true; } -static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) { +static bool LoadByteImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunctionU8 ext_fn) { const u32 imm32 = imm12.ZeroExtend(); const IR::U32 reg_n = v.ir.GetRegister(n); const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32)) diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp index 5b9f1639af..d8a043e553 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_halfword.cpp @@ -4,12 +4,11 @@ */ #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U16&); - -static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunction ext_fn) { +static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, ExtensionFunctionU16 ext_fn) { const auto imm32 = imm12.ZeroExtend(); const auto base = v.ir.AlignPC(4); const auto address = U ? (base + imm32) : (base - imm32); @@ -19,7 +18,7 @@ static bool LoadHalfLiteral(TranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, return true; } -static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunction ext_fn) { +static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, ExtensionFunctionU16 ext_fn) { if (m == Reg::PC) { return v.UnpredictableInstruction(); } @@ -34,7 +33,7 @@ static bool LoadHalfRegister(TranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Re return true; } -static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunction ext_fn) { +static bool LoadHalfImmediate(TranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12, ExtensionFunctionU16 ext_fn) { const u32 imm32 = imm12.ZeroExtend(); const IR::U32 reg_n = v.ir.GetRegister(n); const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32)) diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp index 17d4285c23..eb574d773c 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp @@ -6,11 +6,9 @@ #include #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static bool ITBlockCheck(const A32::IREmitter& ir) { - return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock(); -} static bool TableBranch(TranslatorVisitor& v, Reg n, Reg m, bool half) { if (m == Reg::PC) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp index 2bc782b973..d446fbf3dd 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp @@ -6,11 +6,9 @@ #include #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static bool ITBlockCheck(const A32::IREmitter& ir) { - return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock(); -} static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list, const IR::U32& start_address, const IR::U32& writeback_address) { auto address = start_address; diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp index b92e27fc66..b7556a8caa 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_word.cpp @@ -4,11 +4,9 @@ */ #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static bool ITBlockCheck(const A32::IREmitter& ir) { - return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock(); -} bool TranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) { if (t == Reg::PC && ITBlockCheck(ir)) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp index 654940967d..64d57e917d 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_parallel.cpp @@ -4,15 +4,9 @@ */ #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" +#include "dynarmic/frontend/A32/translate/impl/common.h" namespace Dynarmic::A32 { -static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) { - return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result); -} - -static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { - return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result); -} bool TranslatorVisitor::thumb32_SADD8(Reg n, Reg d, Reg m) { if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.cpp index 3f5a70bdc0..68f536c8d5 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.cpp @@ -5,261 +5,7 @@ #include "dynarmic/frontend/A64/a64_ir_emitter.h" -#include - -#include "dynarmic/ir/opcodes.h" - namespace Dynarmic::A64 { -using Opcode = IR::Opcode; - -u64 IREmitter::PC() const { - return current_location->PC(); -} - -u64 IREmitter::AlignPC(size_t alignment) const { - const u64 pc = PC(); - return static_cast(pc - pc % alignment); -} - -void IREmitter::SetCheckBit(const IR::U1& value) { - Inst(Opcode::A64SetCheckBit, value); -} - -IR::U1 IREmitter::GetCFlag() { - return Inst(Opcode::A64GetCFlag); -} - -IR::U32 IREmitter::GetNZCVRaw() { - return Inst(Opcode::A64GetNZCVRaw); -} - -void IREmitter::SetNZCVRaw(IR::U32 value) { - Inst(Opcode::A64SetNZCVRaw, value); -} - -void IREmitter::SetNZCV(const IR::NZCV& nzcv) { - Inst(Opcode::A64SetNZCV, nzcv); -} - -void IREmitter::CallSupervisor(u32 imm) { - Inst(Opcode::A64CallSupervisor, Imm32(imm)); -} - -void IREmitter::ExceptionRaised(Exception exception) { - Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast(exception))); -} - -void IREmitter::DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) { - Inst(Opcode::A64DataCacheOperationRaised, ImmCurrentLocationDescriptor(), Imm64(static_cast(op)), value); -} - -void IREmitter::InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) { - Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast(op)), value); -} - -void IREmitter::DataSynchronizationBarrier() { - Inst(Opcode::A64DataSynchronizationBarrier); -} - -void IREmitter::DataMemoryBarrier() { - Inst(Opcode::A64DataMemoryBarrier); -} - -void IREmitter::InstructionSynchronizationBarrier() { - Inst(Opcode::A64InstructionSynchronizationBarrier); -} - -IR::U32 IREmitter::GetCNTFRQ() { - return Inst(Opcode::A64GetCNTFRQ); -} - -IR::U64 IREmitter::GetCNTPCT() { - return Inst(Opcode::A64GetCNTPCT); -} - -IR::U32 IREmitter::GetCTR() { - return Inst(Opcode::A64GetCTR); -} - -IR::U32 IREmitter::GetDCZID() { - return Inst(Opcode::A64GetDCZID); -} - -IR::U64 IREmitter::GetTPIDR() { - return Inst(Opcode::A64GetTPIDR); -} - -void IREmitter::SetTPIDR(const IR::U64& value) { - Inst(Opcode::A64SetTPIDR, value); -} - -IR::U64 IREmitter::GetTPIDRRO() { - return Inst(Opcode::A64GetTPIDRRO); -} - -void IREmitter::ClearExclusive() { - Inst(Opcode::A64ClearExclusive); -} - -IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U128 IREmitter::ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U8 IREmitter::ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U16 IREmitter::ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U64 IREmitter::ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -IR::U128 IREmitter::ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); -} - -void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) { - Inst(Opcode::A64WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) { - Inst(Opcode::A64WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) { - Inst(Opcode::A64WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) { - Inst(Opcode::A64WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -void IREmitter::WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) { - Inst(Opcode::A64WriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -IR::U32 IREmitter::ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) { - return Inst(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); -} - -IR::U32 IREmitter::GetW(Reg reg) { - if (reg == Reg::ZR) - return Imm32(0); - return Inst(Opcode::A64GetW, IR::Value(reg)); -} - -IR::U64 IREmitter::GetX(Reg reg) { - if (reg == Reg::ZR) - return Imm64(0); - return Inst(Opcode::A64GetX, IR::Value(reg)); -} - -IR::U128 IREmitter::GetS(Vec vec) { - return Inst(Opcode::A64GetS, IR::Value(vec)); -} - -IR::U128 IREmitter::GetD(Vec vec) { - return Inst(Opcode::A64GetD, IR::Value(vec)); -} - -IR::U128 IREmitter::GetQ(Vec vec) { - return Inst(Opcode::A64GetQ, IR::Value(vec)); -} - -IR::U64 IREmitter::GetSP() { - return Inst(Opcode::A64GetSP); -} - -IR::U32 IREmitter::GetFPCR() { - return Inst(Opcode::A64GetFPCR); -} - -IR::U32 IREmitter::GetFPSR() { - return Inst(Opcode::A64GetFPSR); -} - -void IREmitter::SetW(const Reg reg, const IR::U32& value) { - if (reg == Reg::ZR) - return; - Inst(Opcode::A64SetW, IR::Value(reg), value); -} - -void IREmitter::SetX(const Reg reg, const IR::U64& value) { - if (reg == Reg::ZR) - return; - Inst(Opcode::A64SetX, IR::Value(reg), value); -} - -void IREmitter::SetS(const Vec vec, const IR::U128& value) { - Inst(Opcode::A64SetS, IR::Value(vec), value); -} - -void IREmitter::SetD(const Vec vec, const IR::U128& value) { - Inst(Opcode::A64SetD, IR::Value(vec), value); -} - -void IREmitter::SetQ(const Vec vec, const IR::U128& value) { - Inst(Opcode::A64SetQ, IR::Value(vec), value); -} - -void IREmitter::SetSP(const IR::U64& value) { - Inst(Opcode::A64SetSP, value); -} - -void IREmitter::SetFPCR(const IR::U32& value) { - Inst(Opcode::A64SetFPCR, value); -} - -void IREmitter::SetFPSR(const IR::U32& value) { - Inst(Opcode::A64SetFPSR, value); -} - -void IREmitter::SetPC(const IR::U64& value) { - Inst(Opcode::A64SetPC, value); -} - -IR::U64 IREmitter::ImmCurrentLocationDescriptor() { - return Imm64(IR::LocationDescriptor{*current_location}.Value()); -} } // namespace Dynarmic::A64 diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.h b/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.h index 7fc8bea7c4..3bf633a3da 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.h +++ b/externals/dynarmic/src/dynarmic/frontend/A64/a64_ir_emitter.h @@ -8,12 +8,14 @@ #include #include +#include #include "dynarmic/frontend/A64/a64_location_descriptor.h" #include "dynarmic/frontend/A64/a64_types.h" #include "dynarmic/interface/A64/config.h" #include "dynarmic/ir/ir_emitter.h" #include "dynarmic/ir/value.h" +#include "dynarmic/ir/opcodes.h" namespace Dynarmic::A64 { @@ -24,79 +26,262 @@ namespace Dynarmic::A64 { */ class IREmitter : public IR::IREmitter { public: - explicit IREmitter(IR::Block& block) - : IR::IREmitter(block) {} - explicit IREmitter(IR::Block& block, LocationDescriptor descriptor) - : IR::IREmitter(block), current_location(descriptor) {} + explicit IREmitter(IR::Block& block) : IR::IREmitter(block) {} + explicit IREmitter(IR::Block& block, LocationDescriptor descriptor) : IR::IREmitter(block), current_location(descriptor) {} std::optional current_location; - u64 PC() const; - u64 AlignPC(size_t alignment) const; + using Opcode = IR::Opcode; - void SetCheckBit(const IR::U1& value); - IR::U1 GetCFlag(); - IR::U32 GetNZCVRaw(); - void SetNZCVRaw(IR::U32 value); - void SetNZCV(const IR::NZCV& nzcv); + u64 PC() const noexcept { + return current_location->PC(); + } - void CallSupervisor(u32 imm); - void ExceptionRaised(Exception exception); - void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value); - void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value); - void DataSynchronizationBarrier(); - void DataMemoryBarrier(); - void InstructionSynchronizationBarrier(); - IR::U32 GetCNTFRQ(); - IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this. - IR::U32 GetCTR(); - IR::U32 GetDCZID(); - IR::U64 GetTPIDR(); - IR::U64 GetTPIDRRO(); - void SetTPIDR(const IR::U64& value); + u64 AlignPC(size_t alignment) const noexcept { + const u64 pc = PC(); + return static_cast(pc - pc % alignment); + } - void ClearExclusive(); - IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type); - IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type); - IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type); - IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type); - IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type); - IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type); - IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type); - IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type); - IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type); - IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type); - void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type); - void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type); - void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type); - void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type); - void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type); - IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type); - IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type); - IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type); - IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type); - IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type); + void SetCheckBit(const IR::U1& value) noexcept { + Inst(Opcode::A64SetCheckBit, value); + } - IR::U32 GetW(Reg source_reg); - IR::U64 GetX(Reg source_reg); - IR::U128 GetS(Vec source_vec); - IR::U128 GetD(Vec source_vec); - IR::U128 GetQ(Vec source_vec); - IR::U64 GetSP(); - IR::U32 GetFPCR(); - IR::U32 GetFPSR(); - void SetW(Reg dest_reg, const IR::U32& value); - void SetX(Reg dest_reg, const IR::U64& value); - void SetS(Vec dest_vec, const IR::U128& value); - void SetD(Vec dest_vec, const IR::U128& value); - void SetQ(Vec dest_vec, const IR::U128& value); - void SetSP(const IR::U64& value); - void SetFPCR(const IR::U32& value); - void SetFPSR(const IR::U32& value); - void SetPC(const IR::U64& value); + IR::U1 GetCFlag() noexcept { + return Inst(Opcode::A64GetCFlag); + } + + IR::U32 GetNZCVRaw() noexcept { + return Inst(Opcode::A64GetNZCVRaw); + } + + void SetNZCVRaw(IR::U32 value) noexcept { + Inst(Opcode::A64SetNZCVRaw, value); + } + + void SetNZCV(const IR::NZCV& nzcv) noexcept { + Inst(Opcode::A64SetNZCV, nzcv); + } + + void CallSupervisor(u32 imm) noexcept { + Inst(Opcode::A64CallSupervisor, Imm32(imm)); + } + + void ExceptionRaised(Exception exception) noexcept { + Inst(Opcode::A64ExceptionRaised, Imm64(PC()), Imm64(static_cast(exception))); + } + + void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value) noexcept { + Inst(Opcode::A64DataCacheOperationRaised, ImmCurrentLocationDescriptor(), Imm64(static_cast(op)), value); + } + + void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) noexcept { + Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast(op)), value); + } + + void DataSynchronizationBarrier() noexcept { + Inst(Opcode::A64DataSynchronizationBarrier); + } + + void DataMemoryBarrier() noexcept { + Inst(Opcode::A64DataMemoryBarrier); + } + + void InstructionSynchronizationBarrier() noexcept { + Inst(Opcode::A64InstructionSynchronizationBarrier); + } + + IR::U32 GetCNTFRQ() noexcept { + return Inst(Opcode::A64GetCNTFRQ); + } + + IR::U64 GetCNTPCT() noexcept { + return Inst(Opcode::A64GetCNTPCT); + } + + IR::U32 GetCTR() noexcept { + return Inst(Opcode::A64GetCTR); + } + + IR::U32 GetDCZID() noexcept { + return Inst(Opcode::A64GetDCZID); + } + + IR::U64 GetTPIDR() noexcept { + return Inst(Opcode::A64GetTPIDR); + } + + void SetTPIDR(const IR::U64& value) noexcept { + Inst(Opcode::A64SetTPIDR, value); + } + + IR::U64 GetTPIDRRO() noexcept { + return Inst(Opcode::A64GetTPIDRRO); + } + + void ClearExclusive() noexcept { + Inst(Opcode::A64ClearExclusive); + } + + IR::U8 ReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U16 ReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U32 ReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U64 ReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U128 ReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U8 ExclusiveReadMemory8(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveReadMemory8, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U16 ExclusiveReadMemory16(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveReadMemory16, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U32 ExclusiveReadMemory32(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveReadMemory32, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U64 ExclusiveReadMemory64(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveReadMemory64, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + IR::U128 ExclusiveReadMemory128(const IR::U64& vaddr, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveReadMemory128, ImmCurrentLocationDescriptor(), vaddr, IR::Value{acc_type}); + } + + void WriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) noexcept { + Inst(Opcode::A64WriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + void WriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) noexcept { + Inst(Opcode::A64WriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + void WriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) noexcept { + Inst(Opcode::A64WriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + void WriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) noexcept { + Inst(Opcode::A64WriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + void WriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) noexcept { + Inst(Opcode::A64WriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + IR::U32 ExclusiveWriteMemory8(const IR::U64& vaddr, const IR::U8& value, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveWriteMemory8, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + IR::U32 ExclusiveWriteMemory16(const IR::U64& vaddr, const IR::U16& value, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveWriteMemory16, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + IR::U32 ExclusiveWriteMemory32(const IR::U64& vaddr, const IR::U32& value, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveWriteMemory32, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + IR::U32 ExclusiveWriteMemory64(const IR::U64& vaddr, const IR::U64& value, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveWriteMemory64, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + IR::U32 ExclusiveWriteMemory128(const IR::U64& vaddr, const IR::U128& value, IR::AccType acc_type) noexcept { + return Inst(Opcode::A64ExclusiveWriteMemory128, ImmCurrentLocationDescriptor(), vaddr, value, IR::Value{acc_type}); + } + + IR::U32 GetW(Reg reg) noexcept { + if (reg == Reg::ZR) + return Imm32(0); + return Inst(Opcode::A64GetW, IR::Value(reg)); + } + + IR::U64 GetX(Reg reg) noexcept { + if (reg == Reg::ZR) + return Imm64(0); + return Inst(Opcode::A64GetX, IR::Value(reg)); + } + + IR::U128 GetS(Vec vec) noexcept { + return Inst(Opcode::A64GetS, IR::Value(vec)); + } + + IR::U128 GetD(Vec vec) noexcept { + return Inst(Opcode::A64GetD, IR::Value(vec)); + } + + IR::U128 GetQ(Vec vec) noexcept { + return Inst(Opcode::A64GetQ, IR::Value(vec)); + } + + IR::U64 GetSP() noexcept { + return Inst(Opcode::A64GetSP); + } + + IR::U32 GetFPCR() noexcept { + return Inst(Opcode::A64GetFPCR); + } + + IR::U32 GetFPSR() noexcept { + return Inst(Opcode::A64GetFPSR); + } + + void SetW(const Reg reg, const IR::U32& value) noexcept { + if (reg == Reg::ZR) + return; + Inst(Opcode::A64SetW, IR::Value(reg), value); + } + + void SetX(const Reg reg, const IR::U64& value) noexcept { + if (reg == Reg::ZR) + return; + Inst(Opcode::A64SetX, IR::Value(reg), value); + } + + void SetS(const Vec vec, const IR::U128& value) noexcept { + Inst(Opcode::A64SetS, IR::Value(vec), value); + } + + void SetD(const Vec vec, const IR::U128& value) noexcept { + Inst(Opcode::A64SetD, IR::Value(vec), value); + } + + void SetQ(const Vec vec, const IR::U128& value) noexcept { + Inst(Opcode::A64SetQ, IR::Value(vec), value); + } + + void SetSP(const IR::U64& value) noexcept { + Inst(Opcode::A64SetSP, value); + } + + void SetFPCR(const IR::U32& value) noexcept { + Inst(Opcode::A64SetFPCR, value); + } + + void SetFPSR(const IR::U32& value) noexcept { + Inst(Opcode::A64SetFPSR, value); + } + + void SetPC(const IR::U64& value) noexcept { + Inst(Opcode::A64SetPC, value); + } private: - IR::U64 ImmCurrentLocationDescriptor(); + IR::U64 ImmCurrentLocationDescriptor() noexcept { + return Imm64(IR::LocationDescriptor{*current_location}.Value()); + } }; } // namespace Dynarmic::A64 diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h b/externals/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h index f264893502..e807490d16 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h +++ b/externals/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h @@ -33,27 +33,26 @@ inline size_t ToFastLookupIndex(u32 instruction) { } // namespace detail template -DecodeTable GetDecodeTable() { +constexpr DecodeTable GetDecodeTable() { std::vector> list = { #define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./a64.inc" #undef INST }; + // If a matcher has more bits in its mask it is more specific, so it should come first. std::stable_sort(list.begin(), list.end(), [](const auto& matcher1, const auto& matcher2) { // If a matcher has more bits in its mask it is more specific, so it should come first. return mcl::bit::count_ones(matcher1.GetMask()) > mcl::bit::count_ones(matcher2.GetMask()); }); // Exceptions to the above rule of thumb. - const std::set comes_first{ - "MOVI, MVNI, ORR, BIC (vector, immediate)", - "FMOV (vector, immediate)", - "Unallocated SIMD modified immediate", - }; - std::stable_partition(list.begin(), list.end(), [&](const auto& matcher) { - return comes_first.count(matcher.GetName()) > 0; + return std::set{ + "MOVI, MVNI, ORR, BIC (vector, immediate)", + "FMOV (vector, immediate)", + "Unallocated SIMD modified immediate", + }.count(matcher.GetName()) > 0; }); DecodeTable table{}; @@ -75,7 +74,6 @@ std::optional>> Decode(u32 instruction) const auto matches_instruction = [instruction](const auto& matcher) { return matcher.Matches(instruction); }; - const auto& subtable = table[detail::ToFastLookupIndex(instruction)]; auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction); return iter != subtable.end() ? std::optional>>(*iter) : std::nullopt; diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp index 05996aeb64..352c2e6ae2 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -67,3 +67,64 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, } } // namespace Dynarmic::A64 + +// ls -l | awk '{print "#include \"dynarmic/frontend/A64/translate/impl/" $9 "\""}' +#include "dynarmic/frontend/A64/translate/impl/a64_branch.cpp" +#include "dynarmic/frontend/A64/translate/impl/a64_exception_generating.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_addsub.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_bitfield.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_conditional_compare.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_conditional_select.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_crc32.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_logical.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_multiply.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_pcrel.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_register.cpp" +#include "dynarmic/frontend/A64/translate/impl/data_processing_shift.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_compare.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_conditional_compare.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_conditional_select.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_conversion_integer.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_one_register.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_three_register.cpp" +#include "dynarmic/frontend/A64/translate/impl/floating_point_data_processing_two_register.cpp" +#include "dynarmic/frontend/A64/translate/impl/impl.cpp" +#include "dynarmic/frontend/A64/translate/impl/impl.h" +#include "dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_load_literal.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_multiple_structures.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_no_allocate_pair.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_register_immediate.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_register_pair.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_register_register_offset.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_register_unprivileged.cpp" +#include "dynarmic/frontend/A64/translate/impl/load_store_single_structure.cpp" +#include "dynarmic/frontend/A64/translate/impl/move_wide.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_across_lanes.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_aes.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_copy.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_crypto_four_register.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_crypto_three_register.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_extract.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_permute.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_sha512.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_sha.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_table_lookup.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_three_different.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_three_same.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_three_same_extra.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp" +#include "dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp" +#include "dynarmic/frontend/A64/translate/impl/sys_dc.cpp" +#include "dynarmic/frontend/A64/translate/impl/sys_ic.cpp" +#include "dynarmic/frontend/A64/translate/impl/system.cpp" +#include "dynarmic/frontend/A64/translate/impl/system_flag_format.cpp" +#include "dynarmic/frontend/A64/translate/impl/system_flag_manipulation.cpp" diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp index 63615b0f9a..e3b8d7502c 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_pairwise.cpp @@ -7,14 +7,14 @@ namespace Dynarmic::A64 { namespace { -enum class MinMaxOperation { +enum class MinMaxOperationSSPW { Max, MaxNumeric, Min, MinNumeric, }; -bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOperation operation) { +bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOperationSSPW operation) { const size_t esize = sz ? 64 : 32; const IR::U128 operand = v.V(128, Vn); @@ -22,13 +22,13 @@ bool FPPairwiseMinMax(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, MinMaxOpera const IR::U32U64 element2 = v.ir.VectorGetElement(esize, operand, 1); const IR::U32U64 result = [&] { switch (operation) { - case MinMaxOperation::Max: + case MinMaxOperationSSPW::Max: return v.ir.FPMax(element1, element2); - case MinMaxOperation::MaxNumeric: + case MinMaxOperationSSPW::MaxNumeric: return v.ir.FPMaxNumeric(element1, element2); - case MinMaxOperation::Min: + case MinMaxOperationSSPW::Min: return v.ir.FPMin(element1, element2); - case MinMaxOperation::MinNumeric: + case MinMaxOperationSSPW::MinNumeric: return v.ir.FPMinNumeric(element1, element2); default: UNREACHABLE(); @@ -63,18 +63,18 @@ bool TranslatorVisitor::FADDP_pair_2(bool size, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FMAXNMP_pair_2(bool sz, Vec Vn, Vec Vd) { - return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::MaxNumeric); + return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::MaxNumeric); } bool TranslatorVisitor::FMAXP_pair_2(bool sz, Vec Vn, Vec Vd) { - return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::Max); + return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::Max); } bool TranslatorVisitor::FMINNMP_pair_2(bool sz, Vec Vn, Vec Vd) { - return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::MinNumeric); + return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::MinNumeric); } bool TranslatorVisitor::FMINP_pair_2(bool sz, Vec Vn, Vec Vd) { - return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperation::Min); + return FPPairwiseMinMax(*this, sz, Vn, Vd, MinMaxOperationSSPW::Min); } } // namespace Dynarmic::A64 diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp index a0570edc7e..5d60cb31c3 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp @@ -27,7 +27,7 @@ enum class ShiftExtraBehavior { Accumulate, }; -enum class Signedness { +enum class SignednessSSSBI { Signed, Unsigned, }; @@ -63,7 +63,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, return true; } -bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, Signedness signedness) { +bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, SignednessSSSBI SignednessSSSBI) { if (!immh.Bit<3>()) { return v.ReservedValue(); } @@ -73,7 +73,7 @@ bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, const IR::U64 operand = v.V_scalar(esize, Vn); IR::U64 result = [&]() -> IR::U64 { - if (signedness == Signedness::Signed) { + if (SignednessSSSBI == SignednessSSSBI::Signed) { return v.ir.ArithmeticShiftRight(operand, v.ir.Imm8(shift_amount)); } return v.ir.LogicalShiftRight(operand, v.ir.Imm8(shift_amount)); @@ -88,7 +88,7 @@ bool ShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, return true; } -bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, Signedness signedness) { +bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, ShiftExtraBehavior behavior, SignednessSSSBI SignednessSSSBI) { if (!immh.Bit<3>()) { return v.ReservedValue(); } @@ -100,7 +100,7 @@ bool RoundingShiftRight(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, const IR::U64 round_bit = v.ir.LogicalShiftRight(v.ir.LogicalShiftLeft(operand, v.ir.Imm8(64 - shift_amount)), v.ir.Imm8(63)); const IR::U64 result = [&] { const IR::U64 shifted = [&]() -> IR::U64 { - if (signedness == Signedness::Signed) { + if (SignednessSSSBI == SignednessSSSBI::Signed) { return v.ir.ArithmeticShiftRight(operand, v.ir.Imm8(shift_amount)); } return v.ir.LogicalShiftRight(operand, v.ir.Imm8(shift_amount)); @@ -163,7 +163,7 @@ bool ShiftAndInsert(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec return true; } -bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Narrowing narrowing, Signedness signedness) { +bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Narrowing narrowing, SignednessSSSBI SignednessSSSBI) { if (immh == 0b0000) { return v.ReservedValue(); } @@ -179,7 +179,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, const IR::U128 operand = v.ir.ZeroExtendToQuad(v.ir.VectorGetElement(source_esize, v.V(128, Vn), 0)); IR::U128 wide_result = [&] { - if (signedness == Signedness::Signed) { + if (SignednessSSSBI == SignednessSSSBI::Signed) { return v.ir.VectorArithmeticShiftRight(source_esize, operand, shift_amount); } return v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount); @@ -190,12 +190,12 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, case Narrowing::Truncation: return v.ir.VectorNarrow(source_esize, wide_result); case Narrowing::SaturateToUnsigned: - if (signedness == Signedness::Signed) { + if (SignednessSSSBI == SignednessSSSBI::Signed) { return v.ir.VectorSignedSaturatedNarrowToUnsigned(source_esize, wide_result); } return v.ir.VectorUnsignedSaturatedNarrow(source_esize, wide_result); case Narrowing::SaturateToSigned: - ASSERT(signedness == Signedness::Signed); + ASSERT(SignednessSSSBI == SignednessSSSBI::Signed); return v.ir.VectorSignedSaturatedNarrowToSigned(source_esize, wide_result); } UNREACHABLE(); @@ -206,7 +206,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, return true; } -bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness sign, FloatConversionDirection direction, FP::RoundingMode rounding_mode) { +bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSSBI sign, FloatConversionDirection direction, FP::RoundingMode rounding_mode) { const u32 immh_value = immh.ZeroExtend(); if ((immh_value & 0b1110) == 0b0000) { @@ -227,23 +227,23 @@ bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Ve switch (direction) { case FloatConversionDirection::FloatToFixed: if (esize == 64) { - return sign == Signedness::Signed + return sign == SignednessSSSBI::Signed ? v.ir.FPToFixedS64(operand, fbits, rounding_mode) : v.ir.FPToFixedU64(operand, fbits, rounding_mode); } - return sign == Signedness::Signed + return sign == SignednessSSSBI::Signed ? v.ir.FPToFixedS32(operand, fbits, rounding_mode) : v.ir.FPToFixedU32(operand, fbits, rounding_mode); case FloatConversionDirection::FixedToFloat: if (esize == 64) { - return sign == Signedness::Signed + return sign == SignednessSSSBI::Signed ? v.ir.FPSignedFixedToDouble(operand, fbits, rounding_mode) : v.ir.FPUnsignedFixedToDouble(operand, fbits, rounding_mode); } - return sign == Signedness::Signed + return sign == SignednessSSSBI::Signed ? v.ir.FPSignedFixedToSingle(operand, fbits, rounding_mode) : v.ir.FPUnsignedFixedToSingle(operand, fbits, rounding_mode); } @@ -257,19 +257,19 @@ bool ScalarFPConvertWithRound(TranslatorVisitor& v, Imm<4> immh, Imm<3> immb, Ve } // Anonymous namespace bool TranslatorVisitor::FCVTZS_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); + return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); } bool TranslatorVisitor::FCVTZU_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); + return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); } bool TranslatorVisitor::SCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); + return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); } bool TranslatorVisitor::UCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); + return ScalarFPConvertWithRound(*this, immh, immb, Vn, Vd, SignednessSSSBI::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); } bool TranslatorVisitor::SLI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -289,27 +289,27 @@ bool TranslatorVisitor::SQSHLU_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToSigned, Signedness::Signed); + return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToSigned, SignednessSSSBI::Signed); } bool TranslatorVisitor::SQSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, Signedness::Signed); + return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, SignednessSSSBI::Signed); } bool TranslatorVisitor::SRSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed); + return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Signed); } bool TranslatorVisitor::SRSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed); + return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Signed); } bool TranslatorVisitor::SSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed); + return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Signed); } bool TranslatorVisitor::SSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed); + return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Signed); } bool TranslatorVisitor::SHL_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -332,23 +332,23 @@ bool TranslatorVisitor::UQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { } bool TranslatorVisitor::UQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, Signedness::Unsigned); + return ShiftRightNarrowing(*this, immh, immb, Vn, Vd, Narrowing::SaturateToUnsigned, SignednessSSSBI::Unsigned); } bool TranslatorVisitor::URSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned); + return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Unsigned); } bool TranslatorVisitor::URSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned); + return RoundingShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Unsigned); } bool TranslatorVisitor::USHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned); + return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::None, SignednessSSSBI::Unsigned); } bool TranslatorVisitor::USRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned); + return ShiftRight(*this, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, SignednessSSSBI::Unsigned); } } // namespace Dynarmic::A64 diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp index fb9ae9d141..d551605bda 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp @@ -26,12 +26,12 @@ enum class ComparisonVariant { Zero, }; -enum class Signedness { +enum class SignednessSSTS { Signed, Unsigned, }; -bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) { +bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSSTS sign) { if (size != 0b11) { return v.ReservedValue(); } @@ -39,7 +39,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, Imm<2> size, Vec Vm, Vec Vn, Vec Vd const IR::U128 operand1 = v.V(64, Vn); const IR::U128 operand2 = v.V(64, Vm); const IR::U128 result = [&] { - if (sign == Signedness::Signed) { + if (sign == SignednessSSTS::Signed) { return v.ir.VectorRoundingShiftLeftSigned(64, operand1, operand2); } @@ -369,7 +369,7 @@ bool TranslatorVisitor::SQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return RoundingShiftLeft(*this, size, Vm, Vn, Vd, Signedness::Signed); + return RoundingShiftLeft(*this, size, Vm, Vn, Vd, SignednessSSTS::Signed); } bool TranslatorVisitor::SSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -411,7 +411,7 @@ bool TranslatorVisitor::UQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::URSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return RoundingShiftLeft(*this, size, Vm, Vn, Vd, Signedness::Unsigned); + return RoundingShiftLeft(*this, size, Vm, Vn, Vd, SignednessSSTS::Unsigned); } bool TranslatorVisitor::USHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp index 2289f5cbd1..0fc37f538f 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_two_register_misc.cpp @@ -7,7 +7,7 @@ namespace Dynarmic::A64 { namespace { -enum class ComparisonType { +enum class ComparisonTypeSSTRM { EQ, GE, GT, @@ -15,12 +15,12 @@ enum class ComparisonType { LT }; -enum class Signedness { +enum class SignednessSSTRM { Signed, Unsigned }; -bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, ComparisonType type) { +bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, ComparisonTypeSSTRM type) { const size_t esize = sz ? 64 : 32; const size_t datasize = esize; @@ -28,15 +28,15 @@ bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, C const IR::U128 zero = v.ir.ZeroVector(); const IR::U128 result = [&] { switch (type) { - case ComparisonType::EQ: + case ComparisonTypeSSTRM::EQ: return v.ir.FPVectorEqual(esize, operand, zero); - case ComparisonType::GE: + case ComparisonTypeSSTRM::GE: return v.ir.FPVectorGreaterEqual(esize, operand, zero); - case ComparisonType::GT: + case ComparisonTypeSSTRM::GT: return v.ir.FPVectorGreater(esize, operand, zero); - case ComparisonType::LE: + case ComparisonTypeSSTRM::LE: return v.ir.FPVectorGreaterEqual(esize, zero, operand); - case ComparisonType::LT: + case ComparisonTypeSSTRM::LT: return v.ir.FPVectorGreater(esize, zero, operand); } @@ -47,18 +47,18 @@ bool ScalarFPCompareAgainstZero(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, C return true; } -bool ScalarFPConvertWithRound(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, FP::RoundingMode rmode, Signedness sign) { +bool ScalarFPConvertWithRound(TranslatorVisitor& v, bool sz, Vec Vn, Vec Vd, FP::RoundingMode rmode, SignednessSSTRM sign) { const size_t esize = sz ? 64 : 32; const IR::U32U64 operand = v.V_scalar(esize, Vn); const IR::U32U64 result = [&]() -> IR::U32U64 { if (sz) { - return sign == Signedness::Signed + return sign == SignednessSSTRM::Signed ? v.ir.FPToFixedS64(operand, 0, rmode) : v.ir.FPToFixedU64(operand, 0, rmode); } - return sign == Signedness::Signed + return sign == SignednessSSTRM::Signed ? v.ir.FPToFixedS32(operand, 0, rmode) : v.ir.FPToFixedU32(operand, 0, rmode); }(); @@ -107,55 +107,55 @@ bool TranslatorVisitor::FCMEQ_zero_1(Vec Vn, Vec Vd) { } bool TranslatorVisitor::FCMEQ_zero_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::EQ); + return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::EQ); } bool TranslatorVisitor::FCMGE_zero_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::GE); + return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::GE); } bool TranslatorVisitor::FCMGT_zero_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::GT); + return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::GT); } bool TranslatorVisitor::FCMLE_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::LE); + return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::LE); } bool TranslatorVisitor::FCMLT_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonType::LT); + return ScalarFPCompareAgainstZero(*this, sz, Vn, Vd, ComparisonTypeSSTRM::LT); } bool TranslatorVisitor::FCVTAS_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, Signedness::Signed); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, SignednessSSTRM::Signed); } bool TranslatorVisitor::FCVTAU_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, Signedness::Unsigned); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieAwayFromZero, SignednessSSTRM::Unsigned); } bool TranslatorVisitor::FCVTMS_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, Signedness::Signed); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, SignednessSSTRM::Signed); } bool TranslatorVisitor::FCVTMU_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, Signedness::Unsigned); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsMinusInfinity, SignednessSSTRM::Unsigned); } bool TranslatorVisitor::FCVTNS_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, Signedness::Signed); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, SignednessSSTRM::Signed); } bool TranslatorVisitor::FCVTNU_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, Signedness::Unsigned); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::ToNearest_TieEven, SignednessSSTRM::Unsigned); } bool TranslatorVisitor::FCVTPS_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, Signedness::Signed); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, SignednessSSTRM::Signed); } bool TranslatorVisitor::FCVTPU_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, Signedness::Unsigned); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsPlusInfinity, SignednessSSTRM::Unsigned); } bool TranslatorVisitor::FCVTXN_1(bool sz, Vec Vn, Vec Vd) { @@ -171,11 +171,11 @@ bool TranslatorVisitor::FCVTXN_1(bool sz, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FCVTZS_int_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, Signedness::Signed); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, SignednessSSTRM::Signed); } bool TranslatorVisitor::FCVTZU_int_2(bool sz, Vec Vn, Vec Vd) { - return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, Signedness::Unsigned); + return ScalarFPConvertWithRound(*this, sz, Vn, Vd, FP::RoundingMode::TowardsZero, SignednessSSTRM::Unsigned); } bool TranslatorVisitor::FRECPE_1(Vec Vn, Vec Vd) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp index dbbc4ce12c..7a5d9847d7 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp @@ -9,7 +9,7 @@ namespace Dynarmic::A64 { namespace { -std::pair Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) { +std::pair CombineScalar(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) { if (size == 0b01) { return {concatenate(H, L, M).ZeroExtend(), Vmlo.ZeroExtend()}; } @@ -122,7 +122,7 @@ bool TranslatorVisitor::SQDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm } const size_t esize = 8 << size.ZeroExtend(); - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo); const IR::UAny operand1 = V_scalar(esize, Vn); const IR::UAny operand2 = ir.VectorGetElement(esize, V(128, Vm), index); @@ -137,7 +137,7 @@ bool TranslatorVisitor::SQRDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> V } const size_t esize = 8 << size.ZeroExtend(); - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo); const IR::U128 operand1 = ir.ZeroExtendToQuad(ir.VectorGetElement(esize, V(128, Vn), 0)); const IR::U128 operand2 = V(128, Vm); @@ -154,7 +154,7 @@ bool TranslatorVisitor::SQDMULL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm } const size_t esize = 8 << size.ZeroExtend(); - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineScalar(size, H, L, M, Vmlo); const IR::U128 operand1 = ir.ZeroExtendToQuad(ir.VectorGetElement(esize, V(128, Vn), 0)); const IR::U128 operand2 = V(128, Vm); diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp index 41b0952249..559721a22a 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp @@ -20,24 +20,24 @@ enum class Accumulating { Accumulate }; -enum class Signedness { +enum class SignednessSSBI { Signed, Unsigned }; -enum class Narrowing { +enum class NarrowingSSBI { Truncation, SaturateToUnsigned, SaturateToSigned, }; -enum class SaturatingShiftLeftType { +enum class SaturatingShiftLeftTypeSSBI { Signed, Unsigned, SignedWithUnsignedSaturation, }; -enum class FloatConversionDirection { +enum class FloatConversionDirectionSSBI { FixedToFloat, FloatToFixed, }; @@ -48,7 +48,7 @@ IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round return v.ir.VectorSub(esize, shifted, round_correction); } -bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Accumulating accumulating, Signedness signedness) { +bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Accumulating accumulating, SignednessSSBI SignednessSSBI) { if (immh == 0b0000) { return v.DecodeError(); } @@ -65,7 +65,7 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, const IR::U128 operand = v.V(datasize, Vn); IR::U128 result = [&] { - if (signedness == Signedness::Signed) { + if (SignednessSSBI == SignednessSSBI::Signed) { return v.ir.VectorArithmeticShiftRight(esize, operand, shift_amount); } return v.ir.VectorLogicalShiftRight(esize, operand, shift_amount); @@ -85,7 +85,7 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, return true; } -bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, Narrowing narrowing, Signedness signedness) { +bool ShiftRightNarrowingSSBI(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Rounding rounding, NarrowingSSBI NarrowingSSBI, SignednessSSBI SignednessSSBI) { if (immh == 0b0000) { return v.DecodeError(); } @@ -103,7 +103,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, const IR::U128 operand = v.V(128, Vn); IR::U128 wide_result = [&] { - if (signedness == Signedness::Signed) { + if (SignednessSSBI == SignednessSSBI::Signed) { return v.ir.VectorArithmeticShiftRight(source_esize, operand, shift_amount); } return v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount); @@ -115,16 +115,16 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, } const IR::U128 result = [&] { - switch (narrowing) { - case Narrowing::Truncation: + switch (NarrowingSSBI) { + case NarrowingSSBI::Truncation: return v.ir.VectorNarrow(source_esize, wide_result); - case Narrowing::SaturateToUnsigned: - if (signedness == Signedness::Signed) { + case NarrowingSSBI::SaturateToUnsigned: + if (SignednessSSBI == SignednessSSBI::Signed) { return v.ir.VectorSignedSaturatedNarrowToUnsigned(source_esize, wide_result); } return v.ir.VectorUnsignedSaturatedNarrow(source_esize, wide_result); - case Narrowing::SaturateToSigned: - ASSERT(signedness == Signedness::Signed); + case NarrowingSSBI::SaturateToSigned: + ASSERT(SignednessSSBI == SignednessSSBI::Signed); return v.ir.VectorSignedSaturatedNarrowToSigned(source_esize, wide_result); } UNREACHABLE(); @@ -134,7 +134,7 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, return true; } -bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness) { +bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSBI SignednessSSBI) { if (immh == 0b0000) { return v.DecodeError(); } @@ -151,7 +151,7 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V const IR::U128 operand = v.Vpart(datasize, Vn, part); const IR::U128 expanded_operand = [&] { - if (signedness == Signedness::Signed) { + if (SignednessSSBI == SignednessSSBI::Signed) { return v.ir.VectorSignExtend(esize, operand); } return v.ir.VectorZeroExtend(esize, operand); @@ -162,7 +162,7 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V return true; } -bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SaturatingShiftLeftType type) { +bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SaturatingShiftLeftTypeSSBI type) { if (!Q && immh.Bit<3>()) { return v.ReservedValue(); } @@ -174,11 +174,11 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, const IR::U128 operand = v.V(datasize, Vn); const IR::U128 shift_vec = v.ir.VectorBroadcast(esize, v.I(esize, shift)); const IR::U128 result = [&] { - if (type == SaturatingShiftLeftType::Signed) { + if (type == SaturatingShiftLeftTypeSSBI::Signed) { return v.ir.VectorSignedSaturatedShiftLeft(esize, operand, shift_vec); } - if (type == SaturatingShiftLeftType::Unsigned) { + if (type == SaturatingShiftLeftTypeSSBI::Unsigned) { return v.ir.VectorUnsignedSaturatedShiftLeft(esize, operand, shift_vec); } @@ -189,7 +189,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, return true; } -bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness, FloatConversionDirection direction, FP::RoundingMode rounding_mode) { +bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, SignednessSSBI SignednessSSBI, FloatConversionDirectionSSBI direction, FP::RoundingMode rounding_mode) { if (immh == 0b0000) { return v.DecodeError(); } @@ -210,12 +210,12 @@ bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn const IR::U128 operand = v.V(datasize, Vn); const IR::U128 result = [&] { switch (direction) { - case FloatConversionDirection::FixedToFloat: - return signedness == Signedness::Signed + case FloatConversionDirectionSSBI::FixedToFloat: + return SignednessSSBI == SignednessSSBI::Signed ? v.ir.FPVectorFromSignedFixed(esize, operand, fbits, rounding_mode) : v.ir.FPVectorFromUnsignedFixed(esize, operand, fbits, rounding_mode); - case FloatConversionDirection::FloatToFixed: - return signedness == Signedness::Signed + case FloatConversionDirectionSSBI::FloatToFixed: + return SignednessSSBI == SignednessSSBI::Signed ? v.ir.FPVectorToSignedFixed(esize, operand, fbits, rounding_mode) : v.ir.FPVectorToUnsignedFixed(esize, operand, fbits, rounding_mode); } @@ -229,19 +229,19 @@ bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn } // Anonymous namespace bool TranslatorVisitor::SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, SignednessSSBI::Signed); } bool TranslatorVisitor::SRSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, SignednessSSBI::Signed); } bool TranslatorVisitor::SRSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, SignednessSSBI::Signed); } bool TranslatorVisitor::SSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, SignednessSSBI::Signed); } bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -264,71 +264,71 @@ bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) } bool TranslatorVisitor::SHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::Truncation, Signedness::Unsigned); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::Truncation, SignednessSSBI::Unsigned); } bool TranslatorVisitor::RSHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::Truncation, Signedness::Unsigned); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::Truncation, SignednessSSBI::Unsigned); } bool TranslatorVisitor::SQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::Signed); + return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::Signed); } bool TranslatorVisitor::SQSHLU_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::SignedWithUnsignedSaturation); + return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::SignedWithUnsignedSaturation); } bool TranslatorVisitor::SQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToSigned, Signedness::Signed); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToSigned, SignednessSSBI::Signed); } bool TranslatorVisitor::SQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToSigned, Signedness::Signed); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToSigned, SignednessSSBI::Signed); } bool TranslatorVisitor::SQSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Signed); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Signed); } bool TranslatorVisitor::SQRSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Signed); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Signed); } bool TranslatorVisitor::UQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftType::Unsigned); + return SaturatingShiftLeft(*this, Q, immh, immb, Vn, Vd, SaturatingShiftLeftTypeSSBI::Unsigned); } bool TranslatorVisitor::UQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None, Narrowing::SaturateToUnsigned, Signedness::Unsigned); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::None, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Unsigned); } bool TranslatorVisitor::UQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Narrowing::SaturateToUnsigned, Signedness::Unsigned); + return ShiftRightNarrowingSSBI(*this, Q, immh, immb, Vn, Vd, Rounding::Round, NarrowingSSBI::SaturateToUnsigned, SignednessSSBI::Unsigned); } bool TranslatorVisitor::SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, Signedness::Signed); + return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed); } bool TranslatorVisitor::URSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, SignednessSSBI::Unsigned); } bool TranslatorVisitor::URSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, SignednessSSBI::Unsigned); } bool TranslatorVisitor::USHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, SignednessSSBI::Unsigned); } bool TranslatorVisitor::USRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, SignednessSSBI::Unsigned); } bool TranslatorVisitor::USHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned); + return ShiftLeftLong(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned); } bool TranslatorVisitor::SRI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -384,19 +384,19 @@ bool TranslatorVisitor::SLI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) } bool TranslatorVisitor::SCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed, FloatConversionDirectionSSBI::FixedToFloat, ir.current_location->FPCR().RMode()); } bool TranslatorVisitor::UCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned, FloatConversionDirectionSSBI::FixedToFloat, ir.current_location->FPCR().RMode()); } bool TranslatorVisitor::FCVTZS_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Signed, FloatConversionDirectionSSBI::FloatToFixed, FP::RoundingMode::TowardsZero); } bool TranslatorVisitor::FCVTZU_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, SignednessSSBI::Unsigned, FloatConversionDirectionSSBI::FloatToFixed, FP::RoundingMode::TowardsZero); } } // namespace Dynarmic::A64 diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_different.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_different.cpp index 8cc677b652..8f460665da 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_different.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_different.cpp @@ -12,12 +12,12 @@ enum class AbsoluteDifferenceBehavior { Accumulate }; -enum class Signedness { +enum class SignednessSTD { Signed, Unsigned }; -bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsoluteDifferenceBehavior behavior, Signedness sign) { +bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsoluteDifferenceBehavior behavior, SignednessSTD sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -27,7 +27,7 @@ bool AbsoluteDifferenceLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V const IR::U128 operand1 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vn, Q)); const IR::U128 operand2 = v.ir.VectorZeroExtend(esize, v.Vpart(datasize, Vm, Q)); - IR::U128 result = sign == Signedness::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2) + IR::U128 result = sign == SignednessSTD::Signed ? v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2) : v.ir.VectorUnsignedAbsoluteDifference(esize, operand1, operand2); if (behavior == AbsoluteDifferenceBehavior::Accumulate) { @@ -45,7 +45,7 @@ enum class MultiplyLongBehavior { Subtract }; -bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MultiplyLongBehavior behavior, Signedness sign) { +bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MultiplyLongBehavior behavior, SignednessSTD sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -59,7 +59,7 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec const auto reg_n = v.Vpart(datasize, Vn, Q); const auto reg_m = v.Vpart(datasize, Vm, Q); - return sign == Signedness::Signed + return sign == SignednessSTD::Signed ? v.ir.VectorMultiplySignedWiden(esize, reg_n, reg_m) : v.ir.VectorMultiplyUnsignedWiden(esize, reg_n, reg_m); }(); @@ -81,7 +81,7 @@ enum class LongOperationBehavior { Subtraction }; -bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, LongOperationBehavior behavior, Signedness sign) { +bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, LongOperationBehavior behavior, SignednessSTD sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -92,7 +92,7 @@ bool LongOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Ve const auto get_operand = [&](Vec vec) { const IR::U128 tmp = v.Vpart(64, vec, part); - if (sign == Signedness::Signed) { + if (sign == SignednessSTD::Signed) { return v.ir.VectorSignExtend(esize, tmp); } @@ -118,7 +118,7 @@ enum class WideOperationBehavior { Subtraction }; -bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, WideOperationBehavior behavior, Signedness sign) { +bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, WideOperationBehavior behavior, SignednessSTD sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -130,7 +130,7 @@ bool WideOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Ve const IR::U128 operand2 = [&] { const IR::U128 tmp = v.Vpart(64, Vm, part); - if (sign == Signedness::Signed) { + if (sign == SignednessSTD::Signed) { return v.ir.VectorSignExtend(esize, tmp); } @@ -166,75 +166,75 @@ bool TranslatorVisitor::PMULL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Signed); + return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, SignednessSTD::Signed); } bool TranslatorVisitor::SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Signed); + return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, SignednessSTD::Signed); } bool TranslatorVisitor::SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Signed); + return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, SignednessSTD::Signed); } bool TranslatorVisitor::SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Signed); + return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, SignednessSTD::Signed); } bool TranslatorVisitor::SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Signed); + return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, SignednessSTD::Signed); } bool TranslatorVisitor::SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Signed); + return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, SignednessSTD::Signed); } bool TranslatorVisitor::SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Signed); + return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, SignednessSTD::Signed); } bool TranslatorVisitor::SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Signed); + return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, SignednessSTD::Signed); } bool TranslatorVisitor::SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Signed); + return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, SignednessSTD::Signed); } bool TranslatorVisitor::UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, Signedness::Unsigned); + return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Addition, SignednessSTD::Unsigned); } bool TranslatorVisitor::UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, Signedness::Unsigned); + return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::Accumulate, SignednessSTD::Unsigned); } bool TranslatorVisitor::UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, Signedness::Unsigned); + return AbsoluteDifferenceLong(*this, Q, size, Vm, Vn, Vd, AbsoluteDifferenceBehavior::None, SignednessSTD::Unsigned); } bool TranslatorVisitor::UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, Signedness::Unsigned); + return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Addition, SignednessSTD::Unsigned); } bool TranslatorVisitor::UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, Signedness::Unsigned); + return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Accumulate, SignednessSTD::Unsigned); } bool TranslatorVisitor::UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, Signedness::Unsigned); + return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::Subtract, SignednessSTD::Unsigned); } bool TranslatorVisitor::UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, Signedness::Unsigned); + return MultiplyLong(*this, Q, size, Vm, Vn, Vd, MultiplyLongBehavior::None, SignednessSTD::Unsigned); } bool TranslatorVisitor::USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, Signedness::Unsigned); + return WideOperation(*this, Q, size, Vm, Vn, Vd, WideOperationBehavior::Subtraction, SignednessSTD::Unsigned); } bool TranslatorVisitor::USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, Signedness::Unsigned); + return LongOperation(*this, Q, size, Vm, Vn, Vd, LongOperationBehavior::Subtraction, SignednessSTD::Unsigned); } bool TranslatorVisitor::SQDMULL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_same.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_same.cpp index 5c8bf13aeb..1cfc2ced78 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_same.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_three_same.cpp @@ -12,12 +12,12 @@ enum class Operation { Subtract, }; -enum class ExtraBehavior { +enum class ExtraBehaviorSTS { None, Round }; -bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, ExtraBehavior behavior) { +bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, ExtraBehaviorSTS behavior) { if (size == 0b11) { return v.ReservedValue(); } @@ -35,7 +35,7 @@ bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V return v.ir.VectorSub(doubled_esize, operand1, operand2); }(); - if (behavior == ExtraBehavior::Round) { + if (behavior == ExtraBehaviorSTS::Round) { const u64 round_const = 1ULL << (esize - 1); const IR::U128 round_operand = v.ir.VectorBroadcast(doubled_esize, v.I(doubled_esize, round_const)); wide = v.ir.VectorAdd(doubled_esize, wide, round_operand); @@ -48,12 +48,12 @@ bool HighNarrowingOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, V return true; } -enum class AbsDiffExtraBehavior { +enum class AbsDiffExtraBehaviorSTS { None, Accumulate }; -bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehavior behavior) { +bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, AbsDiffExtraBehaviorSTS behavior) { if (size == 0b11) { return v.ReservedValue(); } @@ -66,7 +66,7 @@ bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, const IR::U128 result = [&] { const IR::U128 tmp = v.ir.VectorSignedAbsoluteDifference(esize, operand1, operand2); - if (behavior == AbsDiffExtraBehavior::Accumulate) { + if (behavior == AbsDiffExtraBehaviorSTS::Accumulate) { const IR::U128 d = v.V(datasize, Vd); return v.ir.VectorAdd(esize, d, tmp); } @@ -78,12 +78,12 @@ bool SignedAbsoluteDifference(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, return true; } -enum class Signedness { +enum class SignednessSTS { Signed, Unsigned }; -bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) { +bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -93,14 +93,14 @@ bool RoundingHalvingAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec V const IR::U128 operand1 = v.V(datasize, Vm); const IR::U128 operand2 = v.V(datasize, Vn); - const IR::U128 result = sign == Signedness::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2) + const IR::U128 result = sign == SignednessSTS::Signed ? v.ir.VectorRoundingHalvingAddSigned(esize, operand1, operand2) : v.ir.VectorRoundingHalvingAddUnsigned(esize, operand1, operand2); v.V(datasize, Vd, result); return true; } -bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) { +bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) { if (size == 0b11 && !Q) { return v.ReservedValue(); } @@ -111,7 +111,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn const IR::U128 operand1 = v.V(datasize, Vn); const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { - if (sign == Signedness::Signed) { + if (sign == SignednessSTS::Signed) { return v.ir.VectorRoundingShiftLeftSigned(esize, operand1, operand2); } @@ -122,7 +122,7 @@ bool RoundingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn return true; } -enum class ComparisonType { +enum class ComparisonTypeSTS { EQ, GE, AbsoluteGE, @@ -130,7 +130,7 @@ enum class ComparisonType { AbsoluteGT }; -bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonType type) { +bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, ComparisonTypeSTS type) { if (sz && !Q) { return v.ReservedValue(); } @@ -142,17 +142,17 @@ bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { switch (type) { - case ComparisonType::EQ: + case ComparisonTypeSTS::EQ: return v.ir.FPVectorEqual(esize, operand1, operand2); - case ComparisonType::GE: + case ComparisonTypeSTS::GE: return v.ir.FPVectorGreaterEqual(esize, operand1, operand2); - case ComparisonType::AbsoluteGE: + case ComparisonTypeSTS::AbsoluteGE: return v.ir.FPVectorGreaterEqual(esize, v.ir.FPVectorAbs(esize, operand1), v.ir.FPVectorAbs(esize, operand2)); - case ComparisonType::GT: + case ComparisonTypeSTS::GT: return v.ir.FPVectorGreater(esize, operand1, operand2); - case ComparisonType::AbsoluteGT: + case ComparisonTypeSTS::AbsoluteGT: return v.ir.FPVectorGreater(esize, v.ir.FPVectorAbs(esize, operand1), v.ir.FPVectorAbs(esize, operand2)); @@ -165,12 +165,12 @@ bool FPCompareRegister(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve return true; } -enum class MinMaxOperation { +enum class MinMaxOperationSTS { Min, Max, }; -bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation, Signedness sign) { +bool VectorMinMaxOperationSTS(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation, SignednessSTS sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -182,14 +182,14 @@ bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { switch (operation) { - case MinMaxOperation::Max: - if (sign == Signedness::Signed) { + case MinMaxOperationSTS::Max: + if (sign == SignednessSTS::Signed) { return v.ir.VectorMaxSigned(esize, operand1, operand2); } return v.ir.VectorMaxUnsigned(esize, operand1, operand2); - case MinMaxOperation::Min: - if (sign == Signedness::Signed) { + case MinMaxOperationSTS::Min: + if (sign == SignednessSTS::Signed) { return v.ir.VectorMinSigned(esize, operand1, operand2); } return v.ir.VectorMinUnsigned(esize, operand1, operand2); @@ -203,7 +203,7 @@ bool VectorMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve return true; } -bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) { +bool FPMinMaxOperationSTS(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation) { if (sz && !Q) { return v.ReservedValue(); } @@ -214,7 +214,7 @@ bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve const IR::U128 operand1 = v.V(datasize, Vn); const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { - if (operation == MinMaxOperation::Min) { + if (operation == MinMaxOperationSTS::Min) { return v.ir.FPVectorMin(esize, operand1, operand2); } @@ -225,7 +225,7 @@ bool FPMinMaxOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Ve return true; } -bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation) { +bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation) { if (sz && !Q) { return v.ReservedValue(); } @@ -236,7 +236,7 @@ bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec const IR::U128 operand1 = v.V(datasize, Vn); const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { - if (operation == MinMaxOperation::Min) { + if (operation == MinMaxOperationSTS::Min) { return v.ir.FPVectorMinNumeric(esize, operand1, operand2); } @@ -247,7 +247,7 @@ bool FPMinMaxNumericOperation(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec return true; } -bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperation operation, Signedness sign) { +bool PairedMinMaxOperationSTS(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, MinMaxOperationSTS operation, SignednessSTS sign) { if (size == 0b11) { return v.ReservedValue(); } @@ -259,14 +259,14 @@ bool PairedMinMaxOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Ve const IR::U128 operand2 = v.V(datasize, Vm); IR::U128 result = [&] { switch (operation) { - case MinMaxOperation::Max: - if (sign == Signedness::Signed) { + case MinMaxOperationSTS::Max: + if (sign == SignednessSTS::Signed) { return Q ? v.ir.VectorPairedMaxSigned(esize, operand1, operand2) : v.ir.VectorPairedMaxSignedLower(esize, operand1, operand2); } return Q ? v.ir.VectorPairedMaxUnsigned(esize, operand1, operand2) : v.ir.VectorPairedMaxUnsignedLower(esize, operand1, operand2); - case MinMaxOperation::Min: - if (sign == Signedness::Signed) { + case MinMaxOperationSTS::Min: + if (sign == SignednessSTS::Signed) { return Q ? v.ir.VectorPairedMinSigned(esize, operand1, operand2) : v.ir.VectorPairedMinSignedLower(esize, operand1, operand2); } return Q ? v.ir.VectorPairedMinUnsigned(esize, operand1, operand2) : v.ir.VectorPairedMinUnsignedLower(esize, operand1, operand2); @@ -311,7 +311,7 @@ bool FPPairedMinMax(TranslatorVisitor& v, bool Q, bool sz, Vec Vm, Vec Vn, Vec V return true; } -bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, Signedness sign) { +bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Operation op, SignednessSTS sign) { if (size == 0b11 && !Q) { return v.ReservedValue(); } @@ -323,7 +323,7 @@ bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Ve const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { - if (sign == Signedness::Signed) { + if (sign == SignednessSTS::Signed) { if (op == Operation::Add) { return v.ir.VectorSignedSaturatedAdd(esize, operand1, operand2); } @@ -342,7 +342,7 @@ bool SaturatingArithmeticOperation(TranslatorVisitor& v, bool Q, Imm<2> size, Ve return true; } -bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, Signedness sign) { +bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd, SignednessSTS sign) { if (size == 0b11 && !Q) { return v.ReservedValue(); } @@ -353,7 +353,7 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vm, Vec const IR::U128 operand1 = v.V(datasize, Vn); const IR::U128 operand2 = v.V(datasize, Vm); const IR::U128 result = [&] { - if (sign == Signedness::Signed) { + if (sign == SignednessSTS::Signed) { return v.ir.VectorSignedSaturatedShiftLeft(esize, operand1, operand2); } @@ -401,27 +401,27 @@ bool TranslatorVisitor::CMGE_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) } bool TranslatorVisitor::SABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::Accumulate); + return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehaviorSTS::Accumulate); } bool TranslatorVisitor::SABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehavior::None); + return SignedAbsoluteDifference(*this, Q, size, Vm, Vn, Vd, AbsDiffExtraBehaviorSTS::None); } bool TranslatorVisitor::SMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed); + return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Signed); } bool TranslatorVisitor::SMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Signed); + return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Signed); } bool TranslatorVisitor::SMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed); + return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Signed); } bool TranslatorVisitor::SMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Signed); + return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Signed); } bool TranslatorVisitor::SQDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -506,19 +506,19 @@ bool TranslatorVisitor::MUL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::ADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::None); + return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehaviorSTS::None); } bool TranslatorVisitor::RADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehavior::Round); + return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, ExtraBehaviorSTS::Round); } bool TranslatorVisitor::SUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::None); + return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehaviorSTS::None); } bool TranslatorVisitor::RSUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehavior::Round); + return HighNarrowingOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, ExtraBehaviorSTS::Round); } bool TranslatorVisitor::SHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -554,15 +554,15 @@ bool TranslatorVisitor::SHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Signed); + return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, SignednessSTS::Signed); } bool TranslatorVisitor::SQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Signed); + return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, SignednessSTS::Signed); } bool TranslatorVisitor::SRHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Signed); + return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed); } bool TranslatorVisitor::UHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -598,15 +598,15 @@ bool TranslatorVisitor::UHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::UQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, Signedness::Unsigned); + return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Add, SignednessSTS::Unsigned); } bool TranslatorVisitor::UQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, Signedness::Unsigned); + return SaturatingArithmeticOperation(*this, Q, size, Vm, Vn, Vd, Operation::Subtract, SignednessSTS::Unsigned); } bool TranslatorVisitor::URHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned); + return RoundingHalvingAdd(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned); } bool TranslatorVisitor::ADDP_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -642,11 +642,11 @@ bool TranslatorVisitor::FABD_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FACGE_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGE); + return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::AbsoluteGE); } bool TranslatorVisitor::FACGT_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::AbsoluteGT); + return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::AbsoluteGT); } bool TranslatorVisitor::FADD_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { @@ -737,15 +737,15 @@ bool TranslatorVisitor::FCMEQ_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FCMEQ_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::EQ); + return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::EQ); } bool TranslatorVisitor::FCMGE_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GE); + return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::GE); } bool TranslatorVisitor::FCMGT_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonType::GT); + return FPCompareRegister(*this, Q, sz, Vm, Vn, Vd, ComparisonTypeSTS::GT); } bool TranslatorVisitor::AND_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) { @@ -827,11 +827,11 @@ bool TranslatorVisitor::CMTST_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed); + return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed); } bool TranslatorVisitor::SRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Signed); + return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Signed); } bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -851,11 +851,11 @@ bool TranslatorVisitor::SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::UQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned); + return SaturatingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned); } bool TranslatorVisitor::URSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, Signedness::Unsigned); + return RoundingShiftLeft(*this, Q, size, Vm, Vn, Vd, SignednessSTS::Unsigned); } bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -875,11 +875,11 @@ bool TranslatorVisitor::USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::UMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned); + return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Unsigned); } bool TranslatorVisitor::UMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Max, Signedness::Unsigned); + return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Max, SignednessSTS::Unsigned); } bool TranslatorVisitor::UABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { @@ -918,11 +918,11 @@ bool TranslatorVisitor::UABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::UMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return VectorMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned); + return VectorMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Unsigned); } bool TranslatorVisitor::UMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { - return PairedMinMaxOperation(*this, Q, size, Vm, Vn, Vd, MinMaxOperation::Min, Signedness::Unsigned); + return PairedMinMaxOperationSTS(*this, Q, size, Vm, Vn, Vd, MinMaxOperationSTS::Min, SignednessSTS::Unsigned); } bool TranslatorVisitor::FSUB_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { @@ -1104,11 +1104,11 @@ bool TranslatorVisitor::EOR_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FMAX_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max); + return FPMinMaxOperationSTS(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Max); } bool TranslatorVisitor::FMAXNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Max); + return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Max); } bool TranslatorVisitor::FMAXNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { @@ -1120,11 +1120,11 @@ bool TranslatorVisitor::FMAXP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FMIN_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPMinMaxOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min); + return FPMinMaxOperationSTS(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Min); } bool TranslatorVisitor::FMINNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { - return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperation::Min); + return FPMinMaxNumericOperation(*this, Q, sz, Vm, Vn, Vd, MinMaxOperationSTS::Min); } bool TranslatorVisitor::FMINNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp index ca3e3b9591..80a8e531a7 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_two_register_misc.cpp @@ -8,7 +8,7 @@ namespace Dynarmic::A64 { namespace { -enum class ComparisonType { +enum class ComparisonTypeSTRM { EQ, GE, GT, @@ -16,7 +16,7 @@ enum class ComparisonType { LT, }; -bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, ComparisonType type) { +bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, ComparisonTypeSTRM type) { if (size == 0b11 && !Q) { return v.ReservedValue(); } @@ -28,15 +28,15 @@ bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec V const IR::U128 zero = v.ir.ZeroVector(); IR::U128 result = [&] { switch (type) { - case ComparisonType::EQ: + case ComparisonTypeSTRM::EQ: return v.ir.VectorEqual(esize, operand, zero); - case ComparisonType::GE: + case ComparisonTypeSTRM::GE: return v.ir.VectorGreaterEqualSigned(esize, operand, zero); - case ComparisonType::GT: + case ComparisonTypeSTRM::GT: return v.ir.VectorGreaterSigned(esize, operand, zero); - case ComparisonType::LE: + case ComparisonTypeSTRM::LE: return v.ir.VectorLessEqualSigned(esize, operand, zero); - case ComparisonType::LT: + case ComparisonTypeSTRM::LT: default: return v.ir.VectorLessSigned(esize, operand, zero); } @@ -50,7 +50,7 @@ bool CompareAgainstZero(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec V return true; } -bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, ComparisonType type) { +bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, ComparisonTypeSTRM type) { if (sz && !Q) { return v.ReservedValue(); } @@ -62,15 +62,15 @@ bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, const IR::U128 zero = v.ir.ZeroVector(); const IR::U128 result = [&] { switch (type) { - case ComparisonType::EQ: + case ComparisonTypeSTRM::EQ: return v.ir.FPVectorEqual(esize, operand, zero); - case ComparisonType::GE: + case ComparisonTypeSTRM::GE: return v.ir.FPVectorGreaterEqual(esize, operand, zero); - case ComparisonType::GT: + case ComparisonTypeSTRM::GT: return v.ir.FPVectorGreater(esize, operand, zero); - case ComparisonType::LE: + case ComparisonTypeSTRM::LE: return v.ir.FPVectorGreaterEqual(esize, zero, operand); - case ComparisonType::LT: + case ComparisonTypeSTRM::LT: return v.ir.FPVectorGreater(esize, zero, operand); } @@ -81,12 +81,12 @@ bool FPCompareAgainstZero(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, return true; } -enum class Signedness { +enum class SignednessSTRM { Signed, Unsigned }; -bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, Signedness signedness) { +bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, SignednessSTRM SignednessSTRM) { if (sz && !Q) { return v.ReservedValue(); } @@ -96,7 +96,7 @@ bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd const FP::RoundingMode rounding_mode = v.ir.current_location->FPCR().RMode(); const IR::U128 operand = v.V(datasize, Vn); - const IR::U128 result = signedness == Signedness::Signed + const IR::U128 result = SignednessSTRM == SignednessSTRM::Signed ? v.ir.FPVectorFromSignedFixed(esize, operand, 0, rounding_mode) : v.ir.FPVectorFromUnsignedFixed(esize, operand, 0, rounding_mode); @@ -104,7 +104,7 @@ bool IntegerConvertToFloat(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd return true; } -bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, Signedness signedness, FP::RoundingMode rounding_mode) { +bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd, SignednessSTRM SignednessSTRM, FP::RoundingMode rounding_mode) { if (sz && !Q) { return v.ReservedValue(); } @@ -113,7 +113,7 @@ bool FloatConvertToInteger(TranslatorVisitor& v, bool Q, bool sz, Vec Vn, Vec Vd const size_t esize = sz ? 64 : 32; const IR::U128 operand = v.V(datasize, Vn); - const IR::U128 result = signedness == Signedness::Signed + const IR::U128 result = SignednessSTRM == SignednessSTRM::Signed ? v.ir.FPVectorToSignedFixed(esize, operand, 0, rounding_mode) : v.ir.FPVectorToUnsignedFixed(esize, operand, 0, rounding_mode); @@ -168,7 +168,7 @@ enum class PairedAddLongExtraBehavior { Accumulate, }; -bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Signedness sign, PairedAddLongExtraBehavior behavior) { +bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, SignednessSTRM sign, PairedAddLongExtraBehavior behavior) { if (size == 0b11) { return v.ReservedValue(); } @@ -178,7 +178,7 @@ bool PairedAddLong(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Si const IR::U128 operand = v.V(datasize, Vn); IR::U128 result = [&] { - if (sign == Signedness::Signed) { + if (sign == SignednessSTRM::Signed) { return v.ir.VectorPairedAddSignedWiden(esize, operand); } @@ -254,23 +254,23 @@ bool TranslatorVisitor::CNT(bool Q, Imm<2> size, Vec Vn, Vec Vd) { } bool TranslatorVisitor::CMGE_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::GE); + return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::GE); } bool TranslatorVisitor::CMGT_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::GT); + return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::GT); } bool TranslatorVisitor::CMEQ_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::EQ); + return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::EQ); } bool TranslatorVisitor::CMLE_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::LE); + return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::LE); } bool TranslatorVisitor::CMLT_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonType::LT); + return CompareAgainstZero(*this, Q, size, Vn, Vd, ComparisonTypeSTRM::LT); } bool TranslatorVisitor::ABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { @@ -341,23 +341,23 @@ bool TranslatorVisitor::FCMEQ_zero_3(bool Q, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FCMEQ_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::EQ); + return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::EQ); } bool TranslatorVisitor::FCMGE_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::GE); + return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::GE); } bool TranslatorVisitor::FCMGT_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::GT); + return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::GT); } bool TranslatorVisitor::FCMLE_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::LE); + return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::LE); } bool TranslatorVisitor::FCMLT_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonType::LT); + return FPCompareAgainstZero(*this, Q, sz, Vn, Vd, ComparisonTypeSTRM::LT); } bool TranslatorVisitor::FCVTL(bool Q, bool sz, Vec Vn, Vec Vd) { @@ -411,19 +411,19 @@ bool TranslatorVisitor::FCVTN(bool Q, bool sz, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FCVTNS_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::ToNearest_TieEven); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::ToNearest_TieEven); } bool TranslatorVisitor::FCVTMS_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsMinusInfinity); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsMinusInfinity); } bool TranslatorVisitor::FCVTAS_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::ToNearest_TieAwayFromZero); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::ToNearest_TieAwayFromZero); } bool TranslatorVisitor::FCVTPS_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsPlusInfinity); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsPlusInfinity); } bool TranslatorVisitor::FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) { @@ -447,27 +447,27 @@ bool TranslatorVisitor::FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) { } bool TranslatorVisitor::FCVTZS_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Signed, FP::RoundingMode::TowardsZero); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed, FP::RoundingMode::TowardsZero); } bool TranslatorVisitor::FCVTNU_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::ToNearest_TieEven); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::ToNearest_TieEven); } bool TranslatorVisitor::FCVTMU_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsMinusInfinity); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsMinusInfinity); } bool TranslatorVisitor::FCVTAU_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::ToNearest_TieAwayFromZero); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::ToNearest_TieAwayFromZero); } bool TranslatorVisitor::FCVTPU_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsPlusInfinity); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsPlusInfinity); } bool TranslatorVisitor::FCVTZU_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return FloatConvertToInteger(*this, Q, sz, Vn, Vd, Signedness::Unsigned, FP::RoundingMode::TowardsZero); + return FloatConvertToInteger(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned, FP::RoundingMode::TowardsZero); } bool TranslatorVisitor::FRINTN_1(bool Q, Vec Vn, Vec Vd) { @@ -780,19 +780,19 @@ bool TranslatorVisitor::USQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Signed, PairedAddLongExtraBehavior::Accumulate); + return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Signed, PairedAddLongExtraBehavior::Accumulate); } bool TranslatorVisitor::SADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Signed, PairedAddLongExtraBehavior::None); + return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Signed, PairedAddLongExtraBehavior::None); } bool TranslatorVisitor::UADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Unsigned, PairedAddLongExtraBehavior::Accumulate); + return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Unsigned, PairedAddLongExtraBehavior::Accumulate); } bool TranslatorVisitor::UADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - return PairedAddLong(*this, Q, size, Vn, Vd, Signedness::Unsigned, PairedAddLongExtraBehavior::None); + return PairedAddLong(*this, Q, size, Vn, Vd, SignednessSTRM::Unsigned, PairedAddLongExtraBehavior::None); } bool TranslatorVisitor::URECPE(bool Q, bool sz, Vec Vn, Vec Vd) { @@ -824,11 +824,11 @@ bool TranslatorVisitor::URSQRTE(bool Q, bool sz, Vec Vn, Vec Vd) { } bool TranslatorVisitor::SCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, Signedness::Signed); + return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, SignednessSTRM::Signed); } bool TranslatorVisitor::UCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { - return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, Signedness::Unsigned); + return IntegerConvertToFloat(*this, Q, sz, Vn, Vd, SignednessSTRM::Unsigned); } bool TranslatorVisitor::SHLL(bool Q, Imm<2> size, Vec Vn, Vec Vd) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp index 07234fc61b..d23b5fc144 100644 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp @@ -11,7 +11,7 @@ namespace Dynarmic::A64 { namespace { -std::pair Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) { +std::pair CombineVector(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> Vmlo) { if (size == 0b01) { return {concatenate(H, L, M).ZeroExtend(), Vmlo.ZeroExtend()}; } @@ -19,19 +19,19 @@ std::pair Combine(Imm<2> size, Imm<1> H, Imm<1> L, Imm<1> M, Imm<4> return {concatenate(H, L).ZeroExtend(), concatenate(M, Vmlo).ZeroExtend()}; } -enum class ExtraBehavior { +enum class ExtraBehaviorSVXIE { None, Extended, Accumulate, Subtract, }; -bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) { +bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) { if (size != 0b01 && size != 0b10) { return v.ReservedValue(); } - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo); const size_t idxdsize = H == 1 ? 128 : 64; const size_t esize = 8 << size.ZeroExtend(); const size_t datasize = Q ? 128 : 64; @@ -41,9 +41,9 @@ bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm< const IR::U128 operand3 = v.V(datasize, Vd); IR::U128 result = v.ir.VectorMultiply(esize, operand1, operand2); - if (extra_behavior == ExtraBehavior::Accumulate) { + if (extra_behavior == ExtraBehaviorSVXIE::Accumulate) { result = v.ir.VectorAdd(esize, operand3, result); - } else if (extra_behavior == ExtraBehavior::Subtract) { + } else if (extra_behavior == ExtraBehaviorSVXIE::Subtract) { result = v.ir.VectorSub(esize, operand3, result); } @@ -51,7 +51,7 @@ bool MultiplyByElement(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm< return true; } -bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) { +bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) { if (sz && L == 1) { return v.ReservedValue(); } @@ -71,13 +71,13 @@ bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> const IR::U128 result = [&] { switch (extra_behavior) { - case ExtraBehavior::None: + case ExtraBehaviorSVXIE::None: return v.ir.FPVectorMul(esize, operand1, operand2); - case ExtraBehavior::Extended: + case ExtraBehaviorSVXIE::Extended: return v.ir.FPVectorMulX(esize, operand1, operand2); - case ExtraBehavior::Accumulate: + case ExtraBehaviorSVXIE::Accumulate: return v.ir.FPVectorMulAdd(esize, operand3, operand1, operand2); - case ExtraBehavior::Subtract: + case ExtraBehaviorSVXIE::Subtract: return v.ir.FPVectorMulAdd(esize, operand3, v.ir.FPVectorNeg(esize, operand1), operand2); } UNREACHABLE(); @@ -86,7 +86,7 @@ bool FPMultiplyByElement(TranslatorVisitor& v, bool Q, bool sz, Imm<1> L, Imm<1> return true; } -bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior) { +bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior) { const size_t idxdsize = H == 1 ? 128 : 64; const size_t index = concatenate(H, L, M).ZeroExtend(); const Vec Vm = Vmlo.ZeroExtend(); @@ -101,13 +101,13 @@ bool FPMultiplyByElementHalfPrecision(TranslatorVisitor& v, bool Q, Imm<1> L, Im // regular multiplies and extended multiplies. const IR::U128 result = [&] { switch (extra_behavior) { - case ExtraBehavior::None: + case ExtraBehaviorSVXIE::None: break; - case ExtraBehavior::Extended: + case ExtraBehaviorSVXIE::Extended: break; - case ExtraBehavior::Accumulate: + case ExtraBehaviorSVXIE::Accumulate: return v.ir.FPVectorMulAdd(esize, operand3, operand1, operand2); - case ExtraBehavior::Subtract: + case ExtraBehaviorSVXIE::Subtract: return v.ir.FPVectorMulAdd(esize, operand3, v.ir.FPVectorNeg(esize, operand1), operand2); } UNREACHABLE(); @@ -151,12 +151,12 @@ bool DotProduct(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I return true; } -enum class Signedness { +enum class SignednessSVXIE { Signed, Unsigned }; -bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehavior extra_behavior, Signedness sign) { +bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd, ExtraBehaviorSVXIE extra_behavior, SignednessSVXIE sign) { if (size == 0b00 || size == 0b11) { return v.ReservedValue(); } @@ -164,23 +164,23 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, const size_t idxsize = H == 1 ? 128 : 64; const size_t esize = 8 << size.ZeroExtend(); const size_t datasize = 64; - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo); const IR::U128 operand1 = v.Vpart(datasize, Vn, Q); const IR::U128 operand2 = v.V(idxsize, Vm); const IR::U128 index_vector = v.ir.VectorBroadcastElement(esize, operand2, index); const IR::U128 result = [&] { - const IR::U128 product = sign == Signedness::Signed + const IR::U128 product = sign == SignednessSVXIE::Signed ? v.ir.VectorMultiplySignedWiden(esize, operand1, index_vector) : v.ir.VectorMultiplyUnsignedWiden(esize, operand1, index_vector); - if (extra_behavior == ExtraBehavior::None) { + if (extra_behavior == ExtraBehaviorSVXIE::None) { return product; } const IR::U128 operand3 = v.V(2 * datasize, Vd); - if (extra_behavior == ExtraBehavior::Accumulate) { + if (extra_behavior == ExtraBehaviorSVXIE::Accumulate) { return v.ir.VectorAdd(2 * esize, operand3, product); } @@ -193,15 +193,15 @@ bool MultiplyLong(TranslatorVisitor& v, bool Q, Imm<2> size, Imm<1> L, Imm<1> M, } // Anonymous namespace bool TranslatorVisitor::MLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate); + return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate); } bool TranslatorVisitor::MLS_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract); + return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract); } bool TranslatorVisitor::MUL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None); + return MultiplyByElement(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None); } bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<2> rot, Imm<1> H, Vec Vn, Vec Vd) { @@ -292,39 +292,39 @@ bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4 } bool TranslatorVisitor::FMLA_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate); + return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate); } bool TranslatorVisitor::FMLA_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate); + return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate); } bool TranslatorVisitor::FMLS_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract); + return FPMultiplyByElementHalfPrecision(*this, Q, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract); } bool TranslatorVisitor::FMLS_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract); + return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract); } bool TranslatorVisitor::FMUL_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None); + return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None); } bool TranslatorVisitor::FMULX_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Extended); + return FPMultiplyByElement(*this, Q, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Extended); } bool TranslatorVisitor::SMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate, Signedness::Signed); + return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate, SignednessSVXIE::Signed); } bool TranslatorVisitor::SMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract, Signedness::Signed); + return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract, SignednessSVXIE::Signed); } bool TranslatorVisitor::SMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None, Signedness::Signed); + return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None, SignednessSVXIE::Signed); } bool TranslatorVisitor::SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { @@ -336,7 +336,7 @@ bool TranslatorVisitor::SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I const size_t idxsize = H == 1 ? 128 : 64; const size_t esize = 8 << size.ZeroExtend(); const size_t datasize = 64; - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo); const IR::U128 operand1 = Vpart(datasize, Vn, part); const IR::U128 operand2 = V(idxsize, Vm); @@ -355,7 +355,7 @@ bool TranslatorVisitor::SQDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, I const size_t idxsize = H == 1 ? 128 : 64; const size_t esize = 8 << size.ZeroExtend(); const size_t datasize = Q ? 128 : 64; - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo); const IR::U128 operand1 = V(datasize, Vn); const IR::U128 operand2 = V(idxsize, Vm); @@ -374,7 +374,7 @@ bool TranslatorVisitor::SQRDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, const size_t idxsize = H == 1 ? 128 : 64; const size_t esize = 8 << size.ZeroExtend(); const size_t datasize = Q ? 128 : 64; - const auto [index, Vm] = Combine(size, H, L, M, Vmlo); + const auto [index, Vm] = CombineVector(size, H, L, M, Vmlo); const IR::U128 operand1 = V(datasize, Vn); const IR::U128 operand2 = V(idxsize, Vm); @@ -394,15 +394,15 @@ bool TranslatorVisitor::UDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> } bool TranslatorVisitor::UMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate, Signedness::Unsigned); + return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Accumulate, SignednessSVXIE::Unsigned); } bool TranslatorVisitor::UMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract, Signedness::Unsigned); + return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::Subtract, SignednessSVXIE::Unsigned); } bool TranslatorVisitor::UMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { - return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None, Signedness::Unsigned); + return MultiplyLong(*this, Q, size, L, M, Vmlo, H, Vn, Vd, ExtraBehaviorSVXIE::None, SignednessSVXIE::Unsigned); } } // namespace Dynarmic::A64 diff --git a/externals/dynarmic/src/dynarmic/interface/A32/arch_version.h b/externals/dynarmic/src/dynarmic/interface/A32/arch_version.h index 240e40ee4c..209bc594f2 100644 --- a/externals/dynarmic/src/dynarmic/interface/A32/arch_version.h +++ b/externals/dynarmic/src/dynarmic/interface/A32/arch_version.h @@ -5,10 +5,12 @@ #pragma once +#include + namespace Dynarmic { namespace A32 { -enum class ArchVersion { +enum class ArchVersion : std::uint8_t { v3, v4, v4T, diff --git a/externals/dynarmic/src/dynarmic/interface/A32/config.h b/externals/dynarmic/src/dynarmic/interface/A32/config.h index 360df06e2a..11fe2236a2 100644 --- a/externals/dynarmic/src/dynarmic/interface/A32/config.h +++ b/externals/dynarmic/src/dynarmic/interface/A32/config.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * SPDX-License-Identifier: 0BSD @@ -120,14 +123,32 @@ struct UserCallbacks : public TranslateCallbacks { }; struct UserConfig { + bool HasOptimization(OptimizationFlag f) const { + if (!unsafe_optimizations) { + f &= all_safe_optimizations; + } + return (f & optimizations) != no_optimizations; + } + UserCallbacks* callbacks; - size_t processor_id = 0; ExclusiveMonitor* global_monitor = nullptr; - /// Select the architecture version to use. - /// There are minor behavioural differences between versions. - ArchVersion arch_version = ArchVersion::v8; + // Page Table + // The page table is used for faster memory access. If an entry in the table is nullptr, + // the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks. + static constexpr std::size_t PAGE_BITS = 12; + static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS); + std::array* page_table = nullptr; + + /// Coprocessors + std::array, 16> coprocessors{}; + + /// Fastmem Pointer + /// This should point to the beginning of a 4GB address space which is in arranged just like + /// what you wish for emulated memory to be. If the host page faults on an address, the JIT + /// will fallback to calling the MemoryRead*/MemoryWrite* callbacks. + std::optional fastmem_pointer = std::nullopt; /// This selects other optimizations than can't otherwise be disabled by setting other /// configuration options. This includes: @@ -137,12 +158,29 @@ struct UserConfig { /// This is intended to be used for debugging. OptimizationFlag optimizations = all_safe_optimizations; - bool HasOptimization(OptimizationFlag f) const { - if (!unsafe_optimizations) { - f &= all_safe_optimizations; - } - return (f & optimizations) != no_optimizations; - } + /// Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host). + /// Maximum size is limited by the maximum length of a x86_64 / arm64 jump. + std::uint32_t code_cache_size = 128 * 1024 * 1024; // bytes + + /// Masks out the first N bits in host pointers from the page table. + /// The intention behind this is to allow users of Dynarmic to pack attributes in the + /// same integer and update the pointer attribute pair atomically. + /// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes. + std::int32_t page_table_pointer_mask_bits = 0; + + /// Select the architecture version to use. + /// There are minor behavioural differences between versions. + ArchVersion arch_version = ArchVersion::v8; + + /// Processor ID + std::uint8_t processor_id = 0; + + /// Determines if we should detect memory accesses via page_table that straddle are + /// misaligned. Accesses that straddle page boundaries will fallback to the relevant + /// memory callback. + /// This value should be the required access sizes this applies to ORed together. + /// To detect any access, use: 8 | 16 | 32 | 64. + std::uint8_t detect_misaligned_access_via_page_table = 0; /// This enables unsafe optimizations that reduce emulation accuracy in favour of speed. /// For safety, in order to enable unsafe optimizations you have to set BOTH this flag @@ -150,12 +188,6 @@ struct UserConfig { /// The prefered and tested mode for this library is with unsafe optimizations disabled. bool unsafe_optimizations = false; - // Page Table - // The page table is used for faster memory access. If an entry in the table is nullptr, - // the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks. - static constexpr std::size_t PAGE_BITS = 12; - static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS); - std::array* page_table = nullptr; /// Determines if the pointer in the page_table shall be offseted locally or globally. /// 'false' will access page_table[addr >> bits][addr & mask] /// 'true' will access page_table[addr >> bits][addr] @@ -163,26 +195,11 @@ struct UserConfig { /// So there might be wrongly faulted pages which maps to nullptr. /// This can be avoided by carefully allocating the memory region. bool absolute_offset_page_table = false; - /// Masks out the first N bits in host pointers from the page table. - /// The intention behind this is to allow users of Dynarmic to pack attributes in the - /// same integer and update the pointer attribute pair atomically. - /// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes. - int page_table_pointer_mask_bits = 0; - /// Determines if we should detect memory accesses via page_table that straddle are - /// misaligned. Accesses that straddle page boundaries will fallback to the relevant - /// memory callback. - /// This value should be the required access sizes this applies to ORed together. - /// To detect any access, use: 8 | 16 | 32 | 64. - std::uint8_t detect_misaligned_access_via_page_table = 0; + /// Determines if the above option only triggers when the misalignment straddles a /// page boundary. bool only_detect_misalignment_via_page_table_on_page_boundary = false; - // Fastmem Pointer - // This should point to the beginning of a 4GB address space which is in arranged just like - // what you wish for emulated memory to be. If the host page faults on an address, the JIT - // will fallback to calling the MemoryRead*/MemoryWrite* callbacks. - std::optional fastmem_pointer = std::nullopt; /// Determines if instructions that pagefault should cause recompilation of that block /// with fastmem disabled. /// Recompiled code will use the page_table if this is available, otherwise memory @@ -198,9 +215,6 @@ struct UserConfig { /// callbacks. bool recompile_on_exclusive_fastmem_failure = true; - // Coprocessors - std::array, 16> coprocessors{}; - /// When set to true, UserCallbacks::InstructionSynchronizationBarrierRaised will be /// called when an ISB instruction is executed. /// When set to false, ISB will be treated as a NOP instruction. @@ -234,10 +248,6 @@ struct UserConfig { /// in unusual behavior. bool always_little_endian = false; - // Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host). - // Maximum size is limited by the maximum length of a x86_64 / arm64 jump. - size_t code_cache_size = 128 * 1024 * 1024; // bytes - /// Internal use only bool very_verbose_debugging_output = false; }; diff --git a/externals/dynarmic/src/dynarmic/interface/A64/config.h b/externals/dynarmic/src/dynarmic/interface/A64/config.h index c8ed623eb4..3563c0b2f4 100644 --- a/externals/dynarmic/src/dynarmic/interface/A64/config.h +++ b/externals/dynarmic/src/dynarmic/interface/A64/config.h @@ -136,11 +136,30 @@ struct UserCallbacks { }; struct UserConfig { + /// Fastmem Pointer + /// This should point to the beginning of a 2^page_table_address_space_bits bytes + /// address space which is in arranged just like what you wish for emulated memory to + /// be. If the host page faults on an address, the JIT will fallback to calling the + /// MemoryRead*/MemoryWrite* callbacks. + std::optional fastmem_pointer = std::nullopt; + UserCallbacks* callbacks; - size_t processor_id = 0; ExclusiveMonitor* global_monitor = nullptr; + /// Pointer to where TPIDRRO_EL0 is stored. This pointer will be inserted into + /// emitted code. + const std::uint64_t* tpidrro_el0 = nullptr; + + /// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into + /// emitted code. + std::uint64_t* tpidr_el0 = nullptr; + + /// Pointer to the page table which we can use for direct page table access. + /// If an entry in page_table is null, the relevant memory callback will be called. + /// If page_table is nullptr, all memory accesses hit the memory callbacks. + void** page_table = nullptr; + /// This selects other optimizations than can't otherwise be disabled by setting other /// configuration options. This includes: /// - IR optimizations @@ -149,12 +168,50 @@ struct UserConfig { /// This is intended to be used for debugging. OptimizationFlag optimizations = all_safe_optimizations; - bool HasOptimization(OptimizationFlag f) const { - if (!unsafe_optimizations) { - f &= all_safe_optimizations; - } - return (f & optimizations) != no_optimizations; - } + /// Declares how many valid address bits are there in virtual addresses. + /// Determines the size of page_table. Valid values are between 12 and 64 inclusive. + /// This is only used if page_table is not nullptr. + std::uint32_t page_table_address_space_bits = 36; + + /// Masks out the first N bits in host pointers from the page table. + /// The intention behind this is to allow users of Dynarmic to pack attributes in the + /// same integer and update the pointer attribute pair atomically. + /// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes. + std::int32_t page_table_pointer_mask_bits = 0; + + /// Counter-timer frequency register. The value of the register is not interpreted by + /// dynarmic. + std::uint32_t cntfrq_el0 = 600000000; + + /// CTR_EL0<27:24> is log2 of the cache writeback granule in words. + /// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words. + /// CTR_EL0<19:16> is log2 of the smallest data/unified cacheline in words. + /// CTR_EL0<15:14> is the level 1 instruction cache policy. + /// CTR_EL0<3:0> is log2 of the smallest instruction cacheline in words. + std::uint32_t ctr_el0 = 0x8444c004; + + /// DCZID_EL0<3:0> is log2 of the block size in words + /// DCZID_EL0<4> is 0 if the DC ZVA instruction is permitted. + std::uint32_t dczid_el0 = 4; + + /// Declares how many valid address bits are there in virtual addresses. + /// Determines the size of fastmem arena. Valid values are between 12 and 64 inclusive. + /// This is only used if fastmem_pointer is set. + std::uint32_t fastmem_address_space_bits = 36; + + // Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host). + // Maximum size is limited by the maximum length of a x86_64 / arm64 jump. + std::uint32_t code_cache_size = 128 * 1024 * 1024; // bytes + + /// Determines if we should detect memory accesses via page_table that straddle are + /// misaligned. Accesses that straddle page boundaries will fallback to the relevant + /// memory callback. + /// This value should be the required access sizes this applies to ORed together. + /// To detect any access, use: 8 | 16 | 32 | 64 | 128. + std::uint8_t detect_misaligned_access_via_page_table = 0; + + /// Processor ID + std::uint8_t processor_id = 0; /// This enables unsafe optimizations that reduce emulation accuracy in favour of speed. /// For safety, in order to enable unsafe optimizations you have to set BOTH this flag @@ -177,48 +234,13 @@ struct UserConfig { /// instruction is executed. bool hook_hint_instructions = false; - /// Counter-timer frequency register. The value of the register is not interpreted by - /// dynarmic. - std::uint32_t cntfrq_el0 = 600000000; - - /// CTR_EL0<27:24> is log2 of the cache writeback granule in words. - /// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words. - /// CTR_EL0<19:16> is log2 of the smallest data/unified cacheline in words. - /// CTR_EL0<15:14> is the level 1 instruction cache policy. - /// CTR_EL0<3:0> is log2 of the smallest instruction cacheline in words. - std::uint32_t ctr_el0 = 0x8444c004; - - /// DCZID_EL0<3:0> is log2 of the block size in words - /// DCZID_EL0<4> is 0 if the DC ZVA instruction is permitted. - std::uint32_t dczid_el0 = 4; - - /// Pointer to where TPIDRRO_EL0 is stored. This pointer will be inserted into - /// emitted code. - const std::uint64_t* tpidrro_el0 = nullptr; - - /// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into - /// emitted code. - std::uint64_t* tpidr_el0 = nullptr; - - /// Pointer to the page table which we can use for direct page table access. - /// If an entry in page_table is null, the relevant memory callback will be called. - /// If page_table is nullptr, all memory accesses hit the memory callbacks. - void** page_table = nullptr; - /// Declares how many valid address bits are there in virtual addresses. - /// Determines the size of page_table. Valid values are between 12 and 64 inclusive. - /// This is only used if page_table is not nullptr. - size_t page_table_address_space_bits = 36; - /// Masks out the first N bits in host pointers from the page table. - /// The intention behind this is to allow users of Dynarmic to pack attributes in the - /// same integer and update the pointer attribute pair atomically. - /// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes. - int page_table_pointer_mask_bits = 0; /// Determines what happens if the guest accesses an entry that is off the end of the /// page table. If true, Dynarmic will silently mirror page_table's address space. If /// false, accessing memory outside of page_table bounds will result in a call to the /// relevant memory callback. /// This is only used if page_table is not nullptr. bool silently_mirror_page_table = true; + /// Determines if the pointer in the page_table shall be offseted locally or globally. /// 'false' will access page_table[addr >> bits][addr & mask] /// 'true' will access page_table[addr >> bits][addr] @@ -226,31 +248,17 @@ struct UserConfig { /// So there might be wrongly faulted pages which maps to nullptr. /// This can be avoided by carefully allocating the memory region. bool absolute_offset_page_table = false; - /// Determines if we should detect memory accesses via page_table that straddle are - /// misaligned. Accesses that straddle page boundaries will fallback to the relevant - /// memory callback. - /// This value should be the required access sizes this applies to ORed together. - /// To detect any access, use: 8 | 16 | 32 | 64 | 128. - std::uint8_t detect_misaligned_access_via_page_table = 0; + /// Determines if the above option only triggers when the misalignment straddles a /// page boundary. bool only_detect_misalignment_via_page_table_on_page_boundary = false; - /// Fastmem Pointer - /// This should point to the beginning of a 2^page_table_address_space_bits bytes - /// address space which is in arranged just like what you wish for emulated memory to - /// be. If the host page faults on an address, the JIT will fallback to calling the - /// MemoryRead*/MemoryWrite* callbacks. - std::optional fastmem_pointer = std::nullopt; /// Determines if instructions that pagefault should cause recompilation of that block /// with fastmem disabled. /// Recompiled code will use the page_table if this is available, otherwise memory /// accesses will hit the memory callbacks. bool recompile_on_fastmem_failure = true; - /// Declares how many valid address bits are there in virtual addresses. - /// Determines the size of fastmem arena. Valid values are between 12 and 64 inclusive. - /// This is only used if fastmem_pointer is set. - size_t fastmem_address_space_bits = 36; + /// Determines what happens if the guest accesses an entry that is off the end of the /// fastmem arena. If true, Dynarmic will silently mirror fastmem's address space. If /// false, accessing memory outside of fastmem bounds will result in a call to the @@ -285,12 +293,15 @@ struct UserConfig { /// AddTicks and GetTicksRemaining are never called, and no cycle counting is done. bool enable_cycle_counting = true; - // Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host). - // Maximum size is limited by the maximum length of a x86_64 / arm64 jump. - size_t code_cache_size = 128 * 1024 * 1024; // bytes - /// Internal use only bool very_verbose_debugging_output = false; + + inline bool HasOptimization(OptimizationFlag f) const { + if (!unsafe_optimizations) { + f &= all_safe_optimizations; + } + return (f & optimizations) != no_optimizations; + } }; } // namespace A64 diff --git a/externals/dynarmic/src/dynarmic/ir/ir_emitter.cpp b/externals/dynarmic/src/dynarmic/ir/ir_emitter.cpp index fc4f69b3e0..3734aae4d5 100644 --- a/externals/dynarmic/src/dynarmic/ir/ir_emitter.cpp +++ b/externals/dynarmic/src/dynarmic/ir/ir_emitter.cpp @@ -14,2877 +14,5 @@ namespace Dynarmic::IR { -U1 IREmitter::Imm1(bool imm1) const { - return U1(Value(imm1)); -} - -U8 IREmitter::Imm8(u8 imm8) const { - return U8(Value(imm8)); -} - -U16 IREmitter::Imm16(u16 imm16) const { - return U16(Value(imm16)); -} - -U32 IREmitter::Imm32(u32 imm32) const { - return U32(Value(imm32)); -} - -U64 IREmitter::Imm64(u64 imm64) const { - return U64(Value(imm64)); -} - -void IREmitter::PushRSB(const LocationDescriptor& return_location) { - Inst(Opcode::PushRSB, IR::Value(return_location.Value())); -} - -U64 IREmitter::Pack2x32To1x64(const U32& lo, const U32& hi) { - return Inst(Opcode::Pack2x32To1x64, lo, hi); -} - -U128 IREmitter::Pack2x64To1x128(const U64& lo, const U64& hi) { - return Inst(Opcode::Pack2x64To1x128, lo, hi); -} - -UAny IREmitter::LeastSignificant(size_t bitsize, const U32U64& value) { - switch (bitsize) { - case 8: - return LeastSignificantByte(value); - case 16: - return LeastSignificantHalf(value); - case 32: - if (value.GetType() == Type::U32) { - return value; - } - return LeastSignificantWord(value); - case 64: - ASSERT(value.GetType() == Type::U64); - return value; - } - ASSERT_FALSE("Invalid bitsize"); -} - -U32 IREmitter::LeastSignificantWord(const U64& value) { - return Inst(Opcode::LeastSignificantWord, value); -} - -U16 IREmitter::LeastSignificantHalf(U32U64 value) { - if (value.GetType() == Type::U64) { - value = LeastSignificantWord(value); - } - return Inst(Opcode::LeastSignificantHalf, value); -} - -U8 IREmitter::LeastSignificantByte(U32U64 value) { - if (value.GetType() == Type::U64) { - value = LeastSignificantWord(value); - } - return Inst(Opcode::LeastSignificantByte, value); -} - -ResultAndCarry IREmitter::MostSignificantWord(const U64& value) { - const auto result = Inst(Opcode::MostSignificantWord, value); - const auto carry_out = Inst(Opcode::GetCarryFromOp, result); - return {result, carry_out}; -} - -U1 IREmitter::MostSignificantBit(const U32& value) { - return Inst(Opcode::MostSignificantBit, value); -} - -U1 IREmitter::IsZero(const U32& value) { - return Inst(Opcode::IsZero32, value); -} - -U1 IREmitter::IsZero(const U64& value) { - return Inst(Opcode::IsZero64, value); -} - -U1 IREmitter::IsZero(const U32U64& value) { - if (value.GetType() == Type::U32) { - return Inst(Opcode::IsZero32, value); - } else { - return Inst(Opcode::IsZero64, value); - } -} - -U1 IREmitter::TestBit(const U32U64& value, const U8& bit) { - if (value.GetType() == Type::U32) { - return Inst(Opcode::TestBit, IndeterminateExtendToLong(value), bit); - } else { - return Inst(Opcode::TestBit, value, bit); - } -} - -U32 IREmitter::ConditionalSelect(Cond cond, const U32& a, const U32& b) { - return Inst(Opcode::ConditionalSelect32, Value{cond}, a, b); -} - -U64 IREmitter::ConditionalSelect(Cond cond, const U64& a, const U64& b) { - return Inst(Opcode::ConditionalSelect64, Value{cond}, a, b); -} - -NZCV IREmitter::ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b) { - return Inst(Opcode::ConditionalSelectNZCV, Value{cond}, a, b); -} - -U32U64 IREmitter::ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::ConditionalSelect32, Value{cond}, a, b); - } else { - return Inst(Opcode::ConditionalSelect64, Value{cond}, a, b); - } -} - -U1 IREmitter::GetCFlagFromNZCV(const NZCV& nzcv) { - return Inst(Opcode::GetCFlagFromNZCV, nzcv); -} - -NZCV IREmitter::NZCVFromPackedFlags(const U32& a) { - return Inst(Opcode::NZCVFromPackedFlags, a); -} - -NZCV IREmitter::NZCVFrom(const Value& value) { - return Inst(Opcode::GetNZCVFromOp, value); -} - -ResultAndCarry IREmitter::LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in) { - const auto result = Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, carry_in); - const auto carry_out = Inst(Opcode::GetCarryFromOp, result); - return {result, carry_out}; -} - -ResultAndCarry IREmitter::LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { - const auto result = Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, carry_in); - const auto carry_out = Inst(Opcode::GetCarryFromOp, result); - return {result, carry_out}; -} - -ResultAndCarry IREmitter::ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { - const auto result = Inst(Opcode::ArithmeticShiftRight32, value_in, shift_amount, carry_in); - const auto carry_out = Inst(Opcode::GetCarryFromOp, result); - return {result, carry_out}; -} - -ResultAndCarry IREmitter::RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { - const auto result = Inst(Opcode::RotateRight32, value_in, shift_amount, carry_in); - const auto carry_out = Inst(Opcode::GetCarryFromOp, result); - return {result, carry_out}; -} - -ResultAndCarry IREmitter::RotateRightExtended(const U32& value_in, const U1& carry_in) { - const auto result = Inst(Opcode::RotateRightExtended, value_in, carry_in); - const auto carry_out = Inst(Opcode::GetCarryFromOp, result); - return {result, carry_out}; -} - -U32U64 IREmitter::LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount) { - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, Imm1(0)); - } else { - return Inst(Opcode::LogicalShiftLeft64, value_in, shift_amount); - } -} - -U32U64 IREmitter::LogicalShiftRight(const U32U64& value_in, const U8& shift_amount) { - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, Imm1(0)); - } else { - return Inst(Opcode::LogicalShiftRight64, value_in, shift_amount); - } -} - -U32U64 IREmitter::ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount) { - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::ArithmeticShiftRight32, value_in, shift_amount, Imm1(0)); - } else { - return Inst(Opcode::ArithmeticShiftRight64, value_in, shift_amount); - } -} - -U32U64 IREmitter::RotateRight(const U32U64& value_in, const U8& shift_amount) { - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::RotateRight32, value_in, shift_amount, Imm1(0)); - } else { - return Inst(Opcode::RotateRight64, value_in, shift_amount); - } -} - -U32U64 IREmitter::LogicalShiftLeftMasked(const U32U64& value_in, const U32U64& shift_amount) { - ASSERT(value_in.GetType() == shift_amount.GetType()); - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::LogicalShiftLeftMasked32, value_in, shift_amount); - } else { - return Inst(Opcode::LogicalShiftLeftMasked64, value_in, shift_amount); - } -} - -U32U64 IREmitter::LogicalShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount) { - ASSERT(value_in.GetType() == shift_amount.GetType()); - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::LogicalShiftRightMasked32, value_in, shift_amount); - } else { - return Inst(Opcode::LogicalShiftRightMasked64, value_in, shift_amount); - } -} - -U32U64 IREmitter::ArithmeticShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount) { - ASSERT(value_in.GetType() == shift_amount.GetType()); - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::ArithmeticShiftRightMasked32, value_in, shift_amount); - } else { - return Inst(Opcode::ArithmeticShiftRightMasked64, value_in, shift_amount); - } -} - -U32U64 IREmitter::RotateRightMasked(const U32U64& value_in, const U32U64& shift_amount) { - ASSERT(value_in.GetType() == shift_amount.GetType()); - if (value_in.GetType() == Type::U32) { - return Inst(Opcode::RotateRightMasked32, value_in, shift_amount); - } else { - return Inst(Opcode::RotateRightMasked64, value_in, shift_amount); - } -} - -U32U64 IREmitter::AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::Add32, a, b, carry_in); - } else { - return Inst(Opcode::Add64, a, b, carry_in); - } -} - -U32U64 IREmitter::Add(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::Add32, a, b, Imm1(0)); - } else { - return Inst(Opcode::Add64, a, b, Imm1(0)); - } -} - -U32U64 IREmitter::SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::Sub32, a, b, carry_in); - } else { - return Inst(Opcode::Sub64, a, b, carry_in); - } -} - -U32U64 IREmitter::Sub(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::Sub32, a, b, Imm1(1)); - } else { - return Inst(Opcode::Sub64, a, b, Imm1(1)); - } -} - -U32U64 IREmitter::Mul(const U32U64& a, const U32U64& b) { - if (a.GetType() == Type::U32) { - return Inst(Opcode::Mul32, a, b); - } - - return Inst(Opcode::Mul64, a, b); -} - -U64 IREmitter::UnsignedMultiplyHigh(const U64& a, const U64& b) { - return Inst(Opcode::UnsignedMultiplyHigh64, a, b); -} - -U64 IREmitter::SignedMultiplyHigh(const U64& a, const U64& b) { - return Inst(Opcode::SignedMultiplyHigh64, a, b); -} - -U32U64 IREmitter::UnsignedDiv(const U32U64& a, const U32U64& b) { - if (a.GetType() == Type::U32) { - return Inst(Opcode::UnsignedDiv32, a, b); - } - - return Inst(Opcode::UnsignedDiv64, a, b); -} - -U32U64 IREmitter::SignedDiv(const U32U64& a, const U32U64& b) { - if (a.GetType() == Type::U32) { - return Inst(Opcode::SignedDiv32, a, b); - } - - return Inst(Opcode::SignedDiv64, a, b); -} - -U32U64 IREmitter::And(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::And32, a, b); - } else { - return Inst(Opcode::And64, a, b); - } -} - -U32U64 IREmitter::AndNot(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::AndNot32, a, b); - } else { - return Inst(Opcode::AndNot64, a, b); - } -} - -U32U64 IREmitter::Eor(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::Eor32, a, b); - } else { - return Inst(Opcode::Eor64, a, b); - } -} - -U32U64 IREmitter::Or(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - if (a.GetType() == Type::U32) { - return Inst(Opcode::Or32, a, b); - } else { - return Inst(Opcode::Or64, a, b); - } -} - -U32U64 IREmitter::Not(const U32U64& a) { - if (a.GetType() == Type::U32) { - return Inst(Opcode::Not32, a); - } else { - return Inst(Opcode::Not64, a); - } -} - -U64 IREmitter::SignExtendToLong(const UAny& a) { - switch (a.GetType()) { - case Type::U8: - return Inst(Opcode::SignExtendByteToLong, a); - case Type::U16: - return Inst(Opcode::SignExtendHalfToLong, a); - case Type::U32: - return Inst(Opcode::SignExtendWordToLong, a); - case Type::U64: - return U64(a); - default: - UNREACHABLE(); - } -} - -U32 IREmitter::SignExtendToWord(const UAny& a) { - switch (a.GetType()) { - case Type::U8: - return Inst(Opcode::SignExtendByteToWord, a); - case Type::U16: - return Inst(Opcode::SignExtendHalfToWord, a); - case Type::U32: - return U32(a); - case Type::U64: - return Inst(Opcode::LeastSignificantWord, a); - default: - UNREACHABLE(); - } -} - -U64 IREmitter::SignExtendWordToLong(const U32& a) { - return Inst(Opcode::SignExtendWordToLong, a); -} - -U32 IREmitter::SignExtendHalfToWord(const U16& a) { - return Inst(Opcode::SignExtendHalfToWord, a); -} - -U32 IREmitter::SignExtendByteToWord(const U8& a) { - return Inst(Opcode::SignExtendByteToWord, a); -} - -U64 IREmitter::ZeroExtendToLong(const UAny& a) { - switch (a.GetType()) { - case Type::U8: - return Inst(Opcode::ZeroExtendByteToLong, a); - case Type::U16: - return Inst(Opcode::ZeroExtendHalfToLong, a); - case Type::U32: - return Inst(Opcode::ZeroExtendWordToLong, a); - case Type::U64: - return U64(a); - default: - UNREACHABLE(); - } -} - -U32 IREmitter::ZeroExtendToWord(const UAny& a) { - switch (a.GetType()) { - case Type::U8: - return Inst(Opcode::ZeroExtendByteToWord, a); - case Type::U16: - return Inst(Opcode::ZeroExtendHalfToWord, a); - case Type::U32: - return U32(a); - case Type::U64: - return Inst(Opcode::LeastSignificantWord, a); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::ZeroExtendToQuad(const UAny& a) { - return Inst(Opcode::ZeroExtendLongToQuad, ZeroExtendToLong(a)); -} - -U64 IREmitter::ZeroExtendWordToLong(const U32& a) { - return Inst(Opcode::ZeroExtendWordToLong, a); -} - -U32 IREmitter::ZeroExtendHalfToWord(const U16& a) { - return Inst(Opcode::ZeroExtendHalfToWord, a); -} - -U32 IREmitter::ZeroExtendByteToWord(const U8& a) { - return Inst(Opcode::ZeroExtendByteToWord, a); -} - -U32 IREmitter::IndeterminateExtendToWord(const UAny& a) { - // TODO: Implement properly - return ZeroExtendToWord(a); -} - -U64 IREmitter::IndeterminateExtendToLong(const UAny& a) { - // TODO: Implement properly - return ZeroExtendToLong(a); -} - -U32 IREmitter::ByteReverseWord(const U32& a) { - return Inst(Opcode::ByteReverseWord, a); -} - -U16 IREmitter::ByteReverseHalf(const U16& a) { - return Inst(Opcode::ByteReverseHalf, a); -} - -U64 IREmitter::ByteReverseDual(const U64& a) { - return Inst(Opcode::ByteReverseDual, a); -} - -U32U64 IREmitter::CountLeadingZeros(const U32U64& a) { - if (a.GetType() == IR::Type::U32) { - return Inst(Opcode::CountLeadingZeros32, a); - } - - return Inst(Opcode::CountLeadingZeros64, a); -} - -U32U64 IREmitter::ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb) { - if (a.GetType() == IR::Type::U32) { - return Inst(Opcode::ExtractRegister32, a, b, lsb); - } - - return Inst(Opcode::ExtractRegister64, a, b, lsb); -} - -U32U64 IREmitter::ReplicateBit(const U32U64& a, u8 bit) { - if (a.GetType() == IR::Type::U32) { - ASSERT(bit < 32); - return Inst(Opcode::ReplicateBit32, a, Imm8(bit)); - } - - ASSERT(bit < 64); - return Inst(Opcode::ReplicateBit64, a, Imm8(bit)); -} - -U32U64 IREmitter::MaxSigned(const U32U64& a, const U32U64& b) { - if (a.GetType() == IR::Type::U32) { - return Inst(Opcode::MaxSigned32, a, b); - } - - return Inst(Opcode::MaxSigned64, a, b); -} - -U32U64 IREmitter::MaxUnsigned(const U32U64& a, const U32U64& b) { - if (a.GetType() == IR::Type::U32) { - return Inst(Opcode::MaxUnsigned32, a, b); - } - - return Inst(Opcode::MaxUnsigned64, a, b); -} - -U32U64 IREmitter::MinSigned(const U32U64& a, const U32U64& b) { - if (a.GetType() == IR::Type::U32) { - return Inst(Opcode::MinSigned32, a, b); - } - - return Inst(Opcode::MinSigned64, a, b); -} - -U32U64 IREmitter::MinUnsigned(const U32U64& a, const U32U64& b) { - if (a.GetType() == IR::Type::U32) { - return Inst(Opcode::MinUnsigned32, a, b); - } - - return Inst(Opcode::MinUnsigned64, a, b); -} - -ResultAndOverflow IREmitter::SignedSaturatedAddWithFlag(const U32& a, const U32& b) { - const auto result = Inst(Opcode::SignedSaturatedAddWithFlag32, a, b); - const auto overflow = Inst(Opcode::GetOverflowFromOp, result); - return {result, overflow}; -} - -ResultAndOverflow IREmitter::SignedSaturatedSubWithFlag(const U32& a, const U32& b) { - const auto result = Inst(Opcode::SignedSaturatedSubWithFlag32, a, b); - const auto overflow = Inst(Opcode::GetOverflowFromOp, result); - return {result, overflow}; -} - -ResultAndOverflow IREmitter::SignedSaturation(const U32& a, size_t bit_size_to_saturate_to) { - ASSERT(bit_size_to_saturate_to >= 1 && bit_size_to_saturate_to <= 32); - const auto result = Inst(Opcode::SignedSaturation, a, Imm8(static_cast(bit_size_to_saturate_to))); - const auto overflow = Inst(Opcode::GetOverflowFromOp, result); - return {result, overflow}; -} - -ResultAndOverflow IREmitter::UnsignedSaturation(const U32& a, size_t bit_size_to_saturate_to) { - ASSERT(bit_size_to_saturate_to <= 31); - const auto result = Inst(Opcode::UnsignedSaturation, a, Imm8(static_cast(bit_size_to_saturate_to))); - const auto overflow = Inst(Opcode::GetOverflowFromOp, result); - return {result, overflow}; -} - -UAny IREmitter::SignedSaturatedAdd(const UAny& a, const UAny& b) { - ASSERT(a.GetType() == b.GetType()); - const auto result = [&]() -> IR::UAny { - switch (a.GetType()) { - case IR::Type::U8: - return Inst(Opcode::SignedSaturatedAdd8, a, b); - case IR::Type::U16: - return Inst(Opcode::SignedSaturatedAdd16, a, b); - case IR::Type::U32: - return Inst(Opcode::SignedSaturatedAdd32, a, b); - case IR::Type::U64: - return Inst(Opcode::SignedSaturatedAdd64, a, b); - default: - return IR::UAny{}; - } - }(); - return result; -} - -UAny IREmitter::SignedSaturatedDoublingMultiplyReturnHigh(const UAny& a, const UAny& b) { - ASSERT(a.GetType() == b.GetType()); - const auto result = [&]() -> IR::UAny { - switch (a.GetType()) { - case IR::Type::U16: - return Inst(Opcode::SignedSaturatedDoublingMultiplyReturnHigh16, a, b); - case IR::Type::U32: - return Inst(Opcode::SignedSaturatedDoublingMultiplyReturnHigh32, a, b); - default: - UNREACHABLE(); - } - }(); - return result; -} - -UAny IREmitter::SignedSaturatedSub(const UAny& a, const UAny& b) { - ASSERT(a.GetType() == b.GetType()); - const auto result = [&]() -> IR::UAny { - switch (a.GetType()) { - case IR::Type::U8: - return Inst(Opcode::SignedSaturatedSub8, a, b); - case IR::Type::U16: - return Inst(Opcode::SignedSaturatedSub16, a, b); - case IR::Type::U32: - return Inst(Opcode::SignedSaturatedSub32, a, b); - case IR::Type::U64: - return Inst(Opcode::SignedSaturatedSub64, a, b); - default: - return IR::UAny{}; - } - }(); - return result; -} - -UAny IREmitter::UnsignedSaturatedAdd(const UAny& a, const UAny& b) { - ASSERT(a.GetType() == b.GetType()); - const auto result = [&]() -> IR::UAny { - switch (a.GetType()) { - case IR::Type::U8: - return Inst(Opcode::UnsignedSaturatedAdd8, a, b); - case IR::Type::U16: - return Inst(Opcode::UnsignedSaturatedAdd16, a, b); - case IR::Type::U32: - return Inst(Opcode::UnsignedSaturatedAdd32, a, b); - case IR::Type::U64: - return Inst(Opcode::UnsignedSaturatedAdd64, a, b); - default: - return IR::UAny{}; - } - }(); - return result; -} - -UAny IREmitter::UnsignedSaturatedSub(const UAny& a, const UAny& b) { - ASSERT(a.GetType() == b.GetType()); - const auto result = [&]() -> IR::UAny { - switch (a.GetType()) { - case IR::Type::U8: - return Inst(Opcode::UnsignedSaturatedSub8, a, b); - case IR::Type::U16: - return Inst(Opcode::UnsignedSaturatedSub16, a, b); - case IR::Type::U32: - return Inst(Opcode::UnsignedSaturatedSub32, a, b); - case IR::Type::U64: - return Inst(Opcode::UnsignedSaturatedSub64, a, b); - default: - return IR::UAny{}; - } - }(); - return result; -} - -U128 IREmitter::VectorSignedSaturatedAdd(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedAdd8, a, b); - case 16: - return Inst(Opcode::VectorSignedSaturatedAdd16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedAdd32, a, b); - case 64: - return Inst(Opcode::VectorSignedSaturatedAdd64, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorSignedSaturatedSub(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedSub8, a, b); - case 16: - return Inst(Opcode::VectorSignedSaturatedSub16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedSub32, a, b); - case 64: - return Inst(Opcode::VectorSignedSaturatedSub64, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorUnsignedSaturatedAdd(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorUnsignedSaturatedAdd8, a, b); - case 16: - return Inst(Opcode::VectorUnsignedSaturatedAdd16, a, b); - case 32: - return Inst(Opcode::VectorUnsignedSaturatedAdd32, a, b); - case 64: - return Inst(Opcode::VectorUnsignedSaturatedAdd64, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorUnsignedSaturatedSub(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorUnsignedSaturatedSub8, a, b); - case 16: - return Inst(Opcode::VectorUnsignedSaturatedSub16, a, b); - case 32: - return Inst(Opcode::VectorUnsignedSaturatedSub32, a, b); - case 64: - return Inst(Opcode::VectorUnsignedSaturatedSub64, a, b); - default: - UNREACHABLE(); - } -} - -ResultAndGE IREmitter::PackedAddU8(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedAddU8, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedAddS8(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedAddS8, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedAddU16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedAddU16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedAddS16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedAddS16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedSubU8(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedSubU8, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedSubS8(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedSubS8, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedSubU16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedSubU16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedSubS16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedSubS16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedAddSubU16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedAddSubU16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedAddSubS16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedAddSubS16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedSubAddU16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedSubAddU16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -ResultAndGE IREmitter::PackedSubAddS16(const U32& a, const U32& b) { - const auto result = Inst(Opcode::PackedSubAddS16, a, b); - const auto ge = Inst(Opcode::GetGEFromOp, result); - return {result, ge}; -} - -U32 IREmitter::PackedHalvingAddU8(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingAddU8, a, b); -} - -U32 IREmitter::PackedHalvingAddS8(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingAddS8, a, b); -} - -U32 IREmitter::PackedHalvingSubU8(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingSubU8, a, b); -} - -U32 IREmitter::PackedHalvingSubS8(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingSubS8, a, b); -} - -U32 IREmitter::PackedHalvingAddU16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingAddU16, a, b); -} - -U32 IREmitter::PackedHalvingAddS16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingAddS16, a, b); -} - -U32 IREmitter::PackedHalvingSubU16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingSubU16, a, b); -} - -U32 IREmitter::PackedHalvingSubS16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingSubS16, a, b); -} - -U32 IREmitter::PackedHalvingAddSubU16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingAddSubU16, a, b); -} - -U32 IREmitter::PackedHalvingAddSubS16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingAddSubS16, a, b); -} - -U32 IREmitter::PackedHalvingSubAddU16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingSubAddU16, a, b); -} - -U32 IREmitter::PackedHalvingSubAddS16(const U32& a, const U32& b) { - return Inst(Opcode::PackedHalvingSubAddS16, a, b); -} - -U32 IREmitter::PackedSaturatedAddU8(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedAddU8, a, b); -} - -U32 IREmitter::PackedSaturatedAddS8(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedAddS8, a, b); -} - -U32 IREmitter::PackedSaturatedSubU8(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedSubU8, a, b); -} - -U32 IREmitter::PackedSaturatedSubS8(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedSubS8, a, b); -} - -U32 IREmitter::PackedSaturatedAddU16(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedAddU16, a, b); -} - -U32 IREmitter::PackedSaturatedAddS16(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedAddS16, a, b); -} - -U32 IREmitter::PackedSaturatedSubU16(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedSubU16, a, b); -} - -U32 IREmitter::PackedSaturatedSubS16(const U32& a, const U32& b) { - return Inst(Opcode::PackedSaturatedSubS16, a, b); -} - -U32 IREmitter::PackedAbsDiffSumU8(const U32& a, const U32& b) { - return Inst(Opcode::PackedAbsDiffSumU8, a, b); -} - -U32 IREmitter::PackedSelect(const U32& ge, const U32& a, const U32& b) { - return Inst(Opcode::PackedSelect, ge, a, b); -} - -U32 IREmitter::CRC32Castagnoli8(const U32& a, const U32& b) { - return Inst(Opcode::CRC32Castagnoli8, a, b); -} - -U32 IREmitter::CRC32Castagnoli16(const U32& a, const U32& b) { - return Inst(Opcode::CRC32Castagnoli16, a, b); -} - -U32 IREmitter::CRC32Castagnoli32(const U32& a, const U32& b) { - return Inst(Opcode::CRC32Castagnoli32, a, b); -} - -U32 IREmitter::CRC32Castagnoli64(const U32& a, const U64& b) { - return Inst(Opcode::CRC32Castagnoli64, a, b); -} - -U32 IREmitter::CRC32ISO8(const U32& a, const U32& b) { - return Inst(Opcode::CRC32ISO8, a, b); -} - -U32 IREmitter::CRC32ISO16(const U32& a, const U32& b) { - return Inst(Opcode::CRC32ISO16, a, b); -} - -U32 IREmitter::CRC32ISO32(const U32& a, const U32& b) { - return Inst(Opcode::CRC32ISO32, a, b); -} - -U32 IREmitter::CRC32ISO64(const U32& a, const U64& b) { - return Inst(Opcode::CRC32ISO64, a, b); -} - -U128 IREmitter::AESDecryptSingleRound(const U128& a) { - return Inst(Opcode::AESDecryptSingleRound, a); -} - -U128 IREmitter::AESEncryptSingleRound(const U128& a) { - return Inst(Opcode::AESEncryptSingleRound, a); -} - -U128 IREmitter::AESInverseMixColumns(const U128& a) { - return Inst(Opcode::AESInverseMixColumns, a); -} - -U128 IREmitter::AESMixColumns(const U128& a) { - return Inst(Opcode::AESMixColumns, a); -} - -U8 IREmitter::SM4AccessSubstitutionBox(const U8& a) { - return Inst(Opcode::SM4AccessSubstitutionBox, a); -} - -U128 IREmitter::SHA256Hash(const U128& x, const U128& y, const U128& w, bool part1) { - return Inst(Opcode::SHA256Hash, x, y, w, Imm1(part1)); -} - -U128 IREmitter::SHA256MessageSchedule0(const U128& x, const U128& y) { - return Inst(Opcode::SHA256MessageSchedule0, x, y); -} - -U128 IREmitter::SHA256MessageSchedule1(const U128& x, const U128& y, const U128& z) { - return Inst(Opcode::SHA256MessageSchedule1, x, y, z); -} - -UAny IREmitter::VectorGetElement(size_t esize, const U128& a, size_t index) { - ASSERT_MSG(esize * index < 128, "Invalid index"); - switch (esize) { - case 8: - return Inst(Opcode::VectorGetElement8, a, Imm8(static_cast(index))); - case 16: - return Inst(Opcode::VectorGetElement16, a, Imm8(static_cast(index))); - case 32: - return Inst(Opcode::VectorGetElement32, a, Imm8(static_cast(index))); - case 64: - return Inst(Opcode::VectorGetElement64, a, Imm8(static_cast(index))); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorSetElement(size_t esize, const U128& a, size_t index, const IR::UAny& elem) { - ASSERT_MSG(esize * index < 128, "Invalid index"); - switch (esize) { - case 8: - return Inst(Opcode::VectorSetElement8, a, Imm8(static_cast(index)), elem); - case 16: - return Inst(Opcode::VectorSetElement16, a, Imm8(static_cast(index)), elem); - case 32: - return Inst(Opcode::VectorSetElement32, a, Imm8(static_cast(index)), elem); - case 64: - return Inst(Opcode::VectorSetElement64, a, Imm8(static_cast(index)), elem); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorAbs(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorAbs8, a); - case 16: - return Inst(Opcode::VectorAbs16, a); - case 32: - return Inst(Opcode::VectorAbs32, a); - case 64: - return Inst(Opcode::VectorAbs64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorAdd(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorAdd8, a, b); - case 16: - return Inst(Opcode::VectorAdd16, a, b); - case 32: - return Inst(Opcode::VectorAdd32, a, b); - case 64: - return Inst(Opcode::VectorAdd64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorAnd(const U128& a, const U128& b) { - return Inst(Opcode::VectorAnd, a, b); -} - -U128 IREmitter::VectorAndNot(const U128& a, const U128& b) { - return Inst(Opcode::VectorAndNot, a, b); -} - -U128 IREmitter::VectorArithmeticShiftRight(size_t esize, const U128& a, u8 shift_amount) { - switch (esize) { - case 8: - return Inst(Opcode::VectorArithmeticShiftRight8, a, Imm8(shift_amount)); - case 16: - return Inst(Opcode::VectorArithmeticShiftRight16, a, Imm8(shift_amount)); - case 32: - return Inst(Opcode::VectorArithmeticShiftRight32, a, Imm8(shift_amount)); - case 64: - return Inst(Opcode::VectorArithmeticShiftRight64, a, Imm8(shift_amount)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorArithmeticVShift(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorArithmeticVShift8, a, b); - case 16: - return Inst(Opcode::VectorArithmeticVShift16, a, b); - case 32: - return Inst(Opcode::VectorArithmeticVShift32, a, b); - case 64: - return Inst(Opcode::VectorArithmeticVShift64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorBroadcastLower(size_t esize, const UAny& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorBroadcastLower8, U8(a)); - case 16: - return Inst(Opcode::VectorBroadcastLower16, U16(a)); - case 32: - return Inst(Opcode::VectorBroadcastLower32, U32(a)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorBroadcast(size_t esize, const UAny& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorBroadcast8, U8(a)); - case 16: - return Inst(Opcode::VectorBroadcast16, U16(a)); - case 32: - return Inst(Opcode::VectorBroadcast32, U32(a)); - case 64: - return Inst(Opcode::VectorBroadcast64, U64(a)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorBroadcastElementLower(size_t esize, const U128& a, size_t index) { - ASSERT_MSG(esize * index < 128, "Invalid index"); - switch (esize) { - case 8: - return Inst(Opcode::VectorBroadcastElementLower8, a, u8(index)); - case 16: - return Inst(Opcode::VectorBroadcastElementLower16, a, u8(index)); - case 32: - return Inst(Opcode::VectorBroadcastElementLower32, a, u8(index)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorBroadcastElement(size_t esize, const U128& a, size_t index) { - ASSERT_MSG(esize * index < 128, "Invalid index"); - switch (esize) { - case 8: - return Inst(Opcode::VectorBroadcastElement8, a, u8(index)); - case 16: - return Inst(Opcode::VectorBroadcastElement16, a, u8(index)); - case 32: - return Inst(Opcode::VectorBroadcastElement32, a, u8(index)); - case 64: - return Inst(Opcode::VectorBroadcastElement64, a, u8(index)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorCountLeadingZeros(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorCountLeadingZeros8, a); - case 16: - return Inst(Opcode::VectorCountLeadingZeros16, a); - case 32: - return Inst(Opcode::VectorCountLeadingZeros32, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorDeinterleaveEven(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorDeinterleaveEven8, a, b); - case 16: - return Inst(Opcode::VectorDeinterleaveEven16, a, b); - case 32: - return Inst(Opcode::VectorDeinterleaveEven32, a, b); - case 64: - return Inst(Opcode::VectorDeinterleaveEven64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorDeinterleaveOdd(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorDeinterleaveOdd8, a, b); - case 16: - return Inst(Opcode::VectorDeinterleaveOdd16, a, b); - case 32: - return Inst(Opcode::VectorDeinterleaveOdd32, a, b); - case 64: - return Inst(Opcode::VectorDeinterleaveOdd64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorDeinterleaveEvenLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorDeinterleaveEvenLower8, a, b); - case 16: - return Inst(Opcode::VectorDeinterleaveEvenLower16, a, b); - case 32: - return Inst(Opcode::VectorDeinterleaveEvenLower32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorDeinterleaveOddLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorDeinterleaveOddLower8, a, b); - case 16: - return Inst(Opcode::VectorDeinterleaveOddLower16, a, b); - case 32: - return Inst(Opcode::VectorDeinterleaveOddLower32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorEor(const U128& a, const U128& b) { - return Inst(Opcode::VectorEor, a, b); -} - -U128 IREmitter::VectorEqual(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorEqual8, a, b); - case 16: - return Inst(Opcode::VectorEqual16, a, b); - case 32: - return Inst(Opcode::VectorEqual32, a, b); - case 64: - return Inst(Opcode::VectorEqual64, a, b); - case 128: - return Inst(Opcode::VectorEqual128, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorExtract(const U128& a, const U128& b, size_t position) { - ASSERT(position <= 128); - return Inst(Opcode::VectorExtract, a, b, Imm8(static_cast(position))); -} - -U128 IREmitter::VectorExtractLower(const U128& a, const U128& b, size_t position) { - ASSERT(position <= 64); - return Inst(Opcode::VectorExtractLower, a, b, Imm8(static_cast(position))); -} - -U128 IREmitter::VectorGreaterSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorGreaterS8, a, b); - case 16: - return Inst(Opcode::VectorGreaterS16, a, b); - case 32: - return Inst(Opcode::VectorGreaterS32, a, b); - case 64: - return Inst(Opcode::VectorGreaterS64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorGreaterEqualSigned(size_t esize, const U128& a, const U128& b) { - return VectorOr(VectorGreaterSigned(esize, a, b), VectorEqual(esize, a, b)); -} - -U128 IREmitter::VectorGreaterEqualUnsigned(size_t esize, const U128& a, const U128& b) { - return VectorEqual(esize, VectorMaxUnsigned(esize, a, b), a); -} - -U128 IREmitter::VectorGreaterUnsigned(size_t esize, const U128& a, const U128& b) { - return VectorNot(VectorEqual(esize, VectorMinUnsigned(esize, a, b), a)); -} - -U128 IREmitter::VectorHalvingAddSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorHalvingAddS8, a, b); - case 16: - return Inst(Opcode::VectorHalvingAddS16, a, b); - case 32: - return Inst(Opcode::VectorHalvingAddS32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorHalvingAddUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorHalvingAddU8, a, b); - case 16: - return Inst(Opcode::VectorHalvingAddU16, a, b); - case 32: - return Inst(Opcode::VectorHalvingAddU32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorHalvingSubSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorHalvingSubS8, a, b); - case 16: - return Inst(Opcode::VectorHalvingSubS16, a, b); - case 32: - return Inst(Opcode::VectorHalvingSubS32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorHalvingSubUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorHalvingSubU8, a, b); - case 16: - return Inst(Opcode::VectorHalvingSubU16, a, b); - case 32: - return Inst(Opcode::VectorHalvingSubU32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorInterleaveLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorInterleaveLower8, a, b); - case 16: - return Inst(Opcode::VectorInterleaveLower16, a, b); - case 32: - return Inst(Opcode::VectorInterleaveLower32, a, b); - case 64: - return Inst(Opcode::VectorInterleaveLower64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorInterleaveUpper(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorInterleaveUpper8, a, b); - case 16: - return Inst(Opcode::VectorInterleaveUpper16, a, b); - case 32: - return Inst(Opcode::VectorInterleaveUpper32, a, b); - case 64: - return Inst(Opcode::VectorInterleaveUpper64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorLessEqualSigned(size_t esize, const U128& a, const U128& b) { - return VectorNot(VectorGreaterSigned(esize, a, b)); -} - -U128 IREmitter::VectorLessEqualUnsigned(size_t esize, const U128& a, const U128& b) { - return VectorEqual(esize, VectorMinUnsigned(esize, a, b), a); -} - -U128 IREmitter::VectorLessSigned(size_t esize, const U128& a, const U128& b) { - return VectorNot(VectorOr(VectorGreaterSigned(esize, a, b), VectorEqual(esize, a, b))); -} - -U128 IREmitter::VectorLessUnsigned(size_t esize, const U128& a, const U128& b) { - return VectorNot(VectorEqual(esize, VectorMaxUnsigned(esize, a, b), a)); -} - -U128 IREmitter::VectorLogicalShiftLeft(size_t esize, const U128& a, u8 shift_amount) { - switch (esize) { - case 8: - return Inst(Opcode::VectorLogicalShiftLeft8, a, Imm8(shift_amount)); - case 16: - return Inst(Opcode::VectorLogicalShiftLeft16, a, Imm8(shift_amount)); - case 32: - return Inst(Opcode::VectorLogicalShiftLeft32, a, Imm8(shift_amount)); - case 64: - return Inst(Opcode::VectorLogicalShiftLeft64, a, Imm8(shift_amount)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorLogicalShiftRight(size_t esize, const U128& a, u8 shift_amount) { - switch (esize) { - case 8: - return Inst(Opcode::VectorLogicalShiftRight8, a, Imm8(shift_amount)); - case 16: - return Inst(Opcode::VectorLogicalShiftRight16, a, Imm8(shift_amount)); - case 32: - return Inst(Opcode::VectorLogicalShiftRight32, a, Imm8(shift_amount)); - case 64: - return Inst(Opcode::VectorLogicalShiftRight64, a, Imm8(shift_amount)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorLogicalVShift(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorLogicalVShift8, a, b); - case 16: - return Inst(Opcode::VectorLogicalVShift16, a, b); - case 32: - return Inst(Opcode::VectorLogicalVShift32, a, b); - case 64: - return Inst(Opcode::VectorLogicalVShift64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMaxSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMaxS8, a, b); - case 16: - return Inst(Opcode::VectorMaxS16, a, b); - case 32: - return Inst(Opcode::VectorMaxS32, a, b); - case 64: - return Inst(Opcode::VectorMaxS64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMaxUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMaxU8, a, b); - case 16: - return Inst(Opcode::VectorMaxU16, a, b); - case 32: - return Inst(Opcode::VectorMaxU32, a, b); - case 64: - return Inst(Opcode::VectorMaxU64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMinSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMinS8, a, b); - case 16: - return Inst(Opcode::VectorMinS16, a, b); - case 32: - return Inst(Opcode::VectorMinS32, a, b); - case 64: - return Inst(Opcode::VectorMinS64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMinUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMinU8, a, b); - case 16: - return Inst(Opcode::VectorMinU16, a, b); - case 32: - return Inst(Opcode::VectorMinU32, a, b); - case 64: - return Inst(Opcode::VectorMinU64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMultiply(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMultiply8, a, b); - case 16: - return Inst(Opcode::VectorMultiply16, a, b); - case 32: - return Inst(Opcode::VectorMultiply32, a, b); - case 64: - return Inst(Opcode::VectorMultiply64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMultiplySignedWiden(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMultiplySignedWiden8, a, b); - case 16: - return Inst(Opcode::VectorMultiplySignedWiden16, a, b); - case 32: - return Inst(Opcode::VectorMultiplySignedWiden32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorMultiplyUnsignedWiden(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorMultiplyUnsignedWiden8, a, b); - case 16: - return Inst(Opcode::VectorMultiplyUnsignedWiden16, a, b); - case 32: - return Inst(Opcode::VectorMultiplyUnsignedWiden32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorNarrow(size_t original_esize, const U128& a) { - switch (original_esize) { - case 16: - return Inst(Opcode::VectorNarrow16, a); - case 32: - return Inst(Opcode::VectorNarrow32, a); - case 64: - return Inst(Opcode::VectorNarrow64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorNot(const U128& a) { - return Inst(Opcode::VectorNot, a); -} - -U128 IREmitter::VectorOr(const U128& a, const U128& b) { - return Inst(Opcode::VectorOr, a, b); -} - -U128 IREmitter::VectorPairedAdd(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedAdd8, a, b); - case 16: - return Inst(Opcode::VectorPairedAdd16, a, b); - case 32: - return Inst(Opcode::VectorPairedAdd32, a, b); - case 64: - return Inst(Opcode::VectorPairedAdd64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorPairedAddLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedAddLower8, a, b); - case 16: - return Inst(Opcode::VectorPairedAddLower16, a, b); - case 32: - return Inst(Opcode::VectorPairedAddLower32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorPairedAddSignedWiden(size_t original_esize, const U128& a) { - switch (original_esize) { - case 8: - return Inst(Opcode::VectorPairedAddSignedWiden8, a); - case 16: - return Inst(Opcode::VectorPairedAddSignedWiden16, a); - case 32: - return Inst(Opcode::VectorPairedAddSignedWiden32, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorPairedAddUnsignedWiden(size_t original_esize, const U128& a) { - switch (original_esize) { - case 8: - return Inst(Opcode::VectorPairedAddUnsignedWiden8, a); - case 16: - return Inst(Opcode::VectorPairedAddUnsignedWiden16, a); - case 32: - return Inst(Opcode::VectorPairedAddUnsignedWiden32, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorPairedMaxSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMaxS8, a, b); - case 16: - return Inst(Opcode::VectorPairedMaxS16, a, b); - case 32: - return Inst(Opcode::VectorPairedMaxS32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMaxUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMaxU8, a, b); - case 16: - return Inst(Opcode::VectorPairedMaxU16, a, b); - case 32: - return Inst(Opcode::VectorPairedMaxU32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMinSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMinS8, a, b); - case 16: - return Inst(Opcode::VectorPairedMinS16, a, b); - case 32: - return Inst(Opcode::VectorPairedMinS32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMinUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMinU8, a, b); - case 16: - return Inst(Opcode::VectorPairedMinU16, a, b); - case 32: - return Inst(Opcode::VectorPairedMinU32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMaxSignedLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMaxLowerS8, a, b); - case 16: - return Inst(Opcode::VectorPairedMaxLowerS16, a, b); - case 32: - return Inst(Opcode::VectorPairedMaxLowerS32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMaxUnsignedLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMaxLowerU8, a, b); - case 16: - return Inst(Opcode::VectorPairedMaxLowerU16, a, b); - case 32: - return Inst(Opcode::VectorPairedMaxLowerU32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMinSignedLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMinLowerS8, a, b); - case 16: - return Inst(Opcode::VectorPairedMinLowerS16, a, b); - case 32: - return Inst(Opcode::VectorPairedMinLowerS32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPairedMinUnsignedLower(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPairedMinLowerU8, a, b); - case 16: - return Inst(Opcode::VectorPairedMinLowerU16, a, b); - case 32: - return Inst(Opcode::VectorPairedMinLowerU32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPolynomialMultiply(const U128& a, const U128& b) { - return Inst(Opcode::VectorPolynomialMultiply8, a, b); -} - -U128 IREmitter::VectorPolynomialMultiplyLong(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorPolynomialMultiplyLong8, a, b); - case 64: - return Inst(Opcode::VectorPolynomialMultiplyLong64, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorPopulationCount(const U128& a) { - return Inst(Opcode::VectorPopulationCount, a); -} - -U128 IREmitter::VectorReverseBits(const U128& a) { - return Inst(Opcode::VectorReverseBits, a); -} - -U128 IREmitter::VectorReverseElementsInHalfGroups(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorReverseElementsInHalfGroups8, a); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorReverseElementsInWordGroups(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorReverseElementsInWordGroups8, a); - case 16: - return Inst(Opcode::VectorReverseElementsInWordGroups16, a); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorReverseElementsInLongGroups(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorReverseElementsInLongGroups8, a); - case 16: - return Inst(Opcode::VectorReverseElementsInLongGroups16, a); - case 32: - return Inst(Opcode::VectorReverseElementsInLongGroups32, a); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorReduceAdd(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorReduceAdd8, a); - case 16: - return Inst(Opcode::VectorReduceAdd16, a); - case 32: - return Inst(Opcode::VectorReduceAdd32, a); - case 64: - return Inst(Opcode::VectorReduceAdd64, a); - } - - UNREACHABLE(); -} - -U128 IREmitter::VectorRotateLeft(size_t esize, const U128& a, u8 amount) { - ASSERT(amount < esize); - - if (amount == 0) { - return a; - } - - return VectorOr(VectorLogicalShiftLeft(esize, a, amount), - VectorLogicalShiftRight(esize, a, static_cast(esize - amount))); -} - -U128 IREmitter::VectorRotateRight(size_t esize, const U128& a, u8 amount) { - ASSERT(amount < esize); - - if (amount == 0) { - return a; - } - - return VectorOr(VectorLogicalShiftRight(esize, a, amount), - VectorLogicalShiftLeft(esize, a, static_cast(esize - amount))); -} - -U128 IREmitter::VectorRotateWholeVectorRight(const U128& a, u8 amount) { - ASSERT(amount % 32 == 0); - return Inst(Opcode::VectorRotateWholeVectorRight, a, Imm8(amount)); -} - -U128 IREmitter::VectorRoundingHalvingAddSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorRoundingHalvingAddS8, a, b); - case 16: - return Inst(Opcode::VectorRoundingHalvingAddS16, a, b); - case 32: - return Inst(Opcode::VectorRoundingHalvingAddS32, a, b); - } - - UNREACHABLE(); -} - -U128 IREmitter::VectorRoundingHalvingAddUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorRoundingHalvingAddU8, a, b); - case 16: - return Inst(Opcode::VectorRoundingHalvingAddU16, a, b); - case 32: - return Inst(Opcode::VectorRoundingHalvingAddU32, a, b); - } - - UNREACHABLE(); -} - -U128 IREmitter::VectorRoundingShiftLeftSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorRoundingShiftLeftS8, a, b); - case 16: - return Inst(Opcode::VectorRoundingShiftLeftS16, a, b); - case 32: - return Inst(Opcode::VectorRoundingShiftLeftS32, a, b); - case 64: - return Inst(Opcode::VectorRoundingShiftLeftS64, a, b); - } - - UNREACHABLE(); -} - -U128 IREmitter::VectorRoundingShiftLeftUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorRoundingShiftLeftU8, a, b); - case 16: - return Inst(Opcode::VectorRoundingShiftLeftU16, a, b); - case 32: - return Inst(Opcode::VectorRoundingShiftLeftU32, a, b); - case 64: - return Inst(Opcode::VectorRoundingShiftLeftU64, a, b); - } - - UNREACHABLE(); -} - -U128 IREmitter::VectorSignExtend(size_t original_esize, const U128& a) { - switch (original_esize) { - case 8: - return Inst(Opcode::VectorSignExtend8, a); - case 16: - return Inst(Opcode::VectorSignExtend16, a); - case 32: - return Inst(Opcode::VectorSignExtend32, a); - case 64: - return Inst(Opcode::VectorSignExtend64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedAbsoluteDifference(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedAbsoluteDifference8, a, b); - case 16: - return Inst(Opcode::VectorSignedAbsoluteDifference16, a, b); - case 32: - return Inst(Opcode::VectorSignedAbsoluteDifference32, a, b); - } - UNREACHABLE(); -} - -UpperAndLower IREmitter::VectorSignedMultiply(size_t esize, const U128& a, const U128& b) { - const Value multiply = [&] { - switch (esize) { - case 16: - return Inst(Opcode::VectorSignedMultiply16, a, b); - case 32: - return Inst(Opcode::VectorSignedMultiply32, a, b); - } - UNREACHABLE(); - }(); - - return { - Inst(Opcode::GetUpperFromOp, multiply), - Inst(Opcode::GetLowerFromOp, multiply), - }; -} - -U128 IREmitter::VectorSignedSaturatedAbs(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedAbs8, a); - case 16: - return Inst(Opcode::VectorSignedSaturatedAbs16, a); - case 32: - return Inst(Opcode::VectorSignedSaturatedAbs32, a); - case 64: - return Inst(Opcode::VectorSignedSaturatedAbs64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedAccumulateUnsigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned8, a, b); - case 16: - return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned32, a, b); - case 64: - return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedDoublingMultiplyHigh(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 16: - return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHigh16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHigh32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorSignedSaturatedDoublingMultiplyHighRounding(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 16: - return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHighRounding16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHighRounding32, a, b); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::VectorSignedSaturatedDoublingMultiplyLong(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 16: - return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyLong16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyLong32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedNarrowToSigned(size_t original_esize, const U128& a) { - switch (original_esize) { - case 16: - return Inst(Opcode::VectorSignedSaturatedNarrowToSigned16, a); - case 32: - return Inst(Opcode::VectorSignedSaturatedNarrowToSigned32, a); - case 64: - return Inst(Opcode::VectorSignedSaturatedNarrowToSigned64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedNarrowToUnsigned(size_t original_esize, const U128& a) { - switch (original_esize) { - case 16: - return Inst(Opcode::VectorSignedSaturatedNarrowToUnsigned16, a); - case 32: - return Inst(Opcode::VectorSignedSaturatedNarrowToUnsigned32, a); - case 64: - return Inst(Opcode::VectorSignedSaturatedNarrowToUnsigned64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedNeg(size_t esize, const U128& a) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedNeg8, a); - case 16: - return Inst(Opcode::VectorSignedSaturatedNeg16, a); - case 32: - return Inst(Opcode::VectorSignedSaturatedNeg32, a); - case 64: - return Inst(Opcode::VectorSignedSaturatedNeg64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedShiftLeft8, a, b); - case 16: - return Inst(Opcode::VectorSignedSaturatedShiftLeft16, a, b); - case 32: - return Inst(Opcode::VectorSignedSaturatedShiftLeft32, a, b); - case 64: - return Inst(Opcode::VectorSignedSaturatedShiftLeft64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSignedSaturatedShiftLeftUnsigned(size_t esize, const U128& a, u8 shift_amount) { - ASSERT(shift_amount < esize); - switch (esize) { - case 8: - return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned8, a, Imm8(shift_amount)); - case 16: - return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned16, a, Imm8(shift_amount)); - case 32: - return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned32, a, Imm8(shift_amount)); - case 64: - return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned64, a, Imm8(shift_amount)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorSub(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorSub8, a, b); - case 16: - return Inst(Opcode::VectorSub16, a, b); - case 32: - return Inst(Opcode::VectorSub32, a, b); - case 64: - return Inst(Opcode::VectorSub64, a, b); - } - UNREACHABLE(); -} - -Table IREmitter::VectorTable(std::vector values) { - ASSERT(values.size() >= 1 && values.size() <= 4); - values.resize(4); - return Inst(Opcode::VectorTable, values[0], values[1], values[2], values[3]); -} - -Table IREmitter::VectorTable(std::vector values) { - ASSERT(values.size() >= 1 && values.size() <= 4); - values.resize(4); - return Inst
(Opcode::VectorTable, values[0], values[1], values[2], values[3]); -} - -U64 IREmitter::VectorTableLookup(const U64& defaults, const Table& table, const U64& indices) { - ASSERT(table.GetInst()->GetArg(0).GetType() == Type::U64); - return Inst(Opcode::VectorTableLookup64, defaults, table, indices); -} - -U128 IREmitter::VectorTableLookup(const U128& defaults, const Table& table, const U128& indices) { - ASSERT(table.GetInst()->GetArg(0).GetType() == Type::U128); - return Inst(Opcode::VectorTableLookup128, defaults, table, indices); -} - -U128 IREmitter::VectorTranspose(size_t esize, const U128& a, const U128& b, bool part) { - switch (esize) { - case 8: - return Inst(Opcode::VectorTranspose8, a, b, Imm1(part)); - case 16: - return Inst(Opcode::VectorTranspose16, a, b, Imm1(part)); - case 32: - return Inst(Opcode::VectorTranspose32, a, b, Imm1(part)); - case 64: - return Inst(Opcode::VectorTranspose64, a, b, Imm1(part)); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorUnsignedAbsoluteDifference(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorUnsignedAbsoluteDifference8, a, b); - case 16: - return Inst(Opcode::VectorUnsignedAbsoluteDifference16, a, b); - case 32: - return Inst(Opcode::VectorUnsignedAbsoluteDifference32, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorUnsignedRecipEstimate(const U128& a) { - return Inst(Opcode::VectorUnsignedRecipEstimate, a); -} - -U128 IREmitter::VectorUnsignedRecipSqrtEstimate(const U128& a) { - return Inst(Opcode::VectorUnsignedRecipSqrtEstimate, a); -} - -U128 IREmitter::VectorUnsignedSaturatedAccumulateSigned(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned8, a, b); - case 16: - return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned16, a, b); - case 32: - return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned32, a, b); - case 64: - return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorUnsignedSaturatedNarrow(size_t esize, const U128& a) { - switch (esize) { - case 16: - return Inst(Opcode::VectorUnsignedSaturatedNarrow16, a); - case 32: - return Inst(Opcode::VectorUnsignedSaturatedNarrow32, a); - case 64: - return Inst(Opcode::VectorUnsignedSaturatedNarrow64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorUnsignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b) { - switch (esize) { - case 8: - return Inst(Opcode::VectorUnsignedSaturatedShiftLeft8, a, b); - case 16: - return Inst(Opcode::VectorUnsignedSaturatedShiftLeft16, a, b); - case 32: - return Inst(Opcode::VectorUnsignedSaturatedShiftLeft32, a, b); - case 64: - return Inst(Opcode::VectorUnsignedSaturatedShiftLeft64, a, b); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorZeroExtend(size_t original_esize, const U128& a) { - switch (original_esize) { - case 8: - return Inst(Opcode::VectorZeroExtend8, a); - case 16: - return Inst(Opcode::VectorZeroExtend16, a); - case 32: - return Inst(Opcode::VectorZeroExtend32, a); - case 64: - return Inst(Opcode::VectorZeroExtend64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::VectorZeroUpper(const U128& a) { - return Inst(Opcode::VectorZeroUpper, a); -} - -U128 IREmitter::ZeroVector() { - return Inst(Opcode::ZeroVector); -} - -U16U32U64 IREmitter::FPAbs(const U16U32U64& a) { - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPAbs16, a); - case Type::U32: - return Inst(Opcode::FPAbs32, a); - case Type::U64: - return Inst(Opcode::FPAbs64, a); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPAdd(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPAdd32, a, b); - case Type::U64: - return Inst(Opcode::FPAdd64, a, b); - default: - UNREACHABLE(); - } -} - -NZCV IREmitter::FPCompare(const U32U64& a, const U32U64& b, bool exc_on_qnan) { - ASSERT(a.GetType() == b.GetType()); - - const IR::U1 exc_on_qnan_imm = Imm1(exc_on_qnan); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPCompare32, a, b, exc_on_qnan_imm); - case Type::U64: - return Inst(Opcode::FPCompare64, a, b, exc_on_qnan_imm); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPDiv(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPDiv32, a, b); - case Type::U64: - return Inst(Opcode::FPDiv64, a, b); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPMax(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPMax32, a, b); - case Type::U64: - return Inst(Opcode::FPMax64, a, b); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPMaxNumeric(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPMaxNumeric32, a, b); - case Type::U64: - return Inst(Opcode::FPMaxNumeric64, a, b); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPMin(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPMin32, a, b); - case Type::U64: - return Inst(Opcode::FPMin64, a, b); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPMinNumeric(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPMinNumeric32, a, b); - case Type::U64: - return Inst(Opcode::FPMinNumeric64, a, b); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPMul(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPMul32, a, b); - case Type::U64: - return Inst(Opcode::FPMul64, a, b); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPMulAdd(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPMulAdd16, a, b, c); - case Type::U32: - return Inst(Opcode::FPMulAdd32, a, b, c); - case Type::U64: - return Inst(Opcode::FPMulAdd64, a, b, c); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPMulSub(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPMulSub16, a, b, c); - case Type::U32: - return Inst(Opcode::FPMulSub32, a, b, c); - case Type::U64: - return Inst(Opcode::FPMulSub64, a, b, c); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPMulX(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPMulX32, a, b); - case Type::U64: - return Inst(Opcode::FPMulX64, a, b); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPNeg(const U16U32U64& a) { - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPNeg16, a); - case Type::U32: - return Inst(Opcode::FPNeg32, a); - case Type::U64: - return Inst(Opcode::FPNeg64, a); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPRecipEstimate(const U16U32U64& a) { - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPRecipEstimate16, a); - case Type::U32: - return Inst(Opcode::FPRecipEstimate32, a); - case Type::U64: - return Inst(Opcode::FPRecipEstimate64, a); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPRecipExponent(const U16U32U64& a) { - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPRecipExponent16, a); - case Type::U32: - return Inst(Opcode::FPRecipExponent32, a); - case Type::U64: - return Inst(Opcode::FPRecipExponent64, a); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPRecipStepFused(const U16U32U64& a, const U16U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPRecipStepFused16, a, b); - case Type::U32: - return Inst(Opcode::FPRecipStepFused32, a, b); - case Type::U64: - return Inst(Opcode::FPRecipStepFused64, a, b); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPRoundInt(const U16U32U64& a, FP::RoundingMode rounding, bool exact) { - const u8 rounding_value = static_cast(rounding); - const IR::U1 exact_imm = Imm1(exact); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPRoundInt16, a, rounding_value, exact_imm); - case Type::U32: - return Inst(Opcode::FPRoundInt32, a, rounding_value, exact_imm); - case Type::U64: - return Inst(Opcode::FPRoundInt64, a, rounding_value, exact_imm); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPRSqrtEstimate(const U16U32U64& a) { - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPRSqrtEstimate16, a); - case Type::U32: - return Inst(Opcode::FPRSqrtEstimate32, a); - case Type::U64: - return Inst(Opcode::FPRSqrtEstimate64, a); - default: - UNREACHABLE(); - } -} - -U16U32U64 IREmitter::FPRSqrtStepFused(const U16U32U64& a, const U16U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPRSqrtStepFused16, a, b); - case Type::U32: - return Inst(Opcode::FPRSqrtStepFused32, a, b); - case Type::U64: - return Inst(Opcode::FPRSqrtStepFused64, a, b); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPSqrt(const U32U64& a) { - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPSqrt32, a); - case Type::U64: - return Inst(Opcode::FPSqrt64, a); - default: - UNREACHABLE(); - } -} - -U32U64 IREmitter::FPSub(const U32U64& a, const U32U64& b) { - ASSERT(a.GetType() == b.GetType()); - - switch (a.GetType()) { - case Type::U32: - return Inst(Opcode::FPSub32, a, b); - case Type::U64: - return Inst(Opcode::FPSub64, a, b); - default: - UNREACHABLE(); - } -} - -U16 IREmitter::FPDoubleToHalf(const U64& a, FP::RoundingMode rounding) { - return Inst(Opcode::FPDoubleToHalf, a, Imm8(static_cast(rounding))); -} - -U32 IREmitter::FPDoubleToSingle(const U64& a, FP::RoundingMode rounding) { - return Inst(Opcode::FPDoubleToSingle, a, Imm8(static_cast(rounding))); -} - -U64 IREmitter::FPHalfToDouble(const U16& a, FP::RoundingMode rounding) { - return Inst(Opcode::FPHalfToDouble, a, Imm8(static_cast(rounding))); -} - -U32 IREmitter::FPHalfToSingle(const U16& a, FP::RoundingMode rounding) { - return Inst(Opcode::FPHalfToSingle, a, Imm8(static_cast(rounding))); -} - -U64 IREmitter::FPSingleToDouble(const U32& a, FP::RoundingMode rounding) { - return Inst(Opcode::FPSingleToDouble, a, Imm8(static_cast(rounding))); -} - -U16 IREmitter::FPSingleToHalf(const U32& a, FP::RoundingMode rounding) { - return Inst(Opcode::FPSingleToHalf, a, Imm8(static_cast(rounding))); -} - -U16 IREmitter::FPToFixedS16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= 16); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPHalfToFixedS16, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPSingleToFixedS16, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPDoubleToFixedS16, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U32 IREmitter::FPToFixedS32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= 32); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPHalfToFixedS32, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPSingleToFixedS32, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPDoubleToFixedS32, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U64 IREmitter::FPToFixedS64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= 64); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPHalfToFixedS64, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPSingleToFixedS64, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPDoubleToFixedS64, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U16 IREmitter::FPToFixedU16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= 16); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPHalfToFixedU16, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPSingleToFixedU16, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPDoubleToFixedU16, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U32 IREmitter::FPToFixedU32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= 32); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPHalfToFixedU32, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPSingleToFixedU32, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPDoubleToFixedU32, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U64 IREmitter::FPToFixedU64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= 64); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPHalfToFixedU64, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPSingleToFixedU64, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPDoubleToFixedU64, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U32 IREmitter::FPSignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); - - const IR::U8 fbits_imm = Imm8(static_cast(fbits)); - const IR::U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPFixedS16ToSingle, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPFixedS32ToSingle, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPFixedS64ToSingle, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U32 IREmitter::FPUnsignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); - - const IR::U8 fbits_imm = Imm8(static_cast(fbits)); - const IR::U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPFixedU16ToSingle, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPFixedU32ToSingle, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPFixedU64ToSingle, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U64 IREmitter::FPSignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); - - const IR::U8 fbits_imm = Imm8(static_cast(fbits)); - const IR::U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPFixedS16ToDouble, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPFixedS32ToDouble, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPFixedS64ToDouble, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U64 IREmitter::FPUnsignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { - ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); - - const IR::U8 fbits_imm = Imm8(static_cast(fbits)); - const IR::U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (a.GetType()) { - case Type::U16: - return Inst(Opcode::FPFixedU16ToDouble, a, fbits_imm, rounding_imm); - case Type::U32: - return Inst(Opcode::FPFixedU32ToDouble, a, fbits_imm, rounding_imm); - case Type::U64: - return Inst(Opcode::FPFixedU64ToDouble, a, fbits_imm, rounding_imm); - default: - UNREACHABLE(); - } -} - -U128 IREmitter::FPVectorAbs(size_t esize, const U128& a) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorAbs16, a); - case 32: - return Inst(Opcode::FPVectorAbs32, a); - case 64: - return Inst(Opcode::FPVectorAbs64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorAdd32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorAdd64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorDiv(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorDiv32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorDiv64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorEqual16, a, b, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorEqual32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorEqual64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorFromHalf(size_t esize, const U128& a, FP::RoundingMode rounding, bool fpcr_controlled) { - ASSERT(esize == 32); - return Inst(Opcode::FPVectorFromHalf32, a, Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); -} - -U128 IREmitter::FPVectorFromSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled) { - ASSERT(fbits <= esize); - switch (esize) { - case 32: - return Inst(Opcode::FPVectorFromSignedFixed32, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorFromSignedFixed64, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorFromUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled) { - ASSERT(fbits <= esize); - switch (esize) { - case 32: - return Inst(Opcode::FPVectorFromUnsignedFixed32, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorFromUnsignedFixed64, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorGreater(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorGreater32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorGreater64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorGreaterEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorGreaterEqual32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorGreaterEqual64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMax(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorMax32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMax64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMaxNumeric(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorMaxNumeric32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMaxNumeric64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMin(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorMin32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMin64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMinNumeric(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorMinNumeric32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMinNumeric64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMul(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorMul32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMul64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMulAdd(size_t esize, const U128& a, const U128& b, const U128& c, bool fpcr_controlled) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorMulAdd16, a, b, c, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorMulAdd32, a, b, c, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMulAdd64, a, b, c, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorMulX(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorMulX32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorMulX64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorNeg(size_t esize, const U128& a) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorNeg16, a); - case 32: - return Inst(Opcode::FPVectorNeg32, a); - case 64: - return Inst(Opcode::FPVectorNeg64, a); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorPairedAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorPairedAdd32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorPairedAdd64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorPairedAddLower(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorPairedAddLower32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorPairedAddLower64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorRecipEstimate(size_t esize, const U128& a, bool fpcr_controlled) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorRecipEstimate16, a, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorRecipEstimate32, a, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorRecipEstimate64, a, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorRecipStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorRecipStepFused16, a, b, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorRecipStepFused32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorRecipStepFused64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorRoundInt(size_t esize, const U128& operand, FP::RoundingMode rounding, bool exact, bool fpcr_controlled) { - const IR::U8 rounding_imm = Imm8(static_cast(rounding)); - const IR::U1 exact_imm = Imm1(exact); - - switch (esize) { - case 16: - return Inst(Opcode::FPVectorRoundInt16, operand, rounding_imm, exact_imm, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorRoundInt32, operand, rounding_imm, exact_imm, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorRoundInt64, operand, rounding_imm, exact_imm, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorRSqrtEstimate(size_t esize, const U128& a, bool fpcr_controlled) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorRSqrtEstimate16, a, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorRSqrtEstimate32, a, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorRSqrtEstimate64, a, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorRSqrtStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 16: - return Inst(Opcode::FPVectorRSqrtStepFused16, a, b, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorRSqrtStepFused32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorRSqrtStepFused64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorSqrt(size_t esize, const U128& a, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorSqrt32, a, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorSqrt64, a, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorSub(size_t esize, const U128& a, const U128& b, bool fpcr_controlled) { - switch (esize) { - case 32: - return Inst(Opcode::FPVectorSub32, a, b, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorSub64, a, b, Imm1(fpcr_controlled)); - } - UNREACHABLE(); -} - -U128 IREmitter::FPVectorToHalf(size_t esize, const U128& a, FP::RoundingMode rounding, bool fpcr_controlled) { - ASSERT(esize == 32); - return Inst(Opcode::FPVectorToHalf32, a, Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); -} - -U128 IREmitter::FPVectorToSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled) { - ASSERT(fbits <= esize); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (esize) { - case 16: - return Inst(Opcode::FPVectorToSignedFixed16, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorToSignedFixed32, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorToSignedFixed64, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); - } - - UNREACHABLE(); -} - -U128 IREmitter::FPVectorToUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled) { - ASSERT(fbits <= esize); - - const U8 fbits_imm = Imm8(static_cast(fbits)); - const U8 rounding_imm = Imm8(static_cast(rounding)); - - switch (esize) { - case 16: - return Inst(Opcode::FPVectorToUnsignedFixed16, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); - case 32: - return Inst(Opcode::FPVectorToUnsignedFixed32, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); - case 64: - return Inst(Opcode::FPVectorToUnsignedFixed64, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); - } - - UNREACHABLE(); -} - -void IREmitter::Breakpoint() { - Inst(Opcode::Breakpoint); -} - -void IREmitter::CallHostFunction(void (*fn)(void)) { - Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), Value{}, Value{}, Value{}); -} - -void IREmitter::CallHostFunction(void (*fn)(u64), const U64& arg1) { - Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), arg1, Value{}, Value{}); -} - -void IREmitter::CallHostFunction(void (*fn)(u64, u64), const U64& arg1, const U64& arg2) { - Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), arg1, arg2, Value{}); -} - -void IREmitter::CallHostFunction(void (*fn)(u64, u64, u64), const U64& arg1, const U64& arg2, const U64& arg3) { - Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), arg1, arg2, arg3); -} - -void IREmitter::SetTerm(const Terminal& terminal) { - block.SetTerminal(terminal); -} } // namespace Dynarmic::IR diff --git a/externals/dynarmic/src/dynarmic/ir/ir_emitter.h b/externals/dynarmic/src/dynarmic/ir/ir_emitter.h index d37df24572..23cfb47498 100644 --- a/externals/dynarmic/src/dynarmic/ir/ir_emitter.h +++ b/externals/dynarmic/src/dynarmic/ir/ir_emitter.h @@ -5,8 +5,13 @@ #pragma once -#include +#include +#include +#include +#include + +#include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/acc_type.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/location_descriptor.h" @@ -69,337 +74,2878 @@ public: Block& block; - U1 Imm1(bool value) const; - U8 Imm8(u8 value) const; - U16 Imm16(u16 value) const; - U32 Imm32(u32 value) const; - U64 Imm64(u64 value) const; + U1 Imm1(bool imm1) const { + return U1(Value(imm1)); + } - void PushRSB(const LocationDescriptor& return_location); + U8 Imm8(u8 imm8) const { + return U8(Value(imm8)); + } - U64 Pack2x32To1x64(const U32& lo, const U32& hi); - U128 Pack2x64To1x128(const U64& lo, const U64& hi); - UAny LeastSignificant(size_t bitsize, const U32U64& value); - U32 LeastSignificantWord(const U64& value); - U16 LeastSignificantHalf(U32U64 value); - U8 LeastSignificantByte(U32U64 value); - ResultAndCarry MostSignificantWord(const U64& value); - U1 MostSignificantBit(const U32& value); - U1 IsZero(const U32& value); - U1 IsZero(const U64& value); - U1 IsZero(const U32U64& value); - U1 TestBit(const U32U64& value, const U8& bit); - U32 ConditionalSelect(Cond cond, const U32& a, const U32& b); - U64 ConditionalSelect(Cond cond, const U64& a, const U64& b); - NZCV ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b); - U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b); + U16 Imm16(u16 imm16) const { + return U16(Value(imm16)); + } - U1 GetCFlagFromNZCV(const NZCV& nzcv); - NZCV NZCVFromPackedFlags(const U32& a); - // This pseudo-instruction may only be added to instructions that support it. - NZCV NZCVFrom(const Value& value); + U32 Imm32(u32 imm32) const { + return U32(Value(imm32)); + } - ResultAndCarry LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in); - ResultAndCarry LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in); - ResultAndCarry ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in); - ResultAndCarry RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in); - U32U64 LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount); - U32U64 LogicalShiftRight(const U32U64& value_in, const U8& shift_amount); - U32U64 ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount); - U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount); - U32U64 LogicalShiftLeftMasked(const U32U64& value_in, const U32U64& shift_amount); - U32U64 LogicalShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount); - U32U64 ArithmeticShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount); - U32U64 RotateRightMasked(const U32U64& value_in, const U32U64& shift_amount); - ResultAndCarry RotateRightExtended(const U32& value_in, const U1& carry_in); - U32U64 AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in); - U32U64 SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in); - U32U64 Add(const U32U64& a, const U32U64& b); - U32U64 Sub(const U32U64& a, const U32U64& b); - U32U64 Mul(const U32U64& a, const U32U64& b); - U64 UnsignedMultiplyHigh(const U64& a, const U64& b); - U64 SignedMultiplyHigh(const U64& a, const U64& b); - U32U64 UnsignedDiv(const U32U64& a, const U32U64& b); - U32U64 SignedDiv(const U32U64& a, const U32U64& b); - U32U64 And(const U32U64& a, const U32U64& b); - U32U64 AndNot(const U32U64& a, const U32U64& b); - U32U64 Eor(const U32U64& a, const U32U64& b); - U32U64 Or(const U32U64& a, const U32U64& b); - U32U64 Not(const U32U64& a); - U32 SignExtendToWord(const UAny& a); - U64 SignExtendToLong(const UAny& a); - U32 SignExtendByteToWord(const U8& a); - U32 SignExtendHalfToWord(const U16& a); - U64 SignExtendWordToLong(const U32& a); - U32 ZeroExtendToWord(const UAny& a); - U64 ZeroExtendToLong(const UAny& a); - U128 ZeroExtendToQuad(const UAny& a); - U32 ZeroExtendByteToWord(const U8& a); - U32 ZeroExtendHalfToWord(const U16& a); - U64 ZeroExtendWordToLong(const U32& a); - U32 IndeterminateExtendToWord(const UAny& a); - U64 IndeterminateExtendToLong(const UAny& a); - U32 ByteReverseWord(const U32& a); - U16 ByteReverseHalf(const U16& a); - U64 ByteReverseDual(const U64& a); - U32U64 CountLeadingZeros(const U32U64& a); - U32U64 ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb); - U32U64 ReplicateBit(const U32U64& a, u8 bit); - U32U64 MaxSigned(const U32U64& a, const U32U64& b); - U32U64 MaxUnsigned(const U32U64& a, const U32U64& b); - U32U64 MinSigned(const U32U64& a, const U32U64& b); - U32U64 MinUnsigned(const U32U64& a, const U32U64& b); + U64 Imm64(u64 imm64) const { + return U64(Value(imm64)); + } - ResultAndOverflow SignedSaturatedAddWithFlag(const U32& a, const U32& b); - ResultAndOverflow SignedSaturatedSubWithFlag(const U32& a, const U32& b); - ResultAndOverflow SignedSaturation(const U32& a, size_t bit_size_to_saturate_to); - ResultAndOverflow UnsignedSaturation(const U32& a, size_t bit_size_to_saturate_to); + void PushRSB(const LocationDescriptor& return_location) { + Inst(Opcode::PushRSB, IR::Value(return_location.Value())); + } - UAny SignedSaturatedAdd(const UAny& a, const UAny& b); - UAny SignedSaturatedDoublingMultiplyReturnHigh(const UAny& a, const UAny& b); - UAny SignedSaturatedSub(const UAny& a, const UAny& b); - UAny UnsignedSaturatedAdd(const UAny& a, const UAny& b); - UAny UnsignedSaturatedSub(const UAny& a, const UAny& b); + U64 Pack2x32To1x64(const U32& lo, const U32& hi) { + return Inst(Opcode::Pack2x32To1x64, lo, hi); + } - U128 VectorSignedSaturatedAdd(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedSub(size_t esize, const U128& a, const U128& b); - U128 VectorUnsignedSaturatedAdd(size_t esize, const U128& a, const U128& b); - U128 VectorUnsignedSaturatedSub(size_t esize, const U128& a, const U128& b); + U128 Pack2x64To1x128(const U64& lo, const U64& hi) { + return Inst(Opcode::Pack2x64To1x128, lo, hi); + } - ResultAndGE PackedAddU8(const U32& a, const U32& b); - ResultAndGE PackedAddS8(const U32& a, const U32& b); - ResultAndGE PackedAddU16(const U32& a, const U32& b); - ResultAndGE PackedAddS16(const U32& a, const U32& b); - ResultAndGE PackedSubU8(const U32& a, const U32& b); - ResultAndGE PackedSubS8(const U32& a, const U32& b); - ResultAndGE PackedSubU16(const U32& a, const U32& b); - ResultAndGE PackedSubS16(const U32& a, const U32& b); - ResultAndGE PackedAddSubU16(const U32& a, const U32& b); - ResultAndGE PackedAddSubS16(const U32& a, const U32& b); - ResultAndGE PackedSubAddU16(const U32& a, const U32& b); - ResultAndGE PackedSubAddS16(const U32& a, const U32& b); - U32 PackedHalvingAddU8(const U32& a, const U32& b); - U32 PackedHalvingAddS8(const U32& a, const U32& b); - U32 PackedHalvingSubU8(const U32& a, const U32& b); - U32 PackedHalvingSubS8(const U32& a, const U32& b); - U32 PackedHalvingAddU16(const U32& a, const U32& b); - U32 PackedHalvingAddS16(const U32& a, const U32& b); - U32 PackedHalvingSubU16(const U32& a, const U32& b); - U32 PackedHalvingSubS16(const U32& a, const U32& b); - U32 PackedHalvingAddSubU16(const U32& a, const U32& b); - U32 PackedHalvingAddSubS16(const U32& a, const U32& b); - U32 PackedHalvingSubAddU16(const U32& a, const U32& b); - U32 PackedHalvingSubAddS16(const U32& a, const U32& b); - U32 PackedSaturatedAddU8(const U32& a, const U32& b); - U32 PackedSaturatedAddS8(const U32& a, const U32& b); - U32 PackedSaturatedSubU8(const U32& a, const U32& b); - U32 PackedSaturatedSubS8(const U32& a, const U32& b); - U32 PackedSaturatedAddU16(const U32& a, const U32& b); - U32 PackedSaturatedAddS16(const U32& a, const U32& b); - U32 PackedSaturatedSubU16(const U32& a, const U32& b); - U32 PackedSaturatedSubS16(const U32& a, const U32& b); - U32 PackedAbsDiffSumU8(const U32& a, const U32& b); - U32 PackedSelect(const U32& ge, const U32& a, const U32& b); + UAny LeastSignificant(size_t bitsize, const U32U64& value) { + switch (bitsize) { + case 8: + return LeastSignificantByte(value); + case 16: + return LeastSignificantHalf(value); + case 32: + if (value.GetType() == Type::U32) { + return value; + } + return LeastSignificantWord(value); + case 64: + ASSERT(value.GetType() == Type::U64); + return value; + } + ASSERT_FALSE("Invalid bitsize"); + } - U32 CRC32Castagnoli8(const U32& a, const U32& b); - U32 CRC32Castagnoli16(const U32& a, const U32& b); - U32 CRC32Castagnoli32(const U32& a, const U32& b); - U32 CRC32Castagnoli64(const U32& a, const U64& b); - U32 CRC32ISO8(const U32& a, const U32& b); - U32 CRC32ISO16(const U32& a, const U32& b); - U32 CRC32ISO32(const U32& a, const U32& b); - U32 CRC32ISO64(const U32& a, const U64& b); + U32 LeastSignificantWord(const U64& value) { + return Inst(Opcode::LeastSignificantWord, value); + } - U128 AESDecryptSingleRound(const U128& a); - U128 AESEncryptSingleRound(const U128& a); - U128 AESInverseMixColumns(const U128& a); - U128 AESMixColumns(const U128& a); + U16 LeastSignificantHalf(U32U64 value) { + if (value.GetType() == Type::U64) { + value = LeastSignificantWord(value); + } + return Inst(Opcode::LeastSignificantHalf, value); + } - U8 SM4AccessSubstitutionBox(const U8& a); + U8 LeastSignificantByte(U32U64 value) { + if (value.GetType() == Type::U64) { + value = LeastSignificantWord(value); + } + return Inst(Opcode::LeastSignificantByte, value); + } - U128 SHA256Hash(const U128& x, const U128& y, const U128& w, bool part1); - U128 SHA256MessageSchedule0(const U128& x, const U128& y); - U128 SHA256MessageSchedule1(const U128& x, const U128& y, const U128& z); + ResultAndCarry MostSignificantWord(const U64& value) { + const auto result = Inst(Opcode::MostSignificantWord, value); + const auto carry_out = Inst(Opcode::GetCarryFromOp, result); + return {result, carry_out}; + } - UAny VectorGetElement(size_t esize, const U128& a, size_t index); - U128 VectorSetElement(size_t esize, const U128& a, size_t index, const UAny& elem); - U128 VectorAbs(size_t esize, const U128& a); - U128 VectorAdd(size_t esize, const U128& a, const U128& b); - U128 VectorAnd(const U128& a, const U128& b); - U128 VectorAndNot(const U128& a, const U128& b); - U128 VectorArithmeticShiftRight(size_t esize, const U128& a, u8 shift_amount); - U128 VectorArithmeticVShift(size_t esize, const U128& a, const U128& b); - U128 VectorBroadcast(size_t esize, const UAny& a); - U128 VectorBroadcastLower(size_t esize, const UAny& a); - U128 VectorBroadcastElement(size_t esize, const U128& a, size_t index); - U128 VectorBroadcastElementLower(size_t esize, const U128& a, size_t index); - U128 VectorCountLeadingZeros(size_t esize, const U128& a); - U128 VectorEor(const U128& a, const U128& b); - U128 VectorDeinterleaveEven(size_t esize, const U128& a, const U128& b); - U128 VectorDeinterleaveEvenLower(size_t esize, const U128& a, const U128& b); - U128 VectorDeinterleaveOdd(size_t esize, const U128& a, const U128& b); - U128 VectorDeinterleaveOddLower(size_t esize, const U128& a, const U128& b); - U128 VectorEqual(size_t esize, const U128& a, const U128& b); - U128 VectorExtract(const U128& a, const U128& b, size_t position); - U128 VectorExtractLower(const U128& a, const U128& b, size_t position); - U128 VectorGreaterEqualSigned(size_t esize, const U128& a, const U128& b); - U128 VectorGreaterEqualUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorGreaterSigned(size_t esize, const U128& a, const U128& b); - U128 VectorGreaterUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorHalvingAddSigned(size_t esize, const U128& a, const U128& b); - U128 VectorHalvingAddUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorHalvingSubSigned(size_t esize, const U128& a, const U128& b); - U128 VectorHalvingSubUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorInterleaveLower(size_t esize, const U128& a, const U128& b); - U128 VectorInterleaveUpper(size_t esize, const U128& a, const U128& b); - U128 VectorLessEqualSigned(size_t esize, const U128& a, const U128& b); - U128 VectorLessEqualUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorLessSigned(size_t esize, const U128& a, const U128& b); - U128 VectorLessUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorLogicalShiftLeft(size_t esize, const U128& a, u8 shift_amount); - U128 VectorLogicalShiftRight(size_t esize, const U128& a, u8 shift_amount); - U128 VectorLogicalVShift(size_t esize, const U128& a, const U128& b); - U128 VectorMaxSigned(size_t esize, const U128& a, const U128& b); - U128 VectorMaxUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorMinSigned(size_t esize, const U128& a, const U128& b); - U128 VectorMinUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorMultiply(size_t esize, const U128& a, const U128& b); - U128 VectorMultiplySignedWiden(size_t esize, const U128& a, const U128& b); - U128 VectorMultiplyUnsignedWiden(size_t esize, const U128& a, const U128& b); - U128 VectorNarrow(size_t original_esize, const U128& a); - U128 VectorNot(const U128& a); - U128 VectorOr(const U128& a, const U128& b); - U128 VectorPairedAdd(size_t esize, const U128& a, const U128& b); - U128 VectorPairedAddLower(size_t esize, const U128& a, const U128& b); - U128 VectorPairedAddSignedWiden(size_t original_esize, const U128& a); - U128 VectorPairedAddUnsignedWiden(size_t original_esize, const U128& a); - U128 VectorPairedMaxSigned(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMaxUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMinSigned(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMinUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMaxSignedLower(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMaxUnsignedLower(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMinSignedLower(size_t esize, const U128& a, const U128& b); - U128 VectorPairedMinUnsignedLower(size_t esize, const U128& a, const U128& b); - U128 VectorPolynomialMultiply(const U128& a, const U128& b); - U128 VectorPolynomialMultiplyLong(size_t esize, const U128& a, const U128& b); - U128 VectorPopulationCount(const U128& a); - U128 VectorReverseBits(const U128& a); - U128 VectorReverseElementsInHalfGroups(size_t esize, const U128& a); - U128 VectorReverseElementsInWordGroups(size_t esize, const U128& a); - U128 VectorReverseElementsInLongGroups(size_t esize, const U128& a); - U128 VectorReduceAdd(size_t esize, const U128& a); - U128 VectorRotateLeft(size_t esize, const U128& a, u8 amount); - U128 VectorRotateRight(size_t esize, const U128& a, u8 amount); - U128 VectorRotateWholeVectorRight(const U128& a, u8 amount); - U128 VectorRoundingHalvingAddSigned(size_t esize, const U128& a, const U128& b); - U128 VectorRoundingHalvingAddUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorRoundingShiftLeftSigned(size_t esize, const U128& a, const U128& b); - U128 VectorRoundingShiftLeftUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorSignExtend(size_t original_esize, const U128& a); - U128 VectorSignedAbsoluteDifference(size_t esize, const U128& a, const U128& b); - UpperAndLower VectorSignedMultiply(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedAbs(size_t esize, const U128& a); - U128 VectorSignedSaturatedAccumulateUnsigned(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedDoublingMultiplyHigh(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedDoublingMultiplyHighRounding(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedDoublingMultiplyLong(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedNarrowToSigned(size_t original_esize, const U128& a); - U128 VectorSignedSaturatedNarrowToUnsigned(size_t original_esize, const U128& a); - U128 VectorSignedSaturatedNeg(size_t esize, const U128& a); - U128 VectorSignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b); - U128 VectorSignedSaturatedShiftLeftUnsigned(size_t esize, const U128& a, u8 shift_amount); - U128 VectorSub(size_t esize, const U128& a, const U128& b); - Table VectorTable(std::vector values); - Table VectorTable(std::vector values); - U64 VectorTableLookup(const U64& defaults, const Table& table, const U64& indices); - U128 VectorTableLookup(const U128& defaults, const Table& table, const U128& indices); - U128 VectorTranspose(size_t esize, const U128& a, const U128& b, bool part); - U128 VectorUnsignedAbsoluteDifference(size_t esize, const U128& a, const U128& b); - U128 VectorUnsignedRecipEstimate(const U128& a); - U128 VectorUnsignedRecipSqrtEstimate(const U128& a); - U128 VectorUnsignedSaturatedAccumulateSigned(size_t esize, const U128& a, const U128& b); - U128 VectorUnsignedSaturatedNarrow(size_t esize, const U128& a); - U128 VectorUnsignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b); - U128 VectorZeroExtend(size_t original_esize, const U128& a); - U128 VectorZeroUpper(const U128& a); - U128 ZeroVector(); + U1 MostSignificantBit(const U32& value) { + return Inst(Opcode::MostSignificantBit, value); + } - U16U32U64 FPAbs(const U16U32U64& a); - U32U64 FPAdd(const U32U64& a, const U32U64& b); - NZCV FPCompare(const U32U64& a, const U32U64& b, bool exc_on_qnan); - U32U64 FPDiv(const U32U64& a, const U32U64& b); - U32U64 FPMax(const U32U64& a, const U32U64& b); - U32U64 FPMaxNumeric(const U32U64& a, const U32U64& b); - U32U64 FPMin(const U32U64& a, const U32U64& b); - U32U64 FPMinNumeric(const U32U64& a, const U32U64& b); - U32U64 FPMul(const U32U64& a, const U32U64& b); - U16U32U64 FPMulAdd(const U16U32U64& addend, const U16U32U64& op1, const U16U32U64& op2); - U16U32U64 FPMulSub(const U16U32U64& minuend, const U16U32U64& op1, const U16U32U64& op2); - U32U64 FPMulX(const U32U64& a, const U32U64& b); - U16U32U64 FPNeg(const U16U32U64& a); - U16U32U64 FPRecipEstimate(const U16U32U64& a); - U16U32U64 FPRecipExponent(const U16U32U64& a); - U16U32U64 FPRecipStepFused(const U16U32U64& a, const U16U32U64& b); - U16U32U64 FPRoundInt(const U16U32U64& a, FP::RoundingMode rounding, bool exact); - U16U32U64 FPRSqrtEstimate(const U16U32U64& a); - U16U32U64 FPRSqrtStepFused(const U16U32U64& a, const U16U32U64& b); - U32U64 FPSqrt(const U32U64& a); - U32U64 FPSub(const U32U64& a, const U32U64& b); - U16 FPDoubleToHalf(const U64& a, FP::RoundingMode rounding); - U32 FPDoubleToSingle(const U64& a, FP::RoundingMode rounding); - U64 FPHalfToDouble(const U16& a, FP::RoundingMode rounding); - U32 FPHalfToSingle(const U16& a, FP::RoundingMode rounding); - U16 FPSingleToHalf(const U32& a, FP::RoundingMode rounding); - U64 FPSingleToDouble(const U32& a, FP::RoundingMode rounding); - U16 FPToFixedS16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U32 FPToFixedS32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U64 FPToFixedS64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U16 FPToFixedU16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U32 FPToFixedU32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U64 FPToFixedU64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U32 FPSignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U32 FPUnsignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U64 FPSignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); - U64 FPUnsignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding); + U1 IsZero(const U32& value) { + return Inst(Opcode::IsZero32, value); + } - U128 FPVectorAbs(size_t esize, const U128& a); - U128 FPVectorAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorDiv(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorFromHalf(size_t esize, const U128& a, FP::RoundingMode rounding, bool fpcr_controlled = true); - U128 FPVectorFromSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true); - U128 FPVectorFromUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true); - U128 FPVectorGreater(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorGreaterEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorMax(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorMaxNumeric(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorMin(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorMinNumeric(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorMul(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorMulAdd(size_t esize, const U128& addend, const U128& op1, const U128& op2, bool fpcr_controlled = true); - U128 FPVectorMulX(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorNeg(size_t esize, const U128& a); - U128 FPVectorPairedAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorPairedAddLower(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorRecipEstimate(size_t esize, const U128& a, bool fpcr_controlled = true); - U128 FPVectorRecipStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorRoundInt(size_t esize, const U128& operand, FP::RoundingMode rounding, bool exact, bool fpcr_controlled = true); - U128 FPVectorRSqrtEstimate(size_t esize, const U128& a, bool fpcr_controlled = true); - U128 FPVectorRSqrtStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorSqrt(size_t esize, const U128& a, bool fpcr_controlled = true); - U128 FPVectorSub(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true); - U128 FPVectorToHalf(size_t esize, const U128& a, FP::RoundingMode rounding, bool fpcr_controlled = true); - U128 FPVectorToSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true); - U128 FPVectorToUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true); + U1 IsZero(const U64& value) { + return Inst(Opcode::IsZero64, value); + } - void Breakpoint(); - void CallHostFunction(void (*fn)(void)); - void CallHostFunction(void (*fn)(u64), const U64& arg1); - void CallHostFunction(void (*fn)(u64, u64), const U64& arg1, const U64& arg2); - void CallHostFunction(void (*fn)(u64, u64, u64), const U64& arg1, const U64& arg2, const U64& arg3); + U1 IsZero(const U32U64& value) { + if (value.GetType() == Type::U32) { + return Inst(Opcode::IsZero32, value); + } else { + return Inst(Opcode::IsZero64, value); + } + } - void SetTerm(const Terminal& terminal); + U1 TestBit(const U32U64& value, const U8& bit) { + if (value.GetType() == Type::U32) { + return Inst(Opcode::TestBit, IndeterminateExtendToLong(value), bit); + } else { + return Inst(Opcode::TestBit, value, bit); + } + } + + U32 ConditionalSelect(Cond cond, const U32& a, const U32& b) { + return Inst(Opcode::ConditionalSelect32, Value{cond}, a, b); + } + + U64 ConditionalSelect(Cond cond, const U64& a, const U64& b) { + return Inst(Opcode::ConditionalSelect64, Value{cond}, a, b); + } + + NZCV ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b) { + return Inst(Opcode::ConditionalSelectNZCV, Value{cond}, a, b); + } + + U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::ConditionalSelect32, Value{cond}, a, b); + } else { + return Inst(Opcode::ConditionalSelect64, Value{cond}, a, b); + } + } + + U1 GetCFlagFromNZCV(const NZCV& nzcv) { + return Inst(Opcode::GetCFlagFromNZCV, nzcv); + } + + NZCV NZCVFromPackedFlags(const U32& a) { + return Inst(Opcode::NZCVFromPackedFlags, a); + } + + NZCV NZCVFrom(const Value& value) { + return Inst(Opcode::GetNZCVFromOp, value); + } + + ResultAndCarry LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in) { + const auto result = Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, carry_in); + const auto carry_out = Inst(Opcode::GetCarryFromOp, result); + return {result, carry_out}; + } + + ResultAndCarry LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { + const auto result = Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, carry_in); + const auto carry_out = Inst(Opcode::GetCarryFromOp, result); + return {result, carry_out}; + } + + ResultAndCarry ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { + const auto result = Inst(Opcode::ArithmeticShiftRight32, value_in, shift_amount, carry_in); + const auto carry_out = Inst(Opcode::GetCarryFromOp, result); + return {result, carry_out}; + } + + ResultAndCarry RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { + const auto result = Inst(Opcode::RotateRight32, value_in, shift_amount, carry_in); + const auto carry_out = Inst(Opcode::GetCarryFromOp, result); + return {result, carry_out}; + } + + ResultAndCarry RotateRightExtended(const U32& value_in, const U1& carry_in) { + const auto result = Inst(Opcode::RotateRightExtended, value_in, carry_in); + const auto carry_out = Inst(Opcode::GetCarryFromOp, result); + return {result, carry_out}; + } + + U32U64 LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount) { + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::LogicalShiftLeft32, value_in, shift_amount, Imm1(0)); + } else { + return Inst(Opcode::LogicalShiftLeft64, value_in, shift_amount); + } + } + + U32U64 LogicalShiftRight(const U32U64& value_in, const U8& shift_amount) { + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::LogicalShiftRight32, value_in, shift_amount, Imm1(0)); + } else { + return Inst(Opcode::LogicalShiftRight64, value_in, shift_amount); + } + } + + U32U64 ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount) { + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::ArithmeticShiftRight32, value_in, shift_amount, Imm1(0)); + } else { + return Inst(Opcode::ArithmeticShiftRight64, value_in, shift_amount); + } + } + + U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount) { + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::RotateRight32, value_in, shift_amount, Imm1(0)); + } else { + return Inst(Opcode::RotateRight64, value_in, shift_amount); + } + } + + U32U64 LogicalShiftLeftMasked(const U32U64& value_in, const U32U64& shift_amount) { + ASSERT(value_in.GetType() == shift_amount.GetType()); + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::LogicalShiftLeftMasked32, value_in, shift_amount); + } else { + return Inst(Opcode::LogicalShiftLeftMasked64, value_in, shift_amount); + } + } + + U32U64 LogicalShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount) { + ASSERT(value_in.GetType() == shift_amount.GetType()); + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::LogicalShiftRightMasked32, value_in, shift_amount); + } else { + return Inst(Opcode::LogicalShiftRightMasked64, value_in, shift_amount); + } + } + + U32U64 ArithmeticShiftRightMasked(const U32U64& value_in, const U32U64& shift_amount) { + ASSERT(value_in.GetType() == shift_amount.GetType()); + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::ArithmeticShiftRightMasked32, value_in, shift_amount); + } else { + return Inst(Opcode::ArithmeticShiftRightMasked64, value_in, shift_amount); + } + } + + U32U64 RotateRightMasked(const U32U64& value_in, const U32U64& shift_amount) { + ASSERT(value_in.GetType() == shift_amount.GetType()); + if (value_in.GetType() == Type::U32) { + return Inst(Opcode::RotateRightMasked32, value_in, shift_amount); + } else { + return Inst(Opcode::RotateRightMasked64, value_in, shift_amount); + } + } + + U32U64 AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::Add32, a, b, carry_in); + } else { + return Inst(Opcode::Add64, a, b, carry_in); + } + } + + U32U64 Add(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::Add32, a, b, Imm1(0)); + } else { + return Inst(Opcode::Add64, a, b, Imm1(0)); + } + } + + U32U64 SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::Sub32, a, b, carry_in); + } else { + return Inst(Opcode::Sub64, a, b, carry_in); + } + } + + U32U64 Sub(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::Sub32, a, b, Imm1(1)); + } else { + return Inst(Opcode::Sub64, a, b, Imm1(1)); + } + } + + U32U64 Mul(const U32U64& a, const U32U64& b) { + if (a.GetType() == Type::U32) { + return Inst(Opcode::Mul32, a, b); + } + + return Inst(Opcode::Mul64, a, b); + } + + U64 UnsignedMultiplyHigh(const U64& a, const U64& b) { + return Inst(Opcode::UnsignedMultiplyHigh64, a, b); + } + + U64 SignedMultiplyHigh(const U64& a, const U64& b) { + return Inst(Opcode::SignedMultiplyHigh64, a, b); + } + + U32U64 UnsignedDiv(const U32U64& a, const U32U64& b) { + if (a.GetType() == Type::U32) { + return Inst(Opcode::UnsignedDiv32, a, b); + } + + return Inst(Opcode::UnsignedDiv64, a, b); + } + + U32U64 SignedDiv(const U32U64& a, const U32U64& b) { + if (a.GetType() == Type::U32) { + return Inst(Opcode::SignedDiv32, a, b); + } + + return Inst(Opcode::SignedDiv64, a, b); + } + + U32U64 And(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::And32, a, b); + } else { + return Inst(Opcode::And64, a, b); + } + } + + U32U64 AndNot(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::AndNot32, a, b); + } else { + return Inst(Opcode::AndNot64, a, b); + } + } + + U32U64 Eor(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::Eor32, a, b); + } else { + return Inst(Opcode::Eor64, a, b); + } + } + + U32U64 Or(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + if (a.GetType() == Type::U32) { + return Inst(Opcode::Or32, a, b); + } else { + return Inst(Opcode::Or64, a, b); + } + } + + U32U64 Not(const U32U64& a) { + if (a.GetType() == Type::U32) { + return Inst(Opcode::Not32, a); + } else { + return Inst(Opcode::Not64, a); + } + } + + U64 SignExtendToLong(const UAny& a) { + switch (a.GetType()) { + case Type::U8: + return Inst(Opcode::SignExtendByteToLong, a); + case Type::U16: + return Inst(Opcode::SignExtendHalfToLong, a); + case Type::U32: + return Inst(Opcode::SignExtendWordToLong, a); + case Type::U64: + return U64(a); + default: + UNREACHABLE(); + } + } + + U32 SignExtendToWord(const UAny& a) { + switch (a.GetType()) { + case Type::U8: + return Inst(Opcode::SignExtendByteToWord, a); + case Type::U16: + return Inst(Opcode::SignExtendHalfToWord, a); + case Type::U32: + return U32(a); + case Type::U64: + return Inst(Opcode::LeastSignificantWord, a); + default: + UNREACHABLE(); + } + } + + U64 SignExtendWordToLong(const U32& a) { + return Inst(Opcode::SignExtendWordToLong, a); + } + + U32 SignExtendHalfToWord(const U16& a) { + return Inst(Opcode::SignExtendHalfToWord, a); + } + + U32 SignExtendByteToWord(const U8& a) { + return Inst(Opcode::SignExtendByteToWord, a); + } + + U64 ZeroExtendToLong(const UAny& a) { + switch (a.GetType()) { + case Type::U8: + return Inst(Opcode::ZeroExtendByteToLong, a); + case Type::U16: + return Inst(Opcode::ZeroExtendHalfToLong, a); + case Type::U32: + return Inst(Opcode::ZeroExtendWordToLong, a); + case Type::U64: + return U64(a); + default: + UNREACHABLE(); + } + } + + U32 ZeroExtendToWord(const UAny& a) { + switch (a.GetType()) { + case Type::U8: + return Inst(Opcode::ZeroExtendByteToWord, a); + case Type::U16: + return Inst(Opcode::ZeroExtendHalfToWord, a); + case Type::U32: + return U32(a); + case Type::U64: + return Inst(Opcode::LeastSignificantWord, a); + default: + UNREACHABLE(); + } + } + + U128 ZeroExtendToQuad(const UAny& a) { + return Inst(Opcode::ZeroExtendLongToQuad, ZeroExtendToLong(a)); + } + + U64 ZeroExtendWordToLong(const U32& a) { + return Inst(Opcode::ZeroExtendWordToLong, a); + } + + U32 ZeroExtendHalfToWord(const U16& a) { + return Inst(Opcode::ZeroExtendHalfToWord, a); + } + + U32 ZeroExtendByteToWord(const U8& a) { + return Inst(Opcode::ZeroExtendByteToWord, a); + } + + U32 IndeterminateExtendToWord(const UAny& a) { + // TODO: Implement properly + return ZeroExtendToWord(a); + } + + U64 IndeterminateExtendToLong(const UAny& a) { + // TODO: Implement properly + return ZeroExtendToLong(a); + } + + U32 ByteReverseWord(const U32& a) { + return Inst(Opcode::ByteReverseWord, a); + } + + U16 ByteReverseHalf(const U16& a) { + return Inst(Opcode::ByteReverseHalf, a); + } + + U64 ByteReverseDual(const U64& a) { + return Inst(Opcode::ByteReverseDual, a); + } + + U32U64 CountLeadingZeros(const U32U64& a) { + if (a.GetType() == IR::Type::U32) { + return Inst(Opcode::CountLeadingZeros32, a); + } + + return Inst(Opcode::CountLeadingZeros64, a); + } + + U32U64 ExtractRegister(const U32U64& a, const U32U64& b, const U8& lsb) { + if (a.GetType() == IR::Type::U32) { + return Inst(Opcode::ExtractRegister32, a, b, lsb); + } + + return Inst(Opcode::ExtractRegister64, a, b, lsb); + } + + U32U64 ReplicateBit(const U32U64& a, u8 bit) { + if (a.GetType() == IR::Type::U32) { + ASSERT(bit < 32); + return Inst(Opcode::ReplicateBit32, a, Imm8(bit)); + } + + ASSERT(bit < 64); + return Inst(Opcode::ReplicateBit64, a, Imm8(bit)); + } + + U32U64 MaxSigned(const U32U64& a, const U32U64& b) { + if (a.GetType() == IR::Type::U32) { + return Inst(Opcode::MaxSigned32, a, b); + } + + return Inst(Opcode::MaxSigned64, a, b); + } + + U32U64 MaxUnsigned(const U32U64& a, const U32U64& b) { + if (a.GetType() == IR::Type::U32) { + return Inst(Opcode::MaxUnsigned32, a, b); + } + + return Inst(Opcode::MaxUnsigned64, a, b); + } + + U32U64 MinSigned(const U32U64& a, const U32U64& b) { + if (a.GetType() == IR::Type::U32) { + return Inst(Opcode::MinSigned32, a, b); + } + + return Inst(Opcode::MinSigned64, a, b); + } + + U32U64 MinUnsigned(const U32U64& a, const U32U64& b) { + if (a.GetType() == IR::Type::U32) { + return Inst(Opcode::MinUnsigned32, a, b); + } + + return Inst(Opcode::MinUnsigned64, a, b); + } + + ResultAndOverflow SignedSaturatedAddWithFlag(const U32& a, const U32& b) { + const auto result = Inst(Opcode::SignedSaturatedAddWithFlag32, a, b); + const auto overflow = Inst(Opcode::GetOverflowFromOp, result); + return {result, overflow}; + } + + ResultAndOverflow SignedSaturatedSubWithFlag(const U32& a, const U32& b) { + const auto result = Inst(Opcode::SignedSaturatedSubWithFlag32, a, b); + const auto overflow = Inst(Opcode::GetOverflowFromOp, result); + return {result, overflow}; + } + + ResultAndOverflow SignedSaturation(const U32& a, size_t bit_size_to_saturate_to) { + ASSERT(bit_size_to_saturate_to >= 1 && bit_size_to_saturate_to <= 32); + const auto result = Inst(Opcode::SignedSaturation, a, Imm8(static_cast(bit_size_to_saturate_to))); + const auto overflow = Inst(Opcode::GetOverflowFromOp, result); + return {result, overflow}; + } + + ResultAndOverflow UnsignedSaturation(const U32& a, size_t bit_size_to_saturate_to) { + ASSERT(bit_size_to_saturate_to <= 31); + const auto result = Inst(Opcode::UnsignedSaturation, a, Imm8(static_cast(bit_size_to_saturate_to))); + const auto overflow = Inst(Opcode::GetOverflowFromOp, result); + return {result, overflow}; + } + + UAny SignedSaturatedAdd(const UAny& a, const UAny& b) { + ASSERT(a.GetType() == b.GetType()); + const auto result = [&]() -> IR::UAny { + switch (a.GetType()) { + case IR::Type::U8: + return Inst(Opcode::SignedSaturatedAdd8, a, b); + case IR::Type::U16: + return Inst(Opcode::SignedSaturatedAdd16, a, b); + case IR::Type::U32: + return Inst(Opcode::SignedSaturatedAdd32, a, b); + case IR::Type::U64: + return Inst(Opcode::SignedSaturatedAdd64, a, b); + default: + return IR::UAny{}; + } + }(); + return result; + } + + UAny SignedSaturatedDoublingMultiplyReturnHigh(const UAny& a, const UAny& b) { + ASSERT(a.GetType() == b.GetType()); + const auto result = [&]() -> IR::UAny { + switch (a.GetType()) { + case IR::Type::U16: + return Inst(Opcode::SignedSaturatedDoublingMultiplyReturnHigh16, a, b); + case IR::Type::U32: + return Inst(Opcode::SignedSaturatedDoublingMultiplyReturnHigh32, a, b); + default: + UNREACHABLE(); + } + }(); + return result; + } + + UAny SignedSaturatedSub(const UAny& a, const UAny& b) { + ASSERT(a.GetType() == b.GetType()); + const auto result = [&]() -> IR::UAny { + switch (a.GetType()) { + case IR::Type::U8: + return Inst(Opcode::SignedSaturatedSub8, a, b); + case IR::Type::U16: + return Inst(Opcode::SignedSaturatedSub16, a, b); + case IR::Type::U32: + return Inst(Opcode::SignedSaturatedSub32, a, b); + case IR::Type::U64: + return Inst(Opcode::SignedSaturatedSub64, a, b); + default: + return IR::UAny{}; + } + }(); + return result; + } + + UAny UnsignedSaturatedAdd(const UAny& a, const UAny& b) { + ASSERT(a.GetType() == b.GetType()); + const auto result = [&]() -> IR::UAny { + switch (a.GetType()) { + case IR::Type::U8: + return Inst(Opcode::UnsignedSaturatedAdd8, a, b); + case IR::Type::U16: + return Inst(Opcode::UnsignedSaturatedAdd16, a, b); + case IR::Type::U32: + return Inst(Opcode::UnsignedSaturatedAdd32, a, b); + case IR::Type::U64: + return Inst(Opcode::UnsignedSaturatedAdd64, a, b); + default: + return IR::UAny{}; + } + }(); + return result; + } + + UAny UnsignedSaturatedSub(const UAny& a, const UAny& b) { + ASSERT(a.GetType() == b.GetType()); + const auto result = [&]() -> IR::UAny { + switch (a.GetType()) { + case IR::Type::U8: + return Inst(Opcode::UnsignedSaturatedSub8, a, b); + case IR::Type::U16: + return Inst(Opcode::UnsignedSaturatedSub16, a, b); + case IR::Type::U32: + return Inst(Opcode::UnsignedSaturatedSub32, a, b); + case IR::Type::U64: + return Inst(Opcode::UnsignedSaturatedSub64, a, b); + default: + return IR::UAny{}; + } + }(); + return result; + } + + U128 VectorSignedSaturatedAdd(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedAdd8, a, b); + case 16: + return Inst(Opcode::VectorSignedSaturatedAdd16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedAdd32, a, b); + case 64: + return Inst(Opcode::VectorSignedSaturatedAdd64, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorSignedSaturatedSub(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedSub8, a, b); + case 16: + return Inst(Opcode::VectorSignedSaturatedSub16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedSub32, a, b); + case 64: + return Inst(Opcode::VectorSignedSaturatedSub64, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorUnsignedSaturatedAdd(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorUnsignedSaturatedAdd8, a, b); + case 16: + return Inst(Opcode::VectorUnsignedSaturatedAdd16, a, b); + case 32: + return Inst(Opcode::VectorUnsignedSaturatedAdd32, a, b); + case 64: + return Inst(Opcode::VectorUnsignedSaturatedAdd64, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorUnsignedSaturatedSub(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorUnsignedSaturatedSub8, a, b); + case 16: + return Inst(Opcode::VectorUnsignedSaturatedSub16, a, b); + case 32: + return Inst(Opcode::VectorUnsignedSaturatedSub32, a, b); + case 64: + return Inst(Opcode::VectorUnsignedSaturatedSub64, a, b); + default: + UNREACHABLE(); + } + } + + ResultAndGE PackedAddU8(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedAddU8, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedAddS8(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedAddS8, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedAddU16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedAddU16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedAddS16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedAddS16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedSubU8(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedSubU8, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedSubS8(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedSubS8, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedSubU16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedSubU16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedSubS16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedSubS16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedAddSubU16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedAddSubU16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedAddSubS16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedAddSubS16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedSubAddU16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedSubAddU16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + ResultAndGE PackedSubAddS16(const U32& a, const U32& b) { + const auto result = Inst(Opcode::PackedSubAddS16, a, b); + const auto ge = Inst(Opcode::GetGEFromOp, result); + return {result, ge}; + } + + U32 PackedHalvingAddU8(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingAddU8, a, b); + } + + U32 PackedHalvingAddS8(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingAddS8, a, b); + } + + U32 PackedHalvingSubU8(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingSubU8, a, b); + } + + U32 PackedHalvingSubS8(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingSubS8, a, b); + } + + U32 PackedHalvingAddU16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingAddU16, a, b); + } + + U32 PackedHalvingAddS16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingAddS16, a, b); + } + + U32 PackedHalvingSubU16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingSubU16, a, b); + } + + U32 PackedHalvingSubS16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingSubS16, a, b); + } + + U32 PackedHalvingAddSubU16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingAddSubU16, a, b); + } + + U32 PackedHalvingAddSubS16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingAddSubS16, a, b); + } + + U32 PackedHalvingSubAddU16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingSubAddU16, a, b); + } + + U32 PackedHalvingSubAddS16(const U32& a, const U32& b) { + return Inst(Opcode::PackedHalvingSubAddS16, a, b); + } + + U32 PackedSaturatedAddU8(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedAddU8, a, b); + } + + U32 PackedSaturatedAddS8(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedAddS8, a, b); + } + + U32 PackedSaturatedSubU8(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedSubU8, a, b); + } + + U32 PackedSaturatedSubS8(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedSubS8, a, b); + } + + U32 PackedSaturatedAddU16(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedAddU16, a, b); + } + + U32 PackedSaturatedAddS16(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedAddS16, a, b); + } + + U32 PackedSaturatedSubU16(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedSubU16, a, b); + } + + U32 PackedSaturatedSubS16(const U32& a, const U32& b) { + return Inst(Opcode::PackedSaturatedSubS16, a, b); + } + + U32 PackedAbsDiffSumU8(const U32& a, const U32& b) { + return Inst(Opcode::PackedAbsDiffSumU8, a, b); + } + + U32 PackedSelect(const U32& ge, const U32& a, const U32& b) { + return Inst(Opcode::PackedSelect, ge, a, b); + } + + U32 CRC32Castagnoli8(const U32& a, const U32& b) { + return Inst(Opcode::CRC32Castagnoli8, a, b); + } + + U32 CRC32Castagnoli16(const U32& a, const U32& b) { + return Inst(Opcode::CRC32Castagnoli16, a, b); + } + + U32 CRC32Castagnoli32(const U32& a, const U32& b) { + return Inst(Opcode::CRC32Castagnoli32, a, b); + } + + U32 CRC32Castagnoli64(const U32& a, const U64& b) { + return Inst(Opcode::CRC32Castagnoli64, a, b); + } + + U32 CRC32ISO8(const U32& a, const U32& b) { + return Inst(Opcode::CRC32ISO8, a, b); + } + + U32 CRC32ISO16(const U32& a, const U32& b) { + return Inst(Opcode::CRC32ISO16, a, b); + } + + U32 CRC32ISO32(const U32& a, const U32& b) { + return Inst(Opcode::CRC32ISO32, a, b); + } + + U32 CRC32ISO64(const U32& a, const U64& b) { + return Inst(Opcode::CRC32ISO64, a, b); + } + + U128 AESDecryptSingleRound(const U128& a) { + return Inst(Opcode::AESDecryptSingleRound, a); + } + + U128 AESEncryptSingleRound(const U128& a) { + return Inst(Opcode::AESEncryptSingleRound, a); + } + + U128 AESInverseMixColumns(const U128& a) { + return Inst(Opcode::AESInverseMixColumns, a); + } + + U128 AESMixColumns(const U128& a) { + return Inst(Opcode::AESMixColumns, a); + } + + U8 SM4AccessSubstitutionBox(const U8& a) { + return Inst(Opcode::SM4AccessSubstitutionBox, a); + } + + U128 SHA256Hash(const U128& x, const U128& y, const U128& w, bool part1) { + return Inst(Opcode::SHA256Hash, x, y, w, Imm1(part1)); + } + + U128 SHA256MessageSchedule0(const U128& x, const U128& y) { + return Inst(Opcode::SHA256MessageSchedule0, x, y); + } + + U128 SHA256MessageSchedule1(const U128& x, const U128& y, const U128& z) { + return Inst(Opcode::SHA256MessageSchedule1, x, y, z); + } + + UAny VectorGetElement(size_t esize, const U128& a, size_t index) { + ASSERT_MSG(esize * index < 128, "Invalid index"); + switch (esize) { + case 8: + return Inst(Opcode::VectorGetElement8, a, Imm8(static_cast(index))); + case 16: + return Inst(Opcode::VectorGetElement16, a, Imm8(static_cast(index))); + case 32: + return Inst(Opcode::VectorGetElement32, a, Imm8(static_cast(index))); + case 64: + return Inst(Opcode::VectorGetElement64, a, Imm8(static_cast(index))); + default: + UNREACHABLE(); + } + } + + U128 VectorSetElement(size_t esize, const U128& a, size_t index, const IR::UAny& elem) { + ASSERT_MSG(esize * index < 128, "Invalid index"); + switch (esize) { + case 8: + return Inst(Opcode::VectorSetElement8, a, Imm8(static_cast(index)), elem); + case 16: + return Inst(Opcode::VectorSetElement16, a, Imm8(static_cast(index)), elem); + case 32: + return Inst(Opcode::VectorSetElement32, a, Imm8(static_cast(index)), elem); + case 64: + return Inst(Opcode::VectorSetElement64, a, Imm8(static_cast(index)), elem); + default: + UNREACHABLE(); + } + } + + U128 VectorAbs(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorAbs8, a); + case 16: + return Inst(Opcode::VectorAbs16, a); + case 32: + return Inst(Opcode::VectorAbs32, a); + case 64: + return Inst(Opcode::VectorAbs64, a); + } + UNREACHABLE(); + } + + U128 VectorAdd(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorAdd8, a, b); + case 16: + return Inst(Opcode::VectorAdd16, a, b); + case 32: + return Inst(Opcode::VectorAdd32, a, b); + case 64: + return Inst(Opcode::VectorAdd64, a, b); + } + UNREACHABLE(); + } + + U128 VectorAnd(const U128& a, const U128& b) { + return Inst(Opcode::VectorAnd, a, b); + } + + U128 VectorAndNot(const U128& a, const U128& b) { + return Inst(Opcode::VectorAndNot, a, b); + } + + U128 VectorArithmeticShiftRight(size_t esize, const U128& a, u8 shift_amount) { + switch (esize) { + case 8: + return Inst(Opcode::VectorArithmeticShiftRight8, a, Imm8(shift_amount)); + case 16: + return Inst(Opcode::VectorArithmeticShiftRight16, a, Imm8(shift_amount)); + case 32: + return Inst(Opcode::VectorArithmeticShiftRight32, a, Imm8(shift_amount)); + case 64: + return Inst(Opcode::VectorArithmeticShiftRight64, a, Imm8(shift_amount)); + } + UNREACHABLE(); + } + + U128 VectorArithmeticVShift(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorArithmeticVShift8, a, b); + case 16: + return Inst(Opcode::VectorArithmeticVShift16, a, b); + case 32: + return Inst(Opcode::VectorArithmeticVShift32, a, b); + case 64: + return Inst(Opcode::VectorArithmeticVShift64, a, b); + } + UNREACHABLE(); + } + + U128 VectorBroadcastLower(size_t esize, const UAny& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorBroadcastLower8, U8(a)); + case 16: + return Inst(Opcode::VectorBroadcastLower16, U16(a)); + case 32: + return Inst(Opcode::VectorBroadcastLower32, U32(a)); + } + UNREACHABLE(); + } + + U128 VectorBroadcast(size_t esize, const UAny& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorBroadcast8, U8(a)); + case 16: + return Inst(Opcode::VectorBroadcast16, U16(a)); + case 32: + return Inst(Opcode::VectorBroadcast32, U32(a)); + case 64: + return Inst(Opcode::VectorBroadcast64, U64(a)); + } + UNREACHABLE(); + } + + U128 VectorBroadcastElementLower(size_t esize, const U128& a, size_t index) { + ASSERT_MSG(esize * index < 128, "Invalid index"); + switch (esize) { + case 8: + return Inst(Opcode::VectorBroadcastElementLower8, a, u8(index)); + case 16: + return Inst(Opcode::VectorBroadcastElementLower16, a, u8(index)); + case 32: + return Inst(Opcode::VectorBroadcastElementLower32, a, u8(index)); + } + UNREACHABLE(); + } + + U128 VectorBroadcastElement(size_t esize, const U128& a, size_t index) { + ASSERT_MSG(esize * index < 128, "Invalid index"); + switch (esize) { + case 8: + return Inst(Opcode::VectorBroadcastElement8, a, u8(index)); + case 16: + return Inst(Opcode::VectorBroadcastElement16, a, u8(index)); + case 32: + return Inst(Opcode::VectorBroadcastElement32, a, u8(index)); + case 64: + return Inst(Opcode::VectorBroadcastElement64, a, u8(index)); + } + UNREACHABLE(); + } + + U128 VectorCountLeadingZeros(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorCountLeadingZeros8, a); + case 16: + return Inst(Opcode::VectorCountLeadingZeros16, a); + case 32: + return Inst(Opcode::VectorCountLeadingZeros32, a); + } + UNREACHABLE(); + } + + U128 VectorDeinterleaveEven(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorDeinterleaveEven8, a, b); + case 16: + return Inst(Opcode::VectorDeinterleaveEven16, a, b); + case 32: + return Inst(Opcode::VectorDeinterleaveEven32, a, b); + case 64: + return Inst(Opcode::VectorDeinterleaveEven64, a, b); + } + UNREACHABLE(); + } + + U128 VectorDeinterleaveOdd(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorDeinterleaveOdd8, a, b); + case 16: + return Inst(Opcode::VectorDeinterleaveOdd16, a, b); + case 32: + return Inst(Opcode::VectorDeinterleaveOdd32, a, b); + case 64: + return Inst(Opcode::VectorDeinterleaveOdd64, a, b); + } + UNREACHABLE(); + } + + U128 VectorDeinterleaveEvenLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorDeinterleaveEvenLower8, a, b); + case 16: + return Inst(Opcode::VectorDeinterleaveEvenLower16, a, b); + case 32: + return Inst(Opcode::VectorDeinterleaveEvenLower32, a, b); + } + UNREACHABLE(); + } + + U128 VectorDeinterleaveOddLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorDeinterleaveOddLower8, a, b); + case 16: + return Inst(Opcode::VectorDeinterleaveOddLower16, a, b); + case 32: + return Inst(Opcode::VectorDeinterleaveOddLower32, a, b); + } + UNREACHABLE(); + } + + U128 VectorEor(const U128& a, const U128& b) { + return Inst(Opcode::VectorEor, a, b); + } + + U128 VectorEqual(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorEqual8, a, b); + case 16: + return Inst(Opcode::VectorEqual16, a, b); + case 32: + return Inst(Opcode::VectorEqual32, a, b); + case 64: + return Inst(Opcode::VectorEqual64, a, b); + case 128: + return Inst(Opcode::VectorEqual128, a, b); + } + UNREACHABLE(); + } + + U128 VectorExtract(const U128& a, const U128& b, size_t position) { + ASSERT(position <= 128); + return Inst(Opcode::VectorExtract, a, b, Imm8(static_cast(position))); + } + + U128 VectorExtractLower(const U128& a, const U128& b, size_t position) { + ASSERT(position <= 64); + return Inst(Opcode::VectorExtractLower, a, b, Imm8(static_cast(position))); + } + + U128 VectorGreaterSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorGreaterS8, a, b); + case 16: + return Inst(Opcode::VectorGreaterS16, a, b); + case 32: + return Inst(Opcode::VectorGreaterS32, a, b); + case 64: + return Inst(Opcode::VectorGreaterS64, a, b); + } + UNREACHABLE(); + } + + U128 VectorGreaterEqualSigned(size_t esize, const U128& a, const U128& b) { + return VectorOr(VectorGreaterSigned(esize, a, b), VectorEqual(esize, a, b)); + } + + U128 VectorGreaterEqualUnsigned(size_t esize, const U128& a, const U128& b) { + return VectorEqual(esize, VectorMaxUnsigned(esize, a, b), a); + } + + U128 VectorGreaterUnsigned(size_t esize, const U128& a, const U128& b) { + return VectorNot(VectorEqual(esize, VectorMinUnsigned(esize, a, b), a)); + } + + U128 VectorHalvingAddSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorHalvingAddS8, a, b); + case 16: + return Inst(Opcode::VectorHalvingAddS16, a, b); + case 32: + return Inst(Opcode::VectorHalvingAddS32, a, b); + } + UNREACHABLE(); + } + + U128 VectorHalvingAddUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorHalvingAddU8, a, b); + case 16: + return Inst(Opcode::VectorHalvingAddU16, a, b); + case 32: + return Inst(Opcode::VectorHalvingAddU32, a, b); + } + UNREACHABLE(); + } + + U128 VectorHalvingSubSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorHalvingSubS8, a, b); + case 16: + return Inst(Opcode::VectorHalvingSubS16, a, b); + case 32: + return Inst(Opcode::VectorHalvingSubS32, a, b); + } + UNREACHABLE(); + } + + U128 VectorHalvingSubUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorHalvingSubU8, a, b); + case 16: + return Inst(Opcode::VectorHalvingSubU16, a, b); + case 32: + return Inst(Opcode::VectorHalvingSubU32, a, b); + } + UNREACHABLE(); + } + + U128 VectorInterleaveLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorInterleaveLower8, a, b); + case 16: + return Inst(Opcode::VectorInterleaveLower16, a, b); + case 32: + return Inst(Opcode::VectorInterleaveLower32, a, b); + case 64: + return Inst(Opcode::VectorInterleaveLower64, a, b); + } + UNREACHABLE(); + } + + U128 VectorInterleaveUpper(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorInterleaveUpper8, a, b); + case 16: + return Inst(Opcode::VectorInterleaveUpper16, a, b); + case 32: + return Inst(Opcode::VectorInterleaveUpper32, a, b); + case 64: + return Inst(Opcode::VectorInterleaveUpper64, a, b); + } + UNREACHABLE(); + } + + U128 VectorLessEqualSigned(size_t esize, const U128& a, const U128& b) { + return VectorNot(VectorGreaterSigned(esize, a, b)); + } + + U128 VectorLessEqualUnsigned(size_t esize, const U128& a, const U128& b) { + return VectorEqual(esize, VectorMinUnsigned(esize, a, b), a); + } + + U128 VectorLessSigned(size_t esize, const U128& a, const U128& b) { + return VectorNot(VectorOr(VectorGreaterSigned(esize, a, b), VectorEqual(esize, a, b))); + } + + U128 VectorLessUnsigned(size_t esize, const U128& a, const U128& b) { + return VectorNot(VectorEqual(esize, VectorMaxUnsigned(esize, a, b), a)); + } + + U128 VectorLogicalShiftLeft(size_t esize, const U128& a, u8 shift_amount) { + switch (esize) { + case 8: + return Inst(Opcode::VectorLogicalShiftLeft8, a, Imm8(shift_amount)); + case 16: + return Inst(Opcode::VectorLogicalShiftLeft16, a, Imm8(shift_amount)); + case 32: + return Inst(Opcode::VectorLogicalShiftLeft32, a, Imm8(shift_amount)); + case 64: + return Inst(Opcode::VectorLogicalShiftLeft64, a, Imm8(shift_amount)); + } + UNREACHABLE(); + } + + U128 VectorLogicalShiftRight(size_t esize, const U128& a, u8 shift_amount) { + switch (esize) { + case 8: + return Inst(Opcode::VectorLogicalShiftRight8, a, Imm8(shift_amount)); + case 16: + return Inst(Opcode::VectorLogicalShiftRight16, a, Imm8(shift_amount)); + case 32: + return Inst(Opcode::VectorLogicalShiftRight32, a, Imm8(shift_amount)); + case 64: + return Inst(Opcode::VectorLogicalShiftRight64, a, Imm8(shift_amount)); + } + UNREACHABLE(); + } + + U128 VectorLogicalVShift(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorLogicalVShift8, a, b); + case 16: + return Inst(Opcode::VectorLogicalVShift16, a, b); + case 32: + return Inst(Opcode::VectorLogicalVShift32, a, b); + case 64: + return Inst(Opcode::VectorLogicalVShift64, a, b); + } + UNREACHABLE(); + } + + U128 VectorMaxSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMaxS8, a, b); + case 16: + return Inst(Opcode::VectorMaxS16, a, b); + case 32: + return Inst(Opcode::VectorMaxS32, a, b); + case 64: + return Inst(Opcode::VectorMaxS64, a, b); + } + UNREACHABLE(); + } + + U128 VectorMaxUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMaxU8, a, b); + case 16: + return Inst(Opcode::VectorMaxU16, a, b); + case 32: + return Inst(Opcode::VectorMaxU32, a, b); + case 64: + return Inst(Opcode::VectorMaxU64, a, b); + } + UNREACHABLE(); + } + + U128 VectorMinSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMinS8, a, b); + case 16: + return Inst(Opcode::VectorMinS16, a, b); + case 32: + return Inst(Opcode::VectorMinS32, a, b); + case 64: + return Inst(Opcode::VectorMinS64, a, b); + } + UNREACHABLE(); + } + + U128 VectorMinUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMinU8, a, b); + case 16: + return Inst(Opcode::VectorMinU16, a, b); + case 32: + return Inst(Opcode::VectorMinU32, a, b); + case 64: + return Inst(Opcode::VectorMinU64, a, b); + } + UNREACHABLE(); + } + + U128 VectorMultiply(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMultiply8, a, b); + case 16: + return Inst(Opcode::VectorMultiply16, a, b); + case 32: + return Inst(Opcode::VectorMultiply32, a, b); + case 64: + return Inst(Opcode::VectorMultiply64, a, b); + } + UNREACHABLE(); + } + + U128 VectorMultiplySignedWiden(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMultiplySignedWiden8, a, b); + case 16: + return Inst(Opcode::VectorMultiplySignedWiden16, a, b); + case 32: + return Inst(Opcode::VectorMultiplySignedWiden32, a, b); + } + UNREACHABLE(); + } + + U128 VectorMultiplyUnsignedWiden(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorMultiplyUnsignedWiden8, a, b); + case 16: + return Inst(Opcode::VectorMultiplyUnsignedWiden16, a, b); + case 32: + return Inst(Opcode::VectorMultiplyUnsignedWiden32, a, b); + } + UNREACHABLE(); + } + + U128 VectorNarrow(size_t original_esize, const U128& a) { + switch (original_esize) { + case 16: + return Inst(Opcode::VectorNarrow16, a); + case 32: + return Inst(Opcode::VectorNarrow32, a); + case 64: + return Inst(Opcode::VectorNarrow64, a); + } + UNREACHABLE(); + } + + U128 VectorNot(const U128& a) { + return Inst(Opcode::VectorNot, a); + } + + U128 VectorOr(const U128& a, const U128& b) { + return Inst(Opcode::VectorOr, a, b); + } + + U128 VectorPairedAdd(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedAdd8, a, b); + case 16: + return Inst(Opcode::VectorPairedAdd16, a, b); + case 32: + return Inst(Opcode::VectorPairedAdd32, a, b); + case 64: + return Inst(Opcode::VectorPairedAdd64, a, b); + } + UNREACHABLE(); + } + + U128 VectorPairedAddLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedAddLower8, a, b); + case 16: + return Inst(Opcode::VectorPairedAddLower16, a, b); + case 32: + return Inst(Opcode::VectorPairedAddLower32, a, b); + } + UNREACHABLE(); + } + + U128 VectorPairedAddSignedWiden(size_t original_esize, const U128& a) { + switch (original_esize) { + case 8: + return Inst(Opcode::VectorPairedAddSignedWiden8, a); + case 16: + return Inst(Opcode::VectorPairedAddSignedWiden16, a); + case 32: + return Inst(Opcode::VectorPairedAddSignedWiden32, a); + } + UNREACHABLE(); + } + + U128 VectorPairedAddUnsignedWiden(size_t original_esize, const U128& a) { + switch (original_esize) { + case 8: + return Inst(Opcode::VectorPairedAddUnsignedWiden8, a); + case 16: + return Inst(Opcode::VectorPairedAddUnsignedWiden16, a); + case 32: + return Inst(Opcode::VectorPairedAddUnsignedWiden32, a); + } + UNREACHABLE(); + } + + U128 VectorPairedMaxSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMaxS8, a, b); + case 16: + return Inst(Opcode::VectorPairedMaxS16, a, b); + case 32: + return Inst(Opcode::VectorPairedMaxS32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMaxUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMaxU8, a, b); + case 16: + return Inst(Opcode::VectorPairedMaxU16, a, b); + case 32: + return Inst(Opcode::VectorPairedMaxU32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMinSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMinS8, a, b); + case 16: + return Inst(Opcode::VectorPairedMinS16, a, b); + case 32: + return Inst(Opcode::VectorPairedMinS32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMinUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMinU8, a, b); + case 16: + return Inst(Opcode::VectorPairedMinU16, a, b); + case 32: + return Inst(Opcode::VectorPairedMinU32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMaxSignedLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMaxLowerS8, a, b); + case 16: + return Inst(Opcode::VectorPairedMaxLowerS16, a, b); + case 32: + return Inst(Opcode::VectorPairedMaxLowerS32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMaxUnsignedLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMaxLowerU8, a, b); + case 16: + return Inst(Opcode::VectorPairedMaxLowerU16, a, b); + case 32: + return Inst(Opcode::VectorPairedMaxLowerU32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMinSignedLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMinLowerS8, a, b); + case 16: + return Inst(Opcode::VectorPairedMinLowerS16, a, b); + case 32: + return Inst(Opcode::VectorPairedMinLowerS32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPairedMinUnsignedLower(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPairedMinLowerU8, a, b); + case 16: + return Inst(Opcode::VectorPairedMinLowerU16, a, b); + case 32: + return Inst(Opcode::VectorPairedMinLowerU32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPolynomialMultiply(const U128& a, const U128& b) { + return Inst(Opcode::VectorPolynomialMultiply8, a, b); + } + + U128 VectorPolynomialMultiplyLong(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorPolynomialMultiplyLong8, a, b); + case 64: + return Inst(Opcode::VectorPolynomialMultiplyLong64, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorPopulationCount(const U128& a) { + return Inst(Opcode::VectorPopulationCount, a); + } + + U128 VectorReverseBits(const U128& a) { + return Inst(Opcode::VectorReverseBits, a); + } + + U128 VectorReverseElementsInHalfGroups(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorReverseElementsInHalfGroups8, a); + default: + UNREACHABLE(); + } + } + + U128 VectorReverseElementsInWordGroups(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorReverseElementsInWordGroups8, a); + case 16: + return Inst(Opcode::VectorReverseElementsInWordGroups16, a); + default: + UNREACHABLE(); + } + } + + U128 VectorReverseElementsInLongGroups(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorReverseElementsInLongGroups8, a); + case 16: + return Inst(Opcode::VectorReverseElementsInLongGroups16, a); + case 32: + return Inst(Opcode::VectorReverseElementsInLongGroups32, a); + default: + UNREACHABLE(); + } + } + + U128 VectorReduceAdd(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorReduceAdd8, a); + case 16: + return Inst(Opcode::VectorReduceAdd16, a); + case 32: + return Inst(Opcode::VectorReduceAdd32, a); + case 64: + return Inst(Opcode::VectorReduceAdd64, a); + } + + UNREACHABLE(); + } + + U128 VectorRotateLeft(size_t esize, const U128& a, u8 amount) { + ASSERT(amount < esize); + + if (amount == 0) { + return a; + } + + return VectorOr(VectorLogicalShiftLeft(esize, a, amount), + VectorLogicalShiftRight(esize, a, static_cast(esize - amount))); + } + + U128 VectorRotateRight(size_t esize, const U128& a, u8 amount) { + ASSERT(amount < esize); + + if (amount == 0) { + return a; + } + + return VectorOr(VectorLogicalShiftRight(esize, a, amount), + VectorLogicalShiftLeft(esize, a, static_cast(esize - amount))); + } + + U128 VectorRotateWholeVectorRight(const U128& a, u8 amount) { + ASSERT(amount % 32 == 0); + return Inst(Opcode::VectorRotateWholeVectorRight, a, Imm8(amount)); + } + + U128 VectorRoundingHalvingAddSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorRoundingHalvingAddS8, a, b); + case 16: + return Inst(Opcode::VectorRoundingHalvingAddS16, a, b); + case 32: + return Inst(Opcode::VectorRoundingHalvingAddS32, a, b); + } + + UNREACHABLE(); + } + + U128 VectorRoundingHalvingAddUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorRoundingHalvingAddU8, a, b); + case 16: + return Inst(Opcode::VectorRoundingHalvingAddU16, a, b); + case 32: + return Inst(Opcode::VectorRoundingHalvingAddU32, a, b); + } + + UNREACHABLE(); + } + + U128 VectorRoundingShiftLeftSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorRoundingShiftLeftS8, a, b); + case 16: + return Inst(Opcode::VectorRoundingShiftLeftS16, a, b); + case 32: + return Inst(Opcode::VectorRoundingShiftLeftS32, a, b); + case 64: + return Inst(Opcode::VectorRoundingShiftLeftS64, a, b); + } + + UNREACHABLE(); + } + + U128 VectorRoundingShiftLeftUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorRoundingShiftLeftU8, a, b); + case 16: + return Inst(Opcode::VectorRoundingShiftLeftU16, a, b); + case 32: + return Inst(Opcode::VectorRoundingShiftLeftU32, a, b); + case 64: + return Inst(Opcode::VectorRoundingShiftLeftU64, a, b); + } + + UNREACHABLE(); + } + + U128 VectorSignExtend(size_t original_esize, const U128& a) { + switch (original_esize) { + case 8: + return Inst(Opcode::VectorSignExtend8, a); + case 16: + return Inst(Opcode::VectorSignExtend16, a); + case 32: + return Inst(Opcode::VectorSignExtend32, a); + case 64: + return Inst(Opcode::VectorSignExtend64, a); + } + UNREACHABLE(); + } + + U128 VectorSignedAbsoluteDifference(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedAbsoluteDifference8, a, b); + case 16: + return Inst(Opcode::VectorSignedAbsoluteDifference16, a, b); + case 32: + return Inst(Opcode::VectorSignedAbsoluteDifference32, a, b); + } + UNREACHABLE(); + } + + UpperAndLower VectorSignedMultiply(size_t esize, const U128& a, const U128& b) { + const Value multiply = [&] { + switch (esize) { + case 16: + return Inst(Opcode::VectorSignedMultiply16, a, b); + case 32: + return Inst(Opcode::VectorSignedMultiply32, a, b); + } + UNREACHABLE(); + }(); + + return { + Inst(Opcode::GetUpperFromOp, multiply), + Inst(Opcode::GetLowerFromOp, multiply), + }; + } + + U128 VectorSignedSaturatedAbs(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedAbs8, a); + case 16: + return Inst(Opcode::VectorSignedSaturatedAbs16, a); + case 32: + return Inst(Opcode::VectorSignedSaturatedAbs32, a); + case 64: + return Inst(Opcode::VectorSignedSaturatedAbs64, a); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedAccumulateUnsigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned8, a, b); + case 16: + return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned32, a, b); + case 64: + return Inst(Opcode::VectorSignedSaturatedAccumulateUnsigned64, a, b); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedDoublingMultiplyHigh(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 16: + return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHigh16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHigh32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorSignedSaturatedDoublingMultiplyHighRounding(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 16: + return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHighRounding16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyHighRounding32, a, b); + default: + UNREACHABLE(); + } + } + + U128 VectorSignedSaturatedDoublingMultiplyLong(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 16: + return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyLong16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedDoublingMultiplyLong32, a, b); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedNarrowToSigned(size_t original_esize, const U128& a) { + switch (original_esize) { + case 16: + return Inst(Opcode::VectorSignedSaturatedNarrowToSigned16, a); + case 32: + return Inst(Opcode::VectorSignedSaturatedNarrowToSigned32, a); + case 64: + return Inst(Opcode::VectorSignedSaturatedNarrowToSigned64, a); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedNarrowToUnsigned(size_t original_esize, const U128& a) { + switch (original_esize) { + case 16: + return Inst(Opcode::VectorSignedSaturatedNarrowToUnsigned16, a); + case 32: + return Inst(Opcode::VectorSignedSaturatedNarrowToUnsigned32, a); + case 64: + return Inst(Opcode::VectorSignedSaturatedNarrowToUnsigned64, a); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedNeg(size_t esize, const U128& a) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedNeg8, a); + case 16: + return Inst(Opcode::VectorSignedSaturatedNeg16, a); + case 32: + return Inst(Opcode::VectorSignedSaturatedNeg32, a); + case 64: + return Inst(Opcode::VectorSignedSaturatedNeg64, a); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedShiftLeft8, a, b); + case 16: + return Inst(Opcode::VectorSignedSaturatedShiftLeft16, a, b); + case 32: + return Inst(Opcode::VectorSignedSaturatedShiftLeft32, a, b); + case 64: + return Inst(Opcode::VectorSignedSaturatedShiftLeft64, a, b); + } + UNREACHABLE(); + } + + U128 VectorSignedSaturatedShiftLeftUnsigned(size_t esize, const U128& a, u8 shift_amount) { + ASSERT(shift_amount < esize); + switch (esize) { + case 8: + return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned8, a, Imm8(shift_amount)); + case 16: + return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned16, a, Imm8(shift_amount)); + case 32: + return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned32, a, Imm8(shift_amount)); + case 64: + return Inst(Opcode::VectorSignedSaturatedShiftLeftUnsigned64, a, Imm8(shift_amount)); + } + UNREACHABLE(); + } + + U128 VectorSub(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorSub8, a, b); + case 16: + return Inst(Opcode::VectorSub16, a, b); + case 32: + return Inst(Opcode::VectorSub32, a, b); + case 64: + return Inst(Opcode::VectorSub64, a, b); + } + UNREACHABLE(); + } + + Table VectorTable(std::vector values) { + ASSERT(values.size() >= 1 && values.size() <= 4); + values.resize(4); + return Inst
(Opcode::VectorTable, values[0], values[1], values[2], values[3]); + } + + Table VectorTable(std::vector values) { + ASSERT(values.size() >= 1 && values.size() <= 4); + values.resize(4); + return Inst
(Opcode::VectorTable, values[0], values[1], values[2], values[3]); + } + + U64 VectorTableLookup(const U64& defaults, const Table& table, const U64& indices) { + ASSERT(table.GetInst()->GetArg(0).GetType() == Type::U64); + return Inst(Opcode::VectorTableLookup64, defaults, table, indices); + } + + U128 VectorTableLookup(const U128& defaults, const Table& table, const U128& indices) { + ASSERT(table.GetInst()->GetArg(0).GetType() == Type::U128); + return Inst(Opcode::VectorTableLookup128, defaults, table, indices); + } + + U128 VectorTranspose(size_t esize, const U128& a, const U128& b, bool part) { + switch (esize) { + case 8: + return Inst(Opcode::VectorTranspose8, a, b, Imm1(part)); + case 16: + return Inst(Opcode::VectorTranspose16, a, b, Imm1(part)); + case 32: + return Inst(Opcode::VectorTranspose32, a, b, Imm1(part)); + case 64: + return Inst(Opcode::VectorTranspose64, a, b, Imm1(part)); + } + UNREACHABLE(); + } + + U128 VectorUnsignedAbsoluteDifference(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorUnsignedAbsoluteDifference8, a, b); + case 16: + return Inst(Opcode::VectorUnsignedAbsoluteDifference16, a, b); + case 32: + return Inst(Opcode::VectorUnsignedAbsoluteDifference32, a, b); + } + UNREACHABLE(); + } + + U128 VectorUnsignedRecipEstimate(const U128& a) { + return Inst(Opcode::VectorUnsignedRecipEstimate, a); + } + + U128 VectorUnsignedRecipSqrtEstimate(const U128& a) { + return Inst(Opcode::VectorUnsignedRecipSqrtEstimate, a); + } + + U128 VectorUnsignedSaturatedAccumulateSigned(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned8, a, b); + case 16: + return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned16, a, b); + case 32: + return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned32, a, b); + case 64: + return Inst(Opcode::VectorUnsignedSaturatedAccumulateSigned64, a, b); + } + UNREACHABLE(); + } + + U128 VectorUnsignedSaturatedNarrow(size_t esize, const U128& a) { + switch (esize) { + case 16: + return Inst(Opcode::VectorUnsignedSaturatedNarrow16, a); + case 32: + return Inst(Opcode::VectorUnsignedSaturatedNarrow32, a); + case 64: + return Inst(Opcode::VectorUnsignedSaturatedNarrow64, a); + } + UNREACHABLE(); + } + + U128 VectorUnsignedSaturatedShiftLeft(size_t esize, const U128& a, const U128& b) { + switch (esize) { + case 8: + return Inst(Opcode::VectorUnsignedSaturatedShiftLeft8, a, b); + case 16: + return Inst(Opcode::VectorUnsignedSaturatedShiftLeft16, a, b); + case 32: + return Inst(Opcode::VectorUnsignedSaturatedShiftLeft32, a, b); + case 64: + return Inst(Opcode::VectorUnsignedSaturatedShiftLeft64, a, b); + } + UNREACHABLE(); + } + + U128 VectorZeroExtend(size_t original_esize, const U128& a) { + switch (original_esize) { + case 8: + return Inst(Opcode::VectorZeroExtend8, a); + case 16: + return Inst(Opcode::VectorZeroExtend16, a); + case 32: + return Inst(Opcode::VectorZeroExtend32, a); + case 64: + return Inst(Opcode::VectorZeroExtend64, a); + } + UNREACHABLE(); + } + + U128 VectorZeroUpper(const U128& a) { + return Inst(Opcode::VectorZeroUpper, a); + } + + U128 ZeroVector() { + return Inst(Opcode::ZeroVector); + } + + U16U32U64 FPAbs(const U16U32U64& a) { + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPAbs16, a); + case Type::U32: + return Inst(Opcode::FPAbs32, a); + case Type::U64: + return Inst(Opcode::FPAbs64, a); + default: + UNREACHABLE(); + } + } + + U32U64 FPAdd(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPAdd32, a, b); + case Type::U64: + return Inst(Opcode::FPAdd64, a, b); + default: + UNREACHABLE(); + } + } + + NZCV FPCompare(const U32U64& a, const U32U64& b, bool exc_on_qnan) { + ASSERT(a.GetType() == b.GetType()); + + const IR::U1 exc_on_qnan_imm = Imm1(exc_on_qnan); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPCompare32, a, b, exc_on_qnan_imm); + case Type::U64: + return Inst(Opcode::FPCompare64, a, b, exc_on_qnan_imm); + default: + UNREACHABLE(); + } + } + + U32U64 FPDiv(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPDiv32, a, b); + case Type::U64: + return Inst(Opcode::FPDiv64, a, b); + default: + UNREACHABLE(); + } + } + + U32U64 FPMax(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPMax32, a, b); + case Type::U64: + return Inst(Opcode::FPMax64, a, b); + default: + UNREACHABLE(); + } + } + + U32U64 FPMaxNumeric(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPMaxNumeric32, a, b); + case Type::U64: + return Inst(Opcode::FPMaxNumeric64, a, b); + default: + UNREACHABLE(); + } + } + + U32U64 FPMin(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPMin32, a, b); + case Type::U64: + return Inst(Opcode::FPMin64, a, b); + default: + UNREACHABLE(); + } + } + + U32U64 FPMinNumeric(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPMinNumeric32, a, b); + case Type::U64: + return Inst(Opcode::FPMinNumeric64, a, b); + default: + UNREACHABLE(); + } + } + + U32U64 FPMul(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPMul32, a, b); + case Type::U64: + return Inst(Opcode::FPMul64, a, b); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPMulAdd(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPMulAdd16, a, b, c); + case Type::U32: + return Inst(Opcode::FPMulAdd32, a, b, c); + case Type::U64: + return Inst(Opcode::FPMulAdd64, a, b, c); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPMulSub(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPMulSub16, a, b, c); + case Type::U32: + return Inst(Opcode::FPMulSub32, a, b, c); + case Type::U64: + return Inst(Opcode::FPMulSub64, a, b, c); + default: + UNREACHABLE(); + } + } + + U32U64 FPMulX(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPMulX32, a, b); + case Type::U64: + return Inst(Opcode::FPMulX64, a, b); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPNeg(const U16U32U64& a) { + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPNeg16, a); + case Type::U32: + return Inst(Opcode::FPNeg32, a); + case Type::U64: + return Inst(Opcode::FPNeg64, a); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPRecipEstimate(const U16U32U64& a) { + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPRecipEstimate16, a); + case Type::U32: + return Inst(Opcode::FPRecipEstimate32, a); + case Type::U64: + return Inst(Opcode::FPRecipEstimate64, a); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPRecipExponent(const U16U32U64& a) { + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPRecipExponent16, a); + case Type::U32: + return Inst(Opcode::FPRecipExponent32, a); + case Type::U64: + return Inst(Opcode::FPRecipExponent64, a); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPRecipStepFused(const U16U32U64& a, const U16U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPRecipStepFused16, a, b); + case Type::U32: + return Inst(Opcode::FPRecipStepFused32, a, b); + case Type::U64: + return Inst(Opcode::FPRecipStepFused64, a, b); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPRoundInt(const U16U32U64& a, FP::RoundingMode rounding, bool exact) { + const u8 rounding_value = static_cast(rounding); + const IR::U1 exact_imm = Imm1(exact); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPRoundInt16, a, rounding_value, exact_imm); + case Type::U32: + return Inst(Opcode::FPRoundInt32, a, rounding_value, exact_imm); + case Type::U64: + return Inst(Opcode::FPRoundInt64, a, rounding_value, exact_imm); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPRSqrtEstimate(const U16U32U64& a) { + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPRSqrtEstimate16, a); + case Type::U32: + return Inst(Opcode::FPRSqrtEstimate32, a); + case Type::U64: + return Inst(Opcode::FPRSqrtEstimate64, a); + default: + UNREACHABLE(); + } + } + + U16U32U64 FPRSqrtStepFused(const U16U32U64& a, const U16U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPRSqrtStepFused16, a, b); + case Type::U32: + return Inst(Opcode::FPRSqrtStepFused32, a, b); + case Type::U64: + return Inst(Opcode::FPRSqrtStepFused64, a, b); + default: + UNREACHABLE(); + } + } + + U32U64 FPSqrt(const U32U64& a) { + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPSqrt32, a); + case Type::U64: + return Inst(Opcode::FPSqrt64, a); + default: + UNREACHABLE(); + } + } + + U32U64 FPSub(const U32U64& a, const U32U64& b) { + ASSERT(a.GetType() == b.GetType()); + + switch (a.GetType()) { + case Type::U32: + return Inst(Opcode::FPSub32, a, b); + case Type::U64: + return Inst(Opcode::FPSub64, a, b); + default: + UNREACHABLE(); + } + } + + U16 FPDoubleToHalf(const U64& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPDoubleToHalf, a, Imm8(static_cast(rounding))); + } + + U32 FPDoubleToSingle(const U64& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPDoubleToSingle, a, Imm8(static_cast(rounding))); + } + + U64 FPHalfToDouble(const U16& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPHalfToDouble, a, Imm8(static_cast(rounding))); + } + + U32 FPHalfToSingle(const U16& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPHalfToSingle, a, Imm8(static_cast(rounding))); + } + + U64 FPSingleToDouble(const U32& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPSingleToDouble, a, Imm8(static_cast(rounding))); + } + + U16 FPSingleToHalf(const U32& a, FP::RoundingMode rounding) { + return Inst(Opcode::FPSingleToHalf, a, Imm8(static_cast(rounding))); + } + + U16 FPToFixedS16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= 16); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPHalfToFixedS16, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPSingleToFixedS16, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPDoubleToFixedS16, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U32 FPToFixedS32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= 32); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPHalfToFixedS32, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPSingleToFixedS32, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPDoubleToFixedS32, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U64 FPToFixedS64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= 64); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPHalfToFixedS64, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPSingleToFixedS64, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPDoubleToFixedS64, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U16 FPToFixedU16(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= 16); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPHalfToFixedU16, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPSingleToFixedU16, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPDoubleToFixedU16, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U32 FPToFixedU32(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= 32); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPHalfToFixedU32, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPSingleToFixedU32, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPDoubleToFixedU32, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U64 FPToFixedU64(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= 64); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPHalfToFixedU64, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPSingleToFixedU64, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPDoubleToFixedU64, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U32 FPSignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); + + const IR::U8 fbits_imm = Imm8(static_cast(fbits)); + const IR::U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPFixedS16ToSingle, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPFixedS32ToSingle, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPFixedS64ToSingle, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U32 FPUnsignedFixedToSingle(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); + + const IR::U8 fbits_imm = Imm8(static_cast(fbits)); + const IR::U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPFixedU16ToSingle, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPFixedU32ToSingle, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPFixedU64ToSingle, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U64 FPSignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); + + const IR::U8 fbits_imm = Imm8(static_cast(fbits)); + const IR::U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPFixedS16ToDouble, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPFixedS32ToDouble, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPFixedS64ToDouble, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U64 FPUnsignedFixedToDouble(const U16U32U64& a, size_t fbits, FP::RoundingMode rounding) { + ASSERT(fbits <= (a.GetType() == Type::U16 ? 16 : (a.GetType() == Type::U32 ? 32 : 64))); + + const IR::U8 fbits_imm = Imm8(static_cast(fbits)); + const IR::U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (a.GetType()) { + case Type::U16: + return Inst(Opcode::FPFixedU16ToDouble, a, fbits_imm, rounding_imm); + case Type::U32: + return Inst(Opcode::FPFixedU32ToDouble, a, fbits_imm, rounding_imm); + case Type::U64: + return Inst(Opcode::FPFixedU64ToDouble, a, fbits_imm, rounding_imm); + default: + UNREACHABLE(); + } + } + + U128 FPVectorAbs(size_t esize, const U128& a) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorAbs16, a); + case 32: + return Inst(Opcode::FPVectorAbs32, a); + case 64: + return Inst(Opcode::FPVectorAbs64, a); + } + UNREACHABLE(); + } + + U128 FPVectorAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorAdd32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorAdd64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorDiv(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorDiv32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorDiv64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorEqual16, a, b, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorEqual32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorEqual64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorFromHalf(size_t esize, const U128& a, FP::RoundingMode rounding, bool fpcr_controlled = true) { + ASSERT(esize == 32); + return Inst(Opcode::FPVectorFromHalf32, a, Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); + } + + U128 FPVectorFromSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true) { + ASSERT(fbits <= esize); + switch (esize) { + case 32: + return Inst(Opcode::FPVectorFromSignedFixed32, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorFromSignedFixed64, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorFromUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true) { + ASSERT(fbits <= esize); + switch (esize) { + case 32: + return Inst(Opcode::FPVectorFromUnsignedFixed32, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorFromUnsignedFixed64, a, Imm8(static_cast(fbits)), Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorGreater(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorGreater32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorGreater64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorGreaterEqual(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorGreaterEqual32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorGreaterEqual64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMax(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorMax32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMax64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMaxNumeric(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorMaxNumeric32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMaxNumeric64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMin(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorMin32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMin64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMinNumeric(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorMinNumeric32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMinNumeric64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMul(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorMul32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMul64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMulAdd(size_t esize, const U128& a, const U128& b, const U128& c, bool fpcr_controlled = true) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorMulAdd16, a, b, c, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorMulAdd32, a, b, c, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMulAdd64, a, b, c, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorMulX(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorMulX32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorMulX64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorNeg(size_t esize, const U128& a) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorNeg16, a); + case 32: + return Inst(Opcode::FPVectorNeg32, a); + case 64: + return Inst(Opcode::FPVectorNeg64, a); + } + UNREACHABLE(); + } + + U128 FPVectorPairedAdd(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorPairedAdd32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorPairedAdd64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorPairedAddLower(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorPairedAddLower32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorPairedAddLower64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorRecipEstimate(size_t esize, const U128& a, bool fpcr_controlled = true) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorRecipEstimate16, a, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorRecipEstimate32, a, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorRecipEstimate64, a, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorRecipStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorRecipStepFused16, a, b, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorRecipStepFused32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorRecipStepFused64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorRoundInt(size_t esize, const U128& operand, FP::RoundingMode rounding, bool exact, bool fpcr_controlled = true) { + const IR::U8 rounding_imm = Imm8(static_cast(rounding)); + const IR::U1 exact_imm = Imm1(exact); + + switch (esize) { + case 16: + return Inst(Opcode::FPVectorRoundInt16, operand, rounding_imm, exact_imm, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorRoundInt32, operand, rounding_imm, exact_imm, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorRoundInt64, operand, rounding_imm, exact_imm, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorRSqrtEstimate(size_t esize, const U128& a, bool fpcr_controlled = true) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorRSqrtEstimate16, a, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorRSqrtEstimate32, a, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorRSqrtEstimate64, a, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorRSqrtStepFused(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 16: + return Inst(Opcode::FPVectorRSqrtStepFused16, a, b, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorRSqrtStepFused32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorRSqrtStepFused64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorSqrt(size_t esize, const U128& a, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorSqrt32, a, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorSqrt64, a, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorSub(size_t esize, const U128& a, const U128& b, bool fpcr_controlled = true) { + switch (esize) { + case 32: + return Inst(Opcode::FPVectorSub32, a, b, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorSub64, a, b, Imm1(fpcr_controlled)); + } + UNREACHABLE(); + } + + U128 FPVectorToHalf(size_t esize, const U128& a, FP::RoundingMode rounding, bool fpcr_controlled = true) { + ASSERT(esize == 32); + return Inst(Opcode::FPVectorToHalf32, a, Imm8(static_cast(rounding)), Imm1(fpcr_controlled)); + } + + U128 FPVectorToSignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true) { + ASSERT(fbits <= esize); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (esize) { + case 16: + return Inst(Opcode::FPVectorToSignedFixed16, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorToSignedFixed32, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorToSignedFixed64, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); + } + + UNREACHABLE(); + } + + U128 FPVectorToUnsignedFixed(size_t esize, const U128& a, size_t fbits, FP::RoundingMode rounding, bool fpcr_controlled = true) { + ASSERT(fbits <= esize); + + const U8 fbits_imm = Imm8(static_cast(fbits)); + const U8 rounding_imm = Imm8(static_cast(rounding)); + + switch (esize) { + case 16: + return Inst(Opcode::FPVectorToUnsignedFixed16, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); + case 32: + return Inst(Opcode::FPVectorToUnsignedFixed32, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); + case 64: + return Inst(Opcode::FPVectorToUnsignedFixed64, a, fbits_imm, rounding_imm, Imm1(fpcr_controlled)); + } + + UNREACHABLE(); + } + + void Breakpoint() { + Inst(Opcode::Breakpoint); + } + + void CallHostFunction(void (*fn)(void)) { + Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), Value{}, Value{}, Value{}); + } + + void CallHostFunction(void (*fn)(u64), const U64& arg1) { + Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), arg1, Value{}, Value{}); + } + + void CallHostFunction(void (*fn)(u64, u64), const U64& arg1, const U64& arg2) { + Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), arg1, arg2, Value{}); + } + + void CallHostFunction(void (*fn)(u64, u64, u64), const U64& arg1, const U64& arg2, const U64& arg3) { + Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast(fn)), arg1, arg2, arg3); + } + + void SetTerm(const Terminal& terminal) { + block.SetTerminal(terminal); + } void SetInsertionPointBefore(IR::Inst* new_insertion_point) { insertion_point = IR::Block::iterator{*new_insertion_point}; diff --git a/externals/sirit/CMakeLists.txt b/externals/sirit/CMakeLists.txt index d98a8b5ba5..782ce8f660 100644 --- a/externals/sirit/CMakeLists.txt +++ b/externals/sirit/CMakeLists.txt @@ -1,6 +1,6 @@ # This file has been adapted from dynarmic -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) project(sirit CXX) # Determine if we're built as a subproject (using add_subdirectory) diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 8fc4a82088..d35caa8b4a 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -58,7 +58,7 @@ android { defaultConfig { // TODO If this is ever modified, change application_id in strings.xml - applicationId = "dev.eden.eden_emulator" + applicationId = "dev.legacy.eden_emulator" minSdk = 30 targetSdk = 35 versionName = getGitVersion() @@ -103,7 +103,7 @@ android { signingConfigs.getByName("default") } - resValue("string", "app_name_suffixed", "Eden") + resValue("string", "app_name_suffixed", "Eden Legacy") isMinifyEnabled = true isDebuggable = false proguardFiles( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index c7d6d6c33a..c0e5983fc6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -15,6 +15,7 @@ import android.view.Surface import android.view.View import android.widget.TextView import androidx.annotation.Keep +import androidx.core.net.toUri import com.google.android.material.dialog.MaterialAlertDialogBuilder import net.swiftzer.semver.SemVer import java.lang.ref.WeakReference @@ -27,6 +28,7 @@ import org.yuzu.yuzu_emu.model.InstallResult import org.yuzu.yuzu_emu.model.Patch import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.network.NetPlayManager +import java.io.File /** * Class which contains methods that interact @@ -102,6 +104,21 @@ object NativeLibrary { FileUtil.getFilename(Uri.parse(path)) } + @Keep + @JvmStatic + fun copyFileToStorage(source: String, destdir: String): Boolean { + return FileUtil.copyUriToInternalStorage( + source.toUri(), + destdir + ) != null + } + + @Keep + @JvmStatic + fun getFileExtension(source: String): String { + return FileUtil.getExtension(source.toUri()) + } + external fun setAppDirectory(directory: String) /** @@ -415,18 +432,29 @@ object NativeLibrary { */ external fun firmwareVersion(): String - fun isFirmwareSupported(): Boolean { - var version: SemVer + /** + * Verifies installed firmware. + * + * @return The result code. + */ + external fun verifyFirmware(): Int - try { - version = SemVer.parse(firmwareVersion()) - } catch (_: Exception) { - return false - } - val max = SemVer(19, 0, 1) + /** + * Check if a game requires firmware to be playable. + * + * @param programId The game's Program ID. + * @return Whether or not the game requires firmware to be playable. + */ + external fun gameRequiresFirmware(programId: String): Boolean - return version <= max - } + /** + * Installs keys from the specified path. + * + * @param path The path to install keys from. + * @param ext What extension the keys should have. + * @return The result code. + */ + external fun installKeys(path: String, ext: String): Int /** * Checks the PatchManager for any addons that are available diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 750e8f4729..c4652f55e1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -3,11 +3,16 @@ package org.yuzu.yuzu_emu.adapters +import android.content.DialogInterface import android.net.Uri +import android.text.Html +import android.text.method.LinkMovementMethod import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import android.widget.ImageView +import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.content.pm.ShortcutInfoCompat @@ -33,6 +38,10 @@ import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.ViewUtils.marquee import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import androidx.recyclerview.widget.RecyclerView +import androidx.core.net.toUri +import androidx.core.content.edit +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.yuzu.yuzu_emu.NativeLibrary class GameAdapter(private val activity: AppCompatActivity) : AbstractDiffAdapter(exact = false) { @@ -171,8 +180,9 @@ class GameAdapter(private val activity: AppCompatActivity) : fun onClick(game: Game) { val gameExists = DocumentFile.fromSingleUri( YuzuApplication.appContext, - Uri.parse(game.path) + game.path.toUri() )?.exists() == true + if (!gameExists) { Toast.makeText( YuzuApplication.appContext, @@ -184,29 +194,49 @@ class GameAdapter(private val activity: AppCompatActivity) : return } - val preferences = - PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - preferences.edit() - .putLong( - game.keyLastPlayedTime, - System.currentTimeMillis() - ) - .apply() - - activity.lifecycleScope.launch { - withContext(Dispatchers.IO) { - val shortcut = - ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path) - .setShortLabel(game.title) - .setIcon(GameIconUtils.getShortcutIcon(activity, game)) - .setIntent(game.launchIntent) - .build() - ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + val launch: () -> Unit = { + val preferences = + PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + preferences.edit { + putLong( + game.keyLastPlayedTime, + System.currentTimeMillis() + ) } + + activity.lifecycleScope.launch { + withContext(Dispatchers.IO) { + val shortcut = + ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path) + .setShortLabel(game.title) + .setIcon(GameIconUtils.getShortcutIcon(activity, game)) + .setIntent(game.launchIntent) + .build() + ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + } + } + + val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true) + binding.root.findNavController().navigate(action) } - val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true) - binding.root.findNavController().navigate(action) + if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) { + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.loader_requires_firmware) + .setMessage( + Html.fromHtml( + activity.getString(R.string.loader_requires_firmware_description), + Html.FROM_HTML_MODE_LEGACY + ) + ) + .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> + launch() + } + .setNegativeButton(android.R.string.cancel) { _,_ -> } + .show() + } else { + launch() + } } fun onLongClick(game: Game): Boolean { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt index 0c1e39d095..91670b207d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt @@ -264,8 +264,6 @@ class DriverFetcherFragment : Fragment() { } releases.add(release) - - println(release.publishTime) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt index f39d9514b3..5fed99e0b0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt @@ -137,7 +137,7 @@ class HomeSettingsFragment : Fragment() { binding.root.findNavController() .navigate(R.id.action_homeSettingsFragment_to_appletLauncherFragment) }, - { NativeLibrary.isFirmwareAvailable() && NativeLibrary.isFirmwareSupported() }, + { NativeLibrary.isFirmwareAvailable() }, R.string.applets_error_firmware, R.string.applets_error_description ) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt index 6443067885..61797f75f5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt @@ -352,7 +352,7 @@ class SetupFragment : Fragment() { val getProdKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> if (result != null) { - mainActivity.processKey(result) + mainActivity.processKey(result, "keys") if (NativeLibrary.areKeysPresent()) { keyCallback.onStepCompleted() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index 1a74057569..43b9085f50 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt @@ -47,9 +47,6 @@ import info.debatty.java.stringsimilarity.Jaccard import info.debatty.java.stringsimilarity.JaroWinkler import java.util.Locale import androidx.core.content.edit -import androidx.core.view.updateLayoutParams -import org.yuzu.yuzu_emu.features.settings.model.Settings -import android.view.ViewParent import androidx.core.view.doOnNextLayout class GamesFragment : Fragment() { @@ -151,7 +148,7 @@ class GamesFragment : Fragment() { ) } gamesViewModel.games.collect(viewLifecycleOwner) { - if (it.size > 0) { + if (it.isNotEmpty()) { setAdapter(it) } } @@ -361,7 +358,7 @@ class GamesFragment : Fragment() { popup.setOnMenuItemClickListener { item -> currentFilter = item.itemId - preferences.edit().putInt(PREF_SORT_TYPE, currentFilter).apply() + preferences.edit { putInt(PREF_SORT_TYPE, currentFilter) } filterAndSearch() true } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index f3800f94e9..6d9a2002f5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -6,6 +6,8 @@ package org.yuzu.yuzu_emu.ui.main import android.content.Intent import android.net.Uri import android.os.Bundle +import android.os.ParcelFileDescriptor +import android.provider.OpenableColumns import android.view.View import android.view.ViewGroup.MarginLayoutParams import android.view.WindowManager @@ -47,6 +49,7 @@ import java.io.BufferedOutputStream import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import androidx.core.content.edit +import androidx.core.net.toFile class MainActivity : AppCompatActivity(), ThemeProvider { private lateinit var binding: ActivityMainBinding @@ -70,10 +73,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val granted = permissions.entries.all { it.value } if (granted) { // Permissions were granted. - Toast.makeText(this, R.string.bluetooth_permissions_granted, Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.bluetooth_permissions_granted, Toast.LENGTH_SHORT) + .show() } else { // Permissions were denied. - Toast.makeText(this, R.string.bluetooth_permissions_denied, Toast.LENGTH_LONG).show() + Toast.makeText(this, R.string.bluetooth_permissions_denied, Toast.LENGTH_LONG) + .show() } } @@ -94,7 +99,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } } } - + override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } @@ -105,13 +110,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider { NativeLibrary.initMultiplayer() binding = ActivityMainBinding.inflate(layoutInflater) - + setContentView(binding.root) - - + + checkAndRequestBluetoothPermissions() - + if (savedInstanceState != null) { checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION) checkedFirmware = savedInstanceState.getBoolean(CHECKED_FIRMWARE) @@ -146,22 +151,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding.statusBarShade.setBackgroundColor( ThemeHelper.getColorWithOpacity( MaterialColors.getColor( - binding.root, - com.google.android.material.R.attr.colorSurface - ), - ThemeHelper.SYSTEM_BAR_ALPHA + binding.root, com.google.android.material.R.attr.colorSurface + ), ThemeHelper.SYSTEM_BAR_ALPHA ) ) - if (InsetsHelper.getSystemGestureType(applicationContext) != - InsetsHelper.GESTURE_NAVIGATION - ) { + if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) { binding.navigationBarShade.setBackgroundColor( ThemeHelper.getColorWithOpacity( MaterialColors.getColor( - binding.root, - com.google.android.material.R.attr.colorSurface - ), - ThemeHelper.SYSTEM_BAR_ALPHA + binding.root, com.google.android.material.R.attr.colorSurface + ), ThemeHelper.SYSTEM_BAR_ALPHA ) ) } @@ -172,9 +171,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) } homeViewModel.contentToInstall.collect( - this, - resetState = { homeViewModel.setContentToInstall(null) } - ) { + this, resetState = { homeViewModel.setContentToInstall(null) }) { if (it != null) { installContent(it) } @@ -183,7 +180,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { if (it) checkKeys() } - homeViewModel.checkFirmware.collect(this, resetState = { homeViewModel.setCheckFirmware(false) }) { + homeViewModel.checkFirmware.collect( + this, resetState = { homeViewModel.setCheckFirmware(false) }) { if (it) checkFirmware() } @@ -203,12 +201,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { negativeButtonTitleId = R.string.close, showNegativeButton = true, positiveAction = { - PreferenceManager.getDefaultSharedPreferences(applicationContext) - .edit() { - putBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_WARNING, false) - } - } - ).show(supportFragmentManager, MessageDialogFragment.TAG) + PreferenceManager.getDefaultSharedPreferences(applicationContext).edit() { + putBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_WARNING, false) + } + }).show(supportFragmentManager, MessageDialogFragment.TAG) } } @@ -228,15 +224,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } private fun checkFirmware() { - if (!NativeLibrary.isFirmwareAvailable() || !NativeLibrary.isFirmwareSupported()) { - MessageDialogFragment.newInstance( - titleId = R.string.firmware_missing, - descriptionId = R.string.firmware_missing_description, - helpLinkId = R.string.firmware_missing_help - ).show(supportFragmentManager, MessageDialogFragment.TAG) - } - } + val resultCode: Int = NativeLibrary.verifyFirmware() + if (resultCode == 0) return; + val resultString: String = + resources.getStringArray(R.array.verifyFirmwareResults)[resultCode] + + MessageDialogFragment.newInstance( + titleId = R.string.firmware_invalid, + descriptionString = resultString, + helpLinkId = R.string.firmware_missing_help + ).show(supportFragmentManager, MessageDialogFragment.TAG) + } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) @@ -283,23 +282,22 @@ class MainActivity : AppCompatActivity(), ThemeProvider { super.onResume() } - private fun setInsets() = - ViewCompat.setOnApplyWindowInsetsListener( - binding.root - ) { _: View, windowInsets: WindowInsetsCompat -> - val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) - val mlpStatusShade = binding.statusBarShade.layoutParams as MarginLayoutParams - mlpStatusShade.height = insets.top - binding.statusBarShade.layoutParams = mlpStatusShade + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( + binding.root + ) { _: View, windowInsets: WindowInsetsCompat -> + val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + val mlpStatusShade = binding.statusBarShade.layoutParams as MarginLayoutParams + mlpStatusShade.height = insets.top + binding.statusBarShade.layoutParams = mlpStatusShade - // The only situation where we care to have a nav bar shade is when it's at the bottom - // of the screen where scrolling list elements can go behind it. - val mlpNavShade = binding.navigationBarShade.layoutParams as MarginLayoutParams - mlpNavShade.height = insets.bottom - binding.navigationBarShade.layoutParams = mlpNavShade + // The only situation where we care to have a nav bar shade is when it's at the bottom + // of the screen where scrolling list elements can go behind it. + val mlpNavShade = binding.navigationBarShade.layoutParams as MarginLayoutParams + mlpNavShade.height = insets.bottom + binding.navigationBarShade.layoutParams = mlpNavShade - windowInsets - } + windowInsets + } override fun setTheme(resId: Int) { super.setTheme(resId) @@ -315,17 +313,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider { fun processGamesDir(result: Uri, calledFromGameFragment: Boolean = false) { contentResolver.takePersistableUriPermission( - result, - Intent.FLAG_GRANT_READ_URI_PERMISSION + result, Intent.FLAG_GRANT_READ_URI_PERMISSION ) val uriString = result.toString() val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString } if (folder != null) { Toast.makeText( - applicationContext, - R.string.folder_already_added, - Toast.LENGTH_SHORT + applicationContext, R.string.folder_already_added, Toast.LENGTH_SHORT ).show() return } @@ -334,72 +329,52 @@ class MainActivity : AppCompatActivity(), ThemeProvider { .show(supportFragmentManager, AddGameFolderDialogFragment.TAG) } - val getProdKey = - registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> - if (result != null) { - processKey(result) - } + val getProdKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> + if (result != null) { + processKey(result, "keys") } - - fun processKey(result: Uri): Boolean { - if (FileUtil.getExtension(result) != "keys") { - MessageDialogFragment.newInstance( - this, - titleId = R.string.reading_keys_failure, - descriptionId = R.string.install_prod_keys_failure_extension_description - ).show(supportFragmentManager, MessageDialogFragment.TAG) - return false - } - - contentResolver.takePersistableUriPermission( - result, - Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - - val dstPath = DirectoryInitialization.userDirectory + "/keys/" - if (FileUtil.copyUriToInternalStorage( - result, - dstPath, - "prod.keys" - ) != null - ) { - if (NativeLibrary.reloadKeys()) { - Toast.makeText( - applicationContext, - R.string.install_keys_success, - Toast.LENGTH_SHORT - ).show() - homeViewModel.setCheckKeys(true) - - val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext) - .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true) - if (!firstTimeSetup) { - homeViewModel.setCheckFirmware(true) - } - - gamesViewModel.reloadGames(true) - return true - } else { - MessageDialogFragment.newInstance( - this, - titleId = R.string.invalid_keys_error, - descriptionId = R.string.install_keys_failure_description, - helpLinkId = R.string.dumping_keys_quickstart_link - ).show(supportFragmentManager, MessageDialogFragment.TAG) - return false - } - } - return false } - val getFirmware = - registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> - if (result == null) { - return@registerForActivityResult - } + val getAmiiboKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> + if (result != null) { + processKey(result, "bin") + } + } + fun processKey(result: Uri, extension: String = "keys") { + contentResolver.takePersistableUriPermission( + result, Intent.FLAG_GRANT_READ_URI_PERMISSION + ) + + val resultCode: Int = NativeLibrary.installKeys(result.toString(), extension); + + if (resultCode == 0) { + // TODO(crueter): It may be worth it to switch some of these Toasts to snackbars, + // since most of it is foreground-only anyways. + Toast.makeText( + applicationContext, R.string.keys_install_success, Toast.LENGTH_SHORT + ).show() + + gamesViewModel.reloadGames(true) + + return + } + + val resultString: String = + resources.getStringArray(R.array.installKeysResults)[resultCode] + + MessageDialogFragment.newInstance( + titleId = R.string.keys_failed, + descriptionString = resultString, + helpLinkId = R.string.keys_missing_help + ).show(supportFragmentManager, MessageDialogFragment.TAG) + } + + val getFirmware = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> + if (result != null) { processFirmware(result) } + } fun processFirmware(result: Uri, onComplete: (() -> Unit)? = null) { val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") } @@ -409,15 +384,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val cacheFirmwareDir = File("${cacheDir.path}/registered/") ProgressDialogFragment.newInstance( - this, - R.string.firmware_installing + this, R.string.firmware_installing ) { progressCallback, _ -> var messageToShow: Any try { FileUtil.unzipToInternalStorage( - result.toString(), - cacheFirmwareDir, - progressCallback + result.toString(), cacheFirmwareDir, progressCallback ) val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1 val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2 @@ -448,10 +420,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } fun uninstallFirmware() { - val firmwarePath = File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/") + val firmwarePath = + File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/") ProgressDialogFragment.newInstance( - this, - R.string.firmware_uninstalling + this, R.string.firmware_uninstalling ) { progressCallback, _ -> var messageToShow: Any try { @@ -473,49 +445,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { messageToShow }.show(supportFragmentManager, ProgressDialogFragment.TAG) } - val getAmiiboKey = - registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> - if (result == null) { - return@registerForActivityResult - } - - if (FileUtil.getExtension(result) != "bin") { - MessageDialogFragment.newInstance( - this, - titleId = R.string.reading_keys_failure, - descriptionId = R.string.install_amiibo_keys_failure_extension_description - ).show(supportFragmentManager, MessageDialogFragment.TAG) - return@registerForActivityResult - } - - contentResolver.takePersistableUriPermission( - result, - Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - - val dstPath = DirectoryInitialization.userDirectory + "/keys/" - if (FileUtil.copyUriToInternalStorage( - result, - dstPath, - "key_retail.bin" - ) != null - ) { - if (NativeLibrary.reloadKeys()) { - Toast.makeText( - applicationContext, - R.string.install_keys_success, - Toast.LENGTH_SHORT - ).show() - } else { - MessageDialogFragment.newInstance( - this, - titleId = R.string.invalid_keys_error, - descriptionId = R.string.install_keys_failure_description, - helpLinkId = R.string.dumping_keys_quickstart_link - ).show(supportFragmentManager, MessageDialogFragment.TAG) - } - } - } val installGameUpdate = registerForActivityResult( ActivityResultContracts.OpenMultipleDocuments() @@ -530,15 +459,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } ProgressDialogFragment.newInstance( - this@MainActivity, - R.string.verifying_content, - false + this@MainActivity, R.string.verifying_content, false ) { _, _ -> var updatesMatchProgram = true for (document in documents) { val valid = NativeLibrary.doesUpdateMatchProgram( - addonViewModel.game!!.programId, - document.toString() + addonViewModel.game!!.programId, document.toString() ) if (!valid) { updatesMatchProgram = false @@ -554,16 +480,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider { titleId = R.string.content_install_notice, descriptionId = R.string.content_install_notice_description, positiveAction = { homeViewModel.setContentToInstall(documents) }, - negativeAction = {} - ) + negativeAction = {}) } }.show(supportFragmentManager, ProgressDialogFragment.TAG) } private fun installContent(documents: List) { ProgressDialogFragment.newInstance( - this@MainActivity, - R.string.installing_game_content + this@MainActivity, R.string.installing_game_content ) { progressCallback, messageCallback -> var installSuccess = 0 var installOverwrite = 0 @@ -571,14 +495,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider { var error = 0 documents.forEach { messageCallback.invoke(FileUtil.getFilename(it)) - when ( - InstallResult.from( - NativeLibrary.installFileToNand( - it.toString(), - progressCallback - ) + when (InstallResult.from( + NativeLibrary.installFileToNand( + it.toString(), progressCallback ) - ) { + )) { InstallResult.Success -> { installSuccess += 1 } @@ -599,13 +520,12 @@ class MainActivity : AppCompatActivity(), ThemeProvider { addonViewModel.refreshAddons() - val separator = System.getProperty("line.separator") ?: "\n" + val separator = System.lineSeparator() ?: "\n" val installResult = StringBuilder() if (installSuccess > 0) { installResult.append( getString( - R.string.install_game_content_success_install, - installSuccess + R.string.install_game_content_success_install, installSuccess ) ) installResult.append(separator) @@ -613,8 +533,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { if (installOverwrite > 0) { installResult.append( getString( - R.string.install_game_content_success_overwrite, - installOverwrite + R.string.install_game_content_success_overwrite, installOverwrite ) ) installResult.append(separator) @@ -624,8 +543,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { installResult.append(separator) installResult.append( getString( - R.string.install_game_content_failed_count, - errorTotal + R.string.install_game_content_failed_count, errorTotal ) ) installResult.append(separator) @@ -666,9 +584,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } ProgressDialogFragment.newInstance( - this, - R.string.exporting_user_data, - true + this, R.string.exporting_user_data, true ) { progressCallback, _ -> val zipResult = FileUtil.zipFromInternalStorage( File(DirectoryInitialization.userDirectory!!), @@ -692,8 +608,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } ProgressDialogFragment.newInstance( - this, - R.string.importing_user_data + this, R.string.importing_user_data ) { progressCallback, _ -> val checkStream = ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result))) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt index 81943e9235..99f7fd81fe 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -177,6 +180,10 @@ object GpuDriverHelper { * @return A non-null [GpuDriverMetadata] instance that may have null members */ fun getMetadataFromZip(driver: File): GpuDriverMetadata { + if (!driver.exists()) { + return GpuDriverMetadata() + } + try { ZipFile(driver).use { zf -> val entries = zf.entries() diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index fe7c0658d4..9fed0b1449 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -60,6 +60,7 @@ #include "core/hle/service/set/system_settings_server.h" #include "core/loader/loader.h" #include "frontend_common/config.h" +#include "frontend_common/firmware_manager.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" @@ -283,6 +284,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string : Service::AM::LaunchType::ApplicationInitiated, .program_index = static_cast(program_index), }; + m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params); if (m_load_result != Core::SystemResultStatus::Success) { return m_load_result; @@ -764,35 +766,19 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass cl } bool isFirmwarePresent() { - auto bis_system = - EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents(); - if (!bis_system) { - return false; - } - - // Query an applet to see if it's available - auto applet_nca = - bis_system->GetEntry(0x010000000000100Dull, FileSys::ContentRecordType::Program); - if (!applet_nca) { - return false; - } - return true; + return FirmwareManager::CheckFirmwarePresence(EmulationSession::GetInstance().System()); } jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env, jclass clazz) { return isFirmwarePresent(); } -// TODO(crueter): This check is nonfunctional... jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclass clazz) { - Service::Set::FirmwareVersionFormat firmware_data{}; - const auto result = Service::Set::GetFirmwareVersionImpl( - firmware_data, EmulationSession::GetInstance().System(), - Service::Set::GetFirmwareVersionType::Version2); + const auto pair = FirmwareManager::GetFirmwareVersion(EmulationSession::GetInstance().System()); + const auto firmware_data = pair.first; + const auto result = pair.second; if (result.IsError() || !isFirmwarePresent()) { - LOG_INFO(Frontend, "Installed firmware: No firmware available"); - return Common::Android::ToJString(env, "N/A"); } @@ -804,6 +790,23 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclas return Common::Android::ToJString(env, display_version); } +jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyFirmware(JNIEnv* env, jclass clazz) { + return static_cast(FirmwareManager::VerifyFirmware(EmulationSession::GetInstance().System())); +} + +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_gameRequiresFirmware(JNIEnv* env, jclass clazz, jstring jprogramId) { + auto program_id = EmulationSession::GetProgramId(env, jprogramId); + + return FirmwareManager::GameRequiresFirmware(program_id); +} + +jint Java_org_yuzu_yuzu_1emu_NativeLibrary_installKeys(JNIEnv* env, jclass clazz, jstring jpath, jstring jext) { + const auto path = Common::Android::GetJString(env, jpath); + const auto ext = Common::Android::GetJString(env, jext); + + return static_cast(FirmwareManager::InstallKeys(path, ext)); +} + jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj, jstring jpath, jstring jprogramId) { diff --git a/src/android/app/src/main/res/drawable/ic_icon_bg.png b/src/android/app/src/main/res/drawable/ic_icon_bg.png new file mode 100644 index 0000000000..30b29a32d8 Binary files /dev/null and b/src/android/app/src/main/res/drawable/ic_icon_bg.png differ diff --git a/src/android/app/src/main/res/drawable/ic_icon_bg.xml b/src/android/app/src/main/res/drawable/ic_icon_bg.xml deleted file mode 100644 index b409a61ea2..0000000000 --- a/src/android/app/src/main/res/drawable/ic_icon_bg.xml +++ /dev/null @@ -1,952 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/ic_icon_bg_orig.png b/src/android/app/src/main/res/drawable/ic_icon_bg_orig.png new file mode 100644 index 0000000000..9ebc6ce17c Binary files /dev/null and b/src/android/app/src/main/res/drawable/ic_icon_bg_orig.png differ diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index 4ea8b30c1e..e100bafe7e 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -349,13 +349,7 @@ إلغاء تثبيت مفاتيح أميبو مطلوب لاستخدام أميبو في اللعبة - تم تحديد ملف مفاتيح غير صالح - تم تثبيت المفاتيح بنجاح - خطأ في قراءة مفاتيح التشفير - وحاول مرة أخر keys تحقق من أن ملف المفاتيح له امتداد وحاول مرة أخر bin تحقق من أن ملف المفاتيح له امتداد - مفاتيح التشفير غير صالحة - الملف المحدد غير صحيح أو تالف. يرجى إعادة المفاتيح الخاصة بك GPU مدير برنامج تشغيل GPU تثبيت برنامج تشغيل قم بتثبيت برامج تشغيل بديلة للحصول على أداء أو دقة أفضل @@ -422,8 +416,6 @@ فحص المحتوى المثبت بحثًا عن تلف مفاتيح التشفير مفقودة لا يمكن فك تشفير البرنامج الثابت والألعاب - البرنامج الثابت مفقود أو جديد جدًا - بعض الألعاب قد لا تعمل بشكل صحيح. يتطلب إيدن البرنامج الثابت 19.0.1 أو أقل. Qlaunch diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index af4f2056b3..d13f24d173 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -344,13 +344,7 @@ ڕەتکردنەوە دامەزراندنی کلیلی Amiibo پێویستە بۆ بەکارهێنانی Amiibo لە یاریدا - فایلی کلیلێکی نادروست هەڵبژێردرا - کلیلەکان بە سەرکەوتوویی دامەزران - هەڵە لە خوێندنەوەی کۆدکردنی کلیل - دڵنیابەوە کە فایلی کلیلەکانت درێژکراوەی .keys ی هەیە و دووبارە هەوڵبدەرەوە. دڵنیابە کە فایلی کلیلەکانت درێژکراوەی .bin ی هەیە و دووبارە هەوڵبدەرەوە. - کلیلی کۆدکردنی نادروستە - فایلە هەڵبژێردراوەکە هەڵەیە یان تێکچووە. تکایە دووبارە کلیلەکانت دەربێنەوە. دامەزراندنی وەگەڕخەری GPU دامەزراندنی وەگەڕخەری بەدیل بۆ ئەوەی بە ئەگەرێکی زۆرەوە کارایی باشتر یان وردبینی هەبێت ڕێکخستنە پێشکەوتووەکان @@ -416,8 +410,6 @@ هەموو ناوەڕۆکی دامەزراو پشکنین دەکات بۆ تێکچوون کلیلە کۆدکراوەکان دیار نییە پتەوواڵا و یارییە تاکەکەسییەکان ناتوانرێت کۆد بکرێنەوە - فریموێر بوونی نییە یان زۆر نوێە - هەندێ یاری لەوانەیە باش کار نەکەن. ئێدەن پێویستی بە فریموێری ١٩.٠.١ یان کەمترە. Qlaunch diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index c71ea42f75..fe8575512e 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -333,10 +333,6 @@ Zrušit Instalovat Amiibo klíče Povinné použití Amiibo ve hře - Vybrané klíče jsou neplatné - Klíče úspěšně nainstalovány - Chyba při čtení šifrovacích klíčů - Neplatné šifrovací klíče Správce ovladače GPU Instalovat GPU ovladač Pokročilé nastavení @@ -380,8 +376,6 @@ Kontrola poškození obsahu Chybí šifrovací klíče Firmware a retail hry nelze dešifrovat - Firmware chybí nebo je příliš nový - Některé hry nemusí fungovat správně. Eden vyžaduje firmware 19.0.1 nebo nižší. Qlaunch diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 06b14f7c15..93881eabb5 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -346,13 +346,7 @@ Abbrechen Amiibo-Schlüssel installieren Benötigt um Amiibos im Spiel zu verwenden - Ungültige Schlüsseldatei ausgewählt - Schlüssel erfolgreich installiert - Fehler beim Lesen der Schlüssel - Überprüfen Sie, ob Ihre Schlüsseldatei die Erweiterung \".keys\" hat, und versuchen Sie es erneut. Überprüfen Sie, ob Ihre Schlüsseldatei die Erweiterung \".bin\" hat, und versuchen Sie es erneut. - Ungültige Schlüssel - Die ausgewählte Datei ist falsch oder beschädigt. Bitte kopieren Sie Ihre Schlüssel erneut. GPU-Treiber Verwaltung GPU-Treiber installieren Alternative Treiber für eventuell bessere Leistung oder Genauigkeit installieren @@ -415,8 +409,6 @@ Wirklich fortfahren? Überprüft installierte Inhalte auf Fehler Schlüssel fehlen Firmware und Spiele können nicht entschlüsselt werden - Firmware fehlt oder ist zu neu - Einige Spiele funktionieren möglicherweise nicht richtig. Eden erfordert Firmware 19.0.1 oder älter. Qlaunch diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 9cac800975..a55bf4d935 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -347,13 +347,7 @@ Cancelar Instalar claves de Amiibo Necesario para usar Amiibos en el juego - Archivo de claves seleccionado no válido - Claves instaladas correctamente - Error al leer las claves de cifrado - Compruebe que el archivo de claves tenga una extensión .keys y pruebe otra vez. Compruebe que el archivo de claves tenga una extensión .bin y pruebe otra vez. - Claves de cifrado no válidas - El archivo seleccionado es incorrecto o está corrupto. Vuelva a redumpear sus claves. Explorador de drivers de GPU Instalar driver de GPU Instale drivers alternativos para obtener un rendimiento o una precisión potencialmente mejores @@ -428,8 +422,6 @@ Comprueba todo el contenido instalado por si hubiese alguno corrupto Faltan las claves de encriptación El firmware y los juegos no se pueden desencriptar - Falta el firmware o es demasiado nuevo - Algunos juegos pueden no funcionar correctamente. Eden requiere firmware 19.0.1 o inferior. Qlaunch diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 48f024322b..99f48c1c9d 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -347,13 +347,7 @@ لغو کلیدهای Amiibo را نصب کنید برای استفاده از Amiibo در بازی لازم است - فایل کلیدهای نامعتبر انتخاب شد - کلیدها با موفقیت نصب شدند - خطا در خواندن کلیدهای رمزگذاری - بررسی کنید که فایل کلیدهای شما دارای پسوند keys. باشد و دوباره امتحان کنید. بررسی کنید که فایل کلیدهای شما دارای پسوند bin. باشد و دوباره امتحان کنید. - کلیدهای رمزگذاری نامعتبر - فایل انتخابی نادرست یا خراب است. لطفا کلیدهای خود را دوباره استخراج کنید. مدیریت درایور پردازنده گرافیکی نصب درایور پردازنده گرافیکی درایورهای جایگزین را برای عملکرد یا دقت بهتر نصب کنید @@ -426,8 +420,6 @@ تمام محتوای نصب شده را از نظر خرابی بررسی می‌کند کلیدهای رمزگذاری وجود ندارند ثابت‌افزار و بازی‌های فروشگاهی قابل رمزگشایی نیستند - فریمور وجود ندارد یا خیلی جدید است - برخی بازی‌ها ممکن است به درستی کار نکنند. ایدن به فریمور نسخه 19.0.1 یا پایین‌تر نیاز دارد. Qlaunch diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index f8ace84f1f..d9783766fe 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -347,13 +347,7 @@ Annuler Installer les clés Amiibo Nécessaire pour utiliser les Amiibo en jeu - Fichier de clés sélectionné invalide - Clés installées avec succès - Erreur lors de la lecture des clés de chiffrement - Vérifiez que votre fichier de clés a une extension .keys et réessayez. Vérifiez que votre fichier de clés a une extension .bin et réessayez. - Clés de chiffrement invalides - Le fichier sélectionné est incorrect ou corrompu. Veuillez dumper à nouveau vos clés. Gestionnaire de pilotes du GPU Installer le pilote du GPU Installer des pilotes alternatifs pour des performances ou une précision potentiellement meilleures @@ -428,8 +422,6 @@ Vérifie l\'intégrité des contenus installés Les clés de chiffrement sont manquantes. Le firmware et les jeux commerciaux ne peuvent pas être déchiffrés - Firmware manquant ou trop récent - Certains jeux peuvent ne pas fonctionner correctement. Eden nécessite le firmware 19.0.1 ou antérieur. Qlaunch diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 711b71d3ed..47a01d7dbd 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -348,13 +348,7 @@ ביטול התקן מפתחות Amiibo נחוץ כדי להשתמש ב Amiibo במשחק - קובץ מפתחות לא חוקי נבחר - מפתחות הותקנו בהצלחה - שגיאה בקריאת מפתחות ההצפנה - ודא שלקובץ המפתחות שלך יש סיומת של key. ונסה/י שוב. ודא/י שלקובץ המפתחות שלך יש סיומת של bin. ונסה/י שוב. - מפתחות הצפנה לא חוקיים - קבוץ שנבחר מושחת או לא נכון. בבקשה הוצא מחדש את המפתחות שלך. מנהל הדרייברים של המעבד הגרפי התקן דרייבר למעבד הגרפי התקן דרייברים אחרים בשביל סיכוי לביצועים או דיוק גבוההים יותר @@ -427,8 +421,6 @@ בודק תוכן מותקן לשגיאות מפתחות הצפנה חסרים לא ניתן לפענח firmware ומשחקים - קושחה חסרה או חדשה מדי - חלק מהמשחקים עשויים לא לפעול כראוי. Eden דורש קושחה בגרסה 19.0.1 או נמוכה יותר. Qlaunch diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 0bedc72e29..e14af511c6 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -346,13 +346,7 @@ Mégse Amiibo kulcsok telepítése Amiibo használata szükséges a játékhoz - Érvénytelen titkosítófájlok kiválasztva - Kulcsok sikeresen telepítve - Hiba történt a titkosítókulcsok olvasása során - Győződj meg róla, hogy a titkosító fájlod .keys kiterjesztéssel rendelkezik, majd próbáld újra. Győződj meg róla, hogy a titkosító fájlod .bin kiterjesztéssel rendelkezik, majd próbáld újra. - Érvénytelen titkosítókulcsok - A kiválasztott fájl helytelen, vagy sérült. Állíts össze egy új kulcsot. GPU illesztőprogram-kezelő GPU illesztőprogram telepítése Alternatív illesztőprogramok telepítése az esetlegesen elérhető teljesítmény és pontosság érdekében @@ -424,8 +418,6 @@ A telepített tartalom épségét ellenőrzi Hiányzó titkosítókulcsok A Firmware és a kiskereskedelmi (retail) játékok nem dekódolhatók - Hiányzó vagy túl új firmware - Néhány játék nem fog megfelelően működni. Az Eden 19.0.1 vagy régebbi firmware-t igényel. Qlaunch diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index 542734e451..2d931d2c5d 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -347,13 +347,7 @@ Batalkan Install Amiibo keys Diperlukan untuk menggunakan Amiibo di dalam game - Keys yang dipilih invalid - Keys berhasil diinstal - Error saat mengecek enkripsi keys - Pastikan file keys anda memiliki format .keys dan coba lagi. Pastikan file keys anda memiliki format .bin dan coba lagi. - Keys enkripsi tidak valid - File yang dipilih salah atau rusak. Silakan masukkan kembali kunci Anda. Manajer driver GPU Install driver GPU Instal driver lain untuk kinerja atau akurasi yang berpotensi lebih baik @@ -424,8 +418,6 @@ Memeriksa semua konten yang terinstal dari kerusakan Kunci enkripsi hilang Firmware dan game retail tidak dapat didekripsi - Firmware hilang atau terlalu baru - Beberapa game mungkin tidak berfungsi dengan baik. Eden memerlukan firmware 19.0.1 atau lebih rendah. Qlaunch diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index ad5b9f62cf..33a937ca93 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -348,13 +348,7 @@ Annulla Installa le chiavi degli Amiibo Necessario per usare gli Amiibo in gioco - Selezionate chiavi non valide - Chiavi installate correttamente - Errore durante la lettura delle chiavi di crittografia - Controlla che le tue chiavi abbiano l\'estensione .keys e prova di nuovo. Controlla che le tue chiavi abbiano l\'estensione .bin e prova di nuovo - Chiavi di crittografia non valide - Il file selezionato è incorretto o corrotto. Per favore riesegui il dump delle tue chiavi. Gestore driver GPU Installa i driver GPU Installa driver alternativi per potenziali prestazioni migliori o accuratezza. @@ -427,8 +421,6 @@ Verifica l\'integrità di tutti i contenuti installati. Chiavi di crittografia mancanti Impossibile decifrare firmware e giochi retail - Firmware mancante o troppo recente - Alcuni giochi potrebbero non funzionare correttamente. Eden richiede il firmware 19.0.1 o precedente. Qlaunch diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index b209943135..c8d23cb6b9 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -346,13 +346,7 @@ キャンセル Amiibo ゲーム内での Amiibo の使用に必要です - 無効なキーファイルです - 正常にインストールされました - 暗号化キーの読み込み失敗 - キーの拡張子が.keysであることを確認し、再度お試しください。 キーの拡張子が.binであることを確認し、再度お試しください。 - 暗号化キーが無効 - ファイルが間違っているか破損しています。キーを再ダンプしてください。 GPUドライバーの管理 GPUドライバー 代替ドライバーをインストールしてパフォーマンスや精度を向上させます @@ -417,8 +411,6 @@ すべてのインストール済みコンテンツの整合性を確認 暗号化キーが不足 ファームウェアと製品版ゲームを復号化できません - ファームウェアがないか、バージョンが新しすぎます - 一部のゲームが正常に動作しない可能性があります。Edenは19.0.1以下のファームウェアが必要です。 Qlaunch diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index 595795570f..deb901fc3f 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -346,13 +346,7 @@ 취소 amiibo 키 설치 게임에서 amiibo 사용 시 필요 - 잘못된 키 파일이 선택됨 - 키 값을 설치했습니다. - 암호화 키 읽기 오류 - 키 파일의 확장자가 .keys인지 확인하고 다시 시도하세요. 키 파일의 확장자가 .bin인지 확인하고 다시 시도하세요. - 암호화 키가 올바르지 않음 - 선택한 파일이 잘못되었거나 손상되었습니다. 키를 다시 덤프하세요. GPU 드라이버 관리자 GPU 드라이버 설치 잠재적인 성능 또는 정확도 개선을 위해 대체 드라이버 설치 @@ -423,8 +417,6 @@ 전체 설치된 콘텐츠의 손상을 확인합니다. 암호화 키를 찾을 수 없음 펌웨어 및 패키지 게임을 해독할 수 없음 - 펌웨어가 없거나 버전이 너무 높습니다 - 일부 게임이 제대로 작동하지 않을 수 있습니다. Eden은 19.0.1 이하 버전의 펌웨어가 필요합니다. Qlaunch diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 82a4601e65..80173a357d 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -344,13 +344,7 @@ Avbryt Installer Amiibo-nøkler Kreves for å bruke Amiibo i spillet - Ugyldig nøkkelfil valgt - Nøkler vellykket installert - Feil ved lesing av krypteringsnøkler - Kontroller at nøkkelfilen har filtypen .keys, og prøv igjen. Kontroller at nøkkelfilen har filtypen .bin, og prøv igjen. - Ugyldige krypteringsnøkler - Den valgte filen er feil eller ødelagt. Vennligst dump nøklene på nytt. Installer GPU-driver Installer alternative drivere for potensielt bedre ytelse eller nøyaktighet. Avanserte innstillinger @@ -416,8 +410,6 @@ Sjekk for korrupsjon Nøkler mangler Kan ikke dekryptere firmware/spill - Firmware mangler eller er for ny - Noen spill fungerer kanskje ikke skikkelig. Eden krever firmware 19.0.1 eller lavere. Qlaunch diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index 394de5fb16..4742f795c8 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -344,13 +344,7 @@ Anuluj Zainstaluj klucze Amiibo Wymagane aby korzystać z Amiibo w grze - Wybrano niepoprawne klucze - Klucze zainstalowane pomyślnie - Błąd podczas odczytu kluczy - Upewnij się że twoje klucze mają rozszerzenie .keys i spróbuj ponownie. Upewnij się że twoje klucze mają rozszerzenie .bin i spróbuj ponownie. - Niepoprawne klucze - Wybrany plik jest niepoprawny lub uszkodzony. Zrzuć ponownie swoje klucze. Zainstaluj sterownik GPU Użyj alternatywnych sterowników aby potencjalnie zwiększyć wydajność i naprawić błędy Ustawienia zaawansowane @@ -416,8 +410,6 @@ Sprawdza integralność zainstalowanych plików. Brak kluczy Firmware i gry nie mogą być odszyfrowane. - Brak firmware lub zbyt nowa wersja - Niektóre gry mogą nie działać poprawnie. Eden wymaga firmware w wersji 19.0.1 lub starszej. Qlaunch diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index 46778754ee..a886450e47 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -347,13 +347,7 @@ Cancelar Instalar chaves Amiibo Necessárias para usar Amiibos em um jogo - Arquivo de chaves selecionado inválido - Chaves instaladas com sucesso - Erro ao ler chaves de encriptação - Verifique se seu arquivo de chaves possui a extensão .keys e tente novamente. Verifique se seu arquivo de chaves possui a extensão .bin e tente novamente. - Chaves de encriptação inválidas - O arquivo selecionado está incorreto ou corrompido. Por favor extraia suas chaves novamente. Gerenciador de driver de GPU Instalar driver para GPU Instale drivers alternativos para desempenho ou precisão potencialmente melhores @@ -428,8 +422,6 @@ Verifica todo o conteúdo instalado em busca de dados corrompidos Faltando chaves de encriptação O firmware e jogos comerciais não poderão ser decriptados - Firmware ausente ou muito recente - Alguns jogos podem não funcionar corretamente. O Eden requer firmware 19.0.1 ou inferior. Qlaunch diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 2da6518d48..caf7090993 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -347,13 +347,7 @@ Cancelar Instala chaves Amiibo Necessário para usares Amiibo no jogo - Ficheiro de chaves inválido - Chaves instaladas com sucesso - Erro ao ler chaves de encriptação - Verifique se seu arquivo keys possui a extensão .keys e tente novamente. Verifique se seu arquivo keys possui a extensão .bin e tente novamente. - Chaves de encriptação inválidas - O ficheiro selecionado está corrompido. Por favor recarrega as tuas chaves. Gerenciador de driver de GPU Instala driver para GPU Instala drivers alternativos para desempenho ou precisão potencialmente melhores @@ -428,8 +422,6 @@ Verifica todo o conteúdo instalado em busca de dados corrompidos Faltando chaves de encriptação O firmware e jogos comerciais não poderão ser decriptados - Firmware em falta ou demasiado recente - Alguns jogos podem não funcionar corretamente. O Eden requer firmware versão 19.0.1 ou inferior. Qlaunch diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index b9f146aa84..3d8371324f 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -346,13 +346,7 @@ Отмена Установить ключи Amiibo Необходимо для использования Amiibo в играх - Выбран неверный файл ключей - Ключи успешно установлены - Ошибка при чтении ключей шифрования - Убедитесь, что файл ключей имеет расширение .keys, и повторите попытку. Убедитесь, что файл ключей имеет расширение .bin, и повторите попытку. - Неверные ключи шифрования - Выбранный файл неверен или поврежден. Пожалуйста, пере-дампите ваши ключи. Менеджер драйверов ГП Установить драйвер ГП Установите альтернативные драйверы для потенциально лучшей производительности и/или точности @@ -430,8 +424,6 @@ Проверяет весь установленный контент на наличие повреждений Отсутствуют ключи шифрования Прошивка и розничные игры не могут быть расшифрованы - Прошивка отсутствует или слишком новая - Некоторые игры могут работать некорректно. Eden требует прошивку версии 19.0.1 или ниже. Qlaunch diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 0217819b68..d133a470b2 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -298,13 +298,7 @@ Отказати Инсталирајте Амиибо Кеис Потребно је користити Амиибо у игри - Изабрана је неважећа датотека тастера - Кључеви су успешно инсталирани - Грешка приликом чишћења кључева за шифровање - Проверите да датотека кључева има. Екеис Ектенсион и покушајте поново. Проверите да датотека кључева има .бин екстензију и покушајте поново. - Неважеће кључеве за шифровање - Изабрана датотека је нетачна или оштећена. Молим вас да вам умањите кључеве. ГПУ возач фетцхер ГПУ управљач возача Инсталирајте ГПУ драјвер @@ -380,8 +374,6 @@ Шифра о шифрирањима недостају Фирмваре и малопродајне игре не могу се дешифровати - Фирмвер недостаје или је превише нов - Неке игре можда неће радити исправно. Eden захтева фирмвер верзије 19.0.1 или старији. Клаунцх diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index c2ab22b0d4..91b600eded 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -344,12 +344,6 @@ Відміна Встановити ключі Amiibo Необхідно для використання Amiibo в іграх - Вибрано неправильний файл ключів - Ключі успішно встановлено - Помилка під час зчитування ключів шифрування - Переконайтеся, що файл ключів має розширення .keys, і повторіть спробу. - Невірні ключі шифрування - Обраний файл невірний або пошкоджений. Будь ласка, зробіть повторний дамп ваших ключів. Встановити драйвер GPU Встановіть альтернативні драйвери для потенційно кращої продуктивності та/або точності Розширені налаштування @@ -415,8 +409,6 @@ Перевіряє встановлений вміст на наявність помилок. Відсутні ключі Прошивку та роздрібні ігри не вдасться розшифрувати. - Прошивка відсутня або занадто нова - Деякі ігри можуть працювати неправильно. Eden вимагає прошивку версії 19.0.1 або нижче. Qlaunch diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index 75a797a386..87de8e80dc 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -344,13 +344,7 @@ Huỷ Cài đặt Amiibo Cần thiết để dùng Amiibo trong trò chơi - Chìa khóa không hợp lệ - Cài đặt chìa khóa thành công - Lỗi đọc keys mã hóa - Xác minh rằng tệp keys của bạn có đuôi .keys và thử lại. Xác minh rằng tệp keys của bạn có đuôi .bin và thử lại. - Keys mã hoá không hợp lệ - Chọn file sai hoặc bị hỏng. Hãy xuất chìa khóa khác Cài đặt driver GPU Cài đặt driver thay thế để có thể có hiệu suất tốt và chính xác hơn Cài đặt nâng cao @@ -416,8 +410,6 @@ Kiểm tra lỗi nội dung đã cài Thiếu keys mã hóa Không thể giải mã firmware và game - Thiếu firmware hoặc phiên bản quá mới - Một số trò chơi có thể không hoạt động bình thường. Eden yêu cầu firmware phiên bản 19.0.1 hoặc thấp hơn. Qlaunch diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index 534b2a322d..20f9bdea90 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -346,13 +346,7 @@ 取消 安装 Amiibo 密钥文件 在遊戏中使用 Amiibo 时必需 - 选择的密钥文件无效 - 密钥文件已成功安装 - 读取加密密钥时出错 - 请确保您的密钥文件扩展名为 .keys 并重试。 请确保您的密钥文件扩展名为 .bin 并重试。 - 无效的加密密钥 - 选择的密钥文件不正确或已损坏。请重新转储密钥文件。 GPU 驱动管理器 安装 GPU 驱动 安装替代的驱动程序以获得更好的性能和精度 @@ -423,8 +417,6 @@ 检查所有安装的内容是否有损坏 密钥缺失 无法解密固件和商业游戏 - 固件缺失或版本过新 - 某些游戏可能无法正常运行。Eden需要19.0.1或更低版本的固件。 Qlaunch diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 5c4494c9aa..dcda2d8260 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -350,13 +350,7 @@ 取消 安裝 Amiibo 金鑰 需要在遊戲中使用 Amiibo - 無效的金鑰檔案已選取 - 金鑰已成功安裝 - 讀取加密金鑰時發生錯誤 - 驗證您的金鑰檔案是否具有 .keys 副檔名並再試一次。 驗證您的金鑰檔案是否具有 .bin 副檔名並再試一次。 - 無效的加密金鑰 - 選取的檔案不正確或已損毀,請重新傾印您的金鑰。 GPU 驅動程式管理員 安裝 GPU 驅動程式 安裝替代驅動程式以取得潛在的更佳效能或準確度 @@ -427,8 +421,6 @@ 检查所有安装的内容是否有损坏 密钥缺失 无法解密固件和商业游戏 - 韌體缺失或版本過新 - 某些遊戲可能無法正常運作。Eden需要19.0.1或更低版本的韌體。 Qlaunch diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index d037d2680a..855fd6e769 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -496,4 +496,18 @@ 3 + + "" + @string/error_firmware_missing + @string/error_firmware_corrupted + @string/error_firmware_too_new + + + + "" + "" + @string/error_keys_copy_failed + @string/error_keys_invalid_filename + @string/error_keys_failed_init + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 602be31027..e611e66c1f 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -304,14 +304,8 @@ Cancel Install Amiibo keys Required to use Amiibo in game - Invalid keys file selected - Keys successfully installed - Error reading encryption keys - Verify your keys file has a .keys extension and try again. Verify your keys file has a .bin extension and try again. - Invalid encryption keys https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys - The selected file is incorrect or corrupt. Please redump your keys. GPU driver fetcher GPU driver manager Install GPU driver @@ -390,10 +384,18 @@ Firmware and retail games cannot be decrypted https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys - Firmware is missing or too new - Some games may not function properly. Eden requires firmware 19.0.1 or below. + Firmware Invalid + Firmware is required to run certain games and use the Home Menu. Eden only works with firmware 19.0.1 and earlier. + Firmware reported as present, but was unable to be read. Check for decryption keys and redump firmware if necessary. + Firmware is too new or could not be read. Eden only works with firmware 19.0.1 and earlier. https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware + Failed to Install Keys + Keys successfully installed + One or more keys failed to copy. + Verify your keys file has a .keys extension and try again. + Keys failed to initialize. Check that your dumping tools are up to date and re-dump keys. + Qlaunch Launch applications from the system home screen @@ -754,13 +756,16 @@ Your ROM is encrypted - game cartidges or installed titles.]]> + game cartridges or installed titles.]]> prod.keys file is installed so that games can be decrypted.]]> An error occurred initializing the video core This is usually caused by an incompatible GPU driver. Installing a custom GPU driver may resolve this problem. Unable to load ROM ROM file does not exist + Game Requires Firmware + dump and install firmware, or press "OK" to launch anyways.]]> + Exit emulation Done diff --git a/src/common/android/id_cache.cpp b/src/common/android/id_cache.cpp index 2625e55c35..e0edd006a5 100644 --- a/src/common/android/id_cache.cpp +++ b/src/common/android/id_cache.cpp @@ -15,7 +15,7 @@ #include -static JavaVM* s_java_vm; +static JavaVM *s_java_vm; static jclass s_native_library_class; static jclass s_disk_cache_progress_class; static jclass s_load_callback_stage_class; @@ -26,6 +26,9 @@ static jmethodID s_disk_cache_load_progress; static jmethodID s_on_emulation_started; static jmethodID s_on_emulation_stopped; static jmethodID s_on_program_changed; +static jmethodID s_copy_to_storage; +static jmethodID s_file_exists; +static jmethodID s_file_extension; static jclass s_game_class; static jmethodID s_game_constructor; @@ -102,513 +105,534 @@ static constexpr jint JNI_VERSION = JNI_VERSION_1_6; namespace Common::Android { -JNIEnv* GetEnvForThread() { - thread_local static struct OwnedEnv { - OwnedEnv() { - status = s_java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); - if (status == JNI_EDETACHED) - s_java_vm->AttachCurrentThread(&env, nullptr); - } - - ~OwnedEnv() { - if (status == JNI_EDETACHED) - s_java_vm->DetachCurrentThread(); - } - - int status; - JNIEnv* env = nullptr; - } owned; - return owned.env; -} - -jclass GetNativeLibraryClass() { - return s_native_library_class; -} - -jclass GetDiskCacheProgressClass() { - return s_disk_cache_progress_class; -} - -jclass GetDiskCacheLoadCallbackStageClass() { - return s_load_callback_stage_class; -} - -jclass GetGameDirClass() { - return s_game_dir_class; -} - -jmethodID GetGameDirConstructor() { - return s_game_dir_constructor; -} - -jmethodID GetExitEmulationActivity() { - return s_exit_emulation_activity; -} - -jmethodID GetDiskCacheLoadProgress() { - return s_disk_cache_load_progress; -} - -jmethodID GetOnEmulationStarted() { - return s_on_emulation_started; -} - -jmethodID GetOnEmulationStopped() { - return s_on_emulation_stopped; -} - -jmethodID GetOnProgramChanged() { - return s_on_program_changed; -} - -jclass GetGameClass() { - return s_game_class; -} - -jmethodID GetGameConstructor() { - return s_game_constructor; -} - -jfieldID GetGameTitleField() { - return s_game_title_field; -} - -jfieldID GetGamePathField() { - return s_game_path_field; -} - -jfieldID GetGameProgramIdField() { - return s_game_program_id_field; -} - -jfieldID GetGameDeveloperField() { - return s_game_developer_field; -} - -jfieldID GetGameVersionField() { - return s_game_version_field; -} - -jfieldID GetGameIsHomebrewField() { - return s_game_is_homebrew_field; -} - -jclass GetStringClass() { - return s_string_class; -} - -jclass GetPairClass() { - return s_pair_class; -} - -jmethodID GetPairConstructor() { - return s_pair_constructor; -} - -jfieldID GetPairFirstField() { - return s_pair_first_field; -} - -jfieldID GetPairSecondField() { - return s_pair_second_field; -} - -jclass GetOverlayControlDataClass() { - return s_overlay_control_data_class; -} - -jmethodID GetOverlayControlDataConstructor() { - return s_overlay_control_data_constructor; -} - -jfieldID GetOverlayControlDataIdField() { - return s_overlay_control_data_id_field; -} - -jfieldID GetOverlayControlDataEnabledField() { - return s_overlay_control_data_enabled_field; -} - -jfieldID GetOverlayControlDataLandscapePositionField() { - return s_overlay_control_data_landscape_position_field; -} - -jfieldID GetOverlayControlDataPortraitPositionField() { - return s_overlay_control_data_portrait_position_field; -} - -jfieldID GetOverlayControlDataFoldablePositionField() { - return s_overlay_control_data_foldable_position_field; -} - -jclass GetPatchClass() { - return s_patch_class; -} - -jmethodID GetPatchConstructor() { - return s_patch_constructor; -} - -jfieldID GetPatchEnabledField() { - return s_patch_enabled_field; -} - -jfieldID GetPatchNameField() { - return s_patch_name_field; -} - -jfieldID GetPatchVersionField() { - return s_patch_version_field; -} - -jfieldID GetPatchTypeField() { - return s_patch_type_field; -} - -jfieldID GetPatchProgramIdField() { - return s_patch_program_id_field; -} - -jfieldID GetPatchTitleIdField() { - return s_patch_title_id_field; -} - -jclass GetDoubleClass() { - return s_double_class; -} - -jmethodID GetDoubleConstructor() { - return s_double_constructor; -} - -jfieldID GetDoubleValueField() { - return s_double_value_field; -} - -jclass GetIntegerClass() { - return s_integer_class; -} - -jmethodID GetIntegerConstructor() { - return s_integer_constructor; -} - -jfieldID GetIntegerValueField() { - return s_integer_value_field; -} - -jclass GetBooleanClass() { - return s_boolean_class; -} - -jmethodID GetBooleanConstructor() { - return s_boolean_constructor; -} - -jfieldID GetBooleanValueField() { - return s_boolean_value_field; -} - -jclass GetPlayerInputClass() { - return s_player_input_class; -} - -jmethodID GetPlayerInputConstructor() { - return s_player_input_constructor; -} - -jfieldID GetPlayerInputConnectedField() { - return s_player_input_connected_field; -} - -jfieldID GetPlayerInputButtonsField() { - return s_player_input_buttons_field; -} - -jfieldID GetPlayerInputAnalogsField() { - return s_player_input_analogs_field; -} - -jfieldID GetPlayerInputMotionsField() { - return s_player_input_motions_field; -} - -jfieldID GetPlayerInputVibrationEnabledField() { - return s_player_input_vibration_enabled_field; -} - -jfieldID GetPlayerInputVibrationStrengthField() { - return s_player_input_vibration_strength_field; -} - -jfieldID GetPlayerInputBodyColorLeftField() { - return s_player_input_body_color_left_field; -} - -jfieldID GetPlayerInputBodyColorRightField() { - return s_player_input_body_color_right_field; -} - -jfieldID GetPlayerInputButtonColorLeftField() { - return s_player_input_button_color_left_field; -} - -jfieldID GetPlayerInputButtonColorRightField() { - return s_player_input_button_color_right_field; -} - -jfieldID GetPlayerInputProfileNameField() { - return s_player_input_profile_name_field; -} - -jfieldID GetPlayerInputUseSystemVibratorField() { - return s_player_input_use_system_vibrator_field; -} - -jclass GetYuzuInputDeviceInterface() { - return s_yuzu_input_device_interface; -} - -jmethodID GetYuzuDeviceGetName() { - return s_yuzu_input_device_get_name; -} - -jmethodID GetYuzuDeviceGetGUID() { - return s_yuzu_input_device_get_guid; -} - -jmethodID GetYuzuDeviceGetPort() { - return s_yuzu_input_device_get_port; -} - -jmethodID GetYuzuDeviceGetSupportsVibration() { - return s_yuzu_input_device_get_supports_vibration; -} - -jmethodID GetYuzuDeviceVibrate() { - return s_yuzu_input_device_vibrate; -} - -jmethodID GetYuzuDeviceGetAxes() { - return s_yuzu_input_device_get_axes; -} - -jmethodID GetYuzuDeviceHasKeys() { - return s_yuzu_input_device_has_keys; -} - -jmethodID GetAddNetPlayMessage() { - return s_add_netplay_message; -} - -jmethodID ClearChat() { - return s_clear_chat; -} - -#ifdef __cplusplus -extern "C" { -#endif - -jint JNI_OnLoad(JavaVM* vm, void* reserved) { - s_java_vm = vm; - - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION) != JNI_OK) - return JNI_ERR; - - // Initialize Java classes - const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary"); - s_native_library_class = reinterpret_cast(env->NewGlobalRef(native_library_class)); - s_disk_cache_progress_class = reinterpret_cast(env->NewGlobalRef( - env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress"))); - s_load_callback_stage_class = reinterpret_cast(env->NewGlobalRef(env->FindClass( - "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage"))); - - const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir"); - s_game_dir_class = reinterpret_cast(env->NewGlobalRef(game_dir_class)); - s_game_dir_constructor = env->GetMethodID(game_dir_class, "", "(Ljava/lang/String;Z)V"); - env->DeleteLocalRef(game_dir_class); - - // Initialize methods - s_exit_emulation_activity = - env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); - s_disk_cache_load_progress = - env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V"); - s_on_emulation_started = - env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V"); - s_on_emulation_stopped = - env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V"); - s_on_program_changed = - env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V"); - - const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game"); - s_game_class = reinterpret_cast(env->NewGlobalRef(game_class)); - s_game_constructor = env->GetMethodID(game_class, "", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/" - "String;Ljava/lang/String;Ljava/lang/String;Z)V"); - s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;"); - s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;"); - s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;"); - s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;"); - s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;"); - s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z"); - env->DeleteLocalRef(game_class); - - const jclass string_class = env->FindClass("java/lang/String"); - s_string_class = reinterpret_cast(env->NewGlobalRef(string_class)); - env->DeleteLocalRef(string_class); - - const jclass pair_class = env->FindClass("kotlin/Pair"); - s_pair_class = reinterpret_cast(env->NewGlobalRef(pair_class)); - s_pair_constructor = - env->GetMethodID(pair_class, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;"); - s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); - env->DeleteLocalRef(pair_class); - - const jclass overlay_control_data_class = - env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData"); - s_overlay_control_data_class = - reinterpret_cast(env->NewGlobalRef(overlay_control_data_class)); - s_overlay_control_data_constructor = - env->GetMethodID(overlay_control_data_class, "", - "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V"); - s_overlay_control_data_id_field = - env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;"); - s_overlay_control_data_enabled_field = - env->GetFieldID(overlay_control_data_class, "enabled", "Z"); - s_overlay_control_data_landscape_position_field = - env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;"); - s_overlay_control_data_portrait_position_field = - env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;"); - s_overlay_control_data_foldable_position_field = - env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); - env->DeleteLocalRef(overlay_control_data_class); - - const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch"); - s_patch_class = reinterpret_cast(env->NewGlobalRef(patch_class)); - s_patch_constructor = env->GetMethodID( - patch_class, "", - "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"); - s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z"); - s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;"); - s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;"); - s_patch_type_field = env->GetFieldID(patch_class, "type", "I"); - s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;"); - s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;"); - env->DeleteLocalRef(patch_class); - - const jclass double_class = env->FindClass("java/lang/Double"); - s_double_class = reinterpret_cast(env->NewGlobalRef(double_class)); - s_double_constructor = env->GetMethodID(double_class, "", "(D)V"); - s_double_value_field = env->GetFieldID(double_class, "value", "D"); - env->DeleteLocalRef(double_class); - - const jclass int_class = env->FindClass("java/lang/Integer"); - s_integer_class = reinterpret_cast(env->NewGlobalRef(int_class)); - s_integer_constructor = env->GetMethodID(int_class, "", "(I)V"); - s_integer_value_field = env->GetFieldID(int_class, "value", "I"); - env->DeleteLocalRef(int_class); - - const jclass boolean_class = env->FindClass("java/lang/Boolean"); - s_boolean_class = reinterpret_cast(env->NewGlobalRef(boolean_class)); - s_boolean_constructor = env->GetMethodID(boolean_class, "", "(Z)V"); - s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z"); - env->DeleteLocalRef(boolean_class); - - const jclass player_input_class = - env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput"); - s_player_input_class = reinterpret_cast(env->NewGlobalRef(player_input_class)); - s_player_input_constructor = env->GetMethodID( - player_input_class, "", - "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V"); - s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z"); - s_player_input_buttons_field = - env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;"); - s_player_input_analogs_field = - env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;"); - s_player_input_motions_field = - env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;"); - s_player_input_vibration_enabled_field = - env->GetFieldID(player_input_class, "vibrationEnabled", "Z"); - s_player_input_vibration_strength_field = - env->GetFieldID(player_input_class, "vibrationStrength", "I"); - s_player_input_body_color_left_field = - env->GetFieldID(player_input_class, "bodyColorLeft", "J"); - s_player_input_body_color_right_field = - env->GetFieldID(player_input_class, "bodyColorRight", "J"); - s_player_input_button_color_left_field = - env->GetFieldID(player_input_class, "buttonColorLeft", "J"); - s_player_input_button_color_right_field = - env->GetFieldID(player_input_class, "buttonColorRight", "J"); - s_player_input_profile_name_field = - env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;"); - s_player_input_use_system_vibrator_field = - env->GetFieldID(player_input_class, "useSystemVibrator", "Z"); - env->DeleteLocalRef(player_input_class); - - const jclass yuzu_input_device_interface = - env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice"); - s_yuzu_input_device_interface = - reinterpret_cast(env->NewGlobalRef(yuzu_input_device_interface)); - s_yuzu_input_device_get_name = - env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;"); - s_yuzu_input_device_get_guid = - env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;"); - s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort", "()I"); - s_yuzu_input_device_get_supports_vibration = - env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z"); - s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate", "(F)V"); - s_yuzu_input_device_get_axes = - env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;"); - s_yuzu_input_device_has_keys = - env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z"); - env->DeleteLocalRef(yuzu_input_device_interface); - s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage", - "(ILjava/lang/String;)V"); - s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V"); - - - // Initialize Android Storage - Common::FS::Android::RegisterCallbacks(env, s_native_library_class); - - // Initialize applets - Common::Android::SoftwareKeyboard::InitJNI(env); - - return JNI_VERSION; -} - -void JNI_OnUnload(JavaVM* vm, void* reserved) { - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION) != JNI_OK) { - return; + JNIEnv *GetEnvForThread() { + thread_local static struct OwnedEnv { + OwnedEnv() { + status = s_java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + if (status == JNI_EDETACHED) + s_java_vm->AttachCurrentThread(&env, nullptr); + } + + ~OwnedEnv() { + if (status == JNI_EDETACHED) + s_java_vm->DetachCurrentThread(); + } + + int status; + JNIEnv *env = nullptr; + } owned; + return owned.env; } - // UnInitialize Android Storage - Common::FS::Android::UnRegisterCallbacks(); - env->DeleteGlobalRef(s_native_library_class); - env->DeleteGlobalRef(s_disk_cache_progress_class); - env->DeleteGlobalRef(s_load_callback_stage_class); - env->DeleteGlobalRef(s_game_dir_class); - env->DeleteGlobalRef(s_game_class); - env->DeleteGlobalRef(s_string_class); - env->DeleteGlobalRef(s_pair_class); - env->DeleteGlobalRef(s_overlay_control_data_class); - env->DeleteGlobalRef(s_patch_class); - env->DeleteGlobalRef(s_double_class); - env->DeleteGlobalRef(s_integer_class); - env->DeleteGlobalRef(s_boolean_class); - env->DeleteGlobalRef(s_player_input_class); - env->DeleteGlobalRef(s_yuzu_input_device_interface); + jclass GetNativeLibraryClass() { + return s_native_library_class; + } - // UnInitialize applets - SoftwareKeyboard::CleanupJNI(env); + jclass GetDiskCacheProgressClass() { + return s_disk_cache_progress_class; + } - AndroidMultiplayer::NetworkShutdown(); -} + jclass GetDiskCacheLoadCallbackStageClass() { + return s_load_callback_stage_class; + } + + jclass GetGameDirClass() { + return s_game_dir_class; + } + + jmethodID GetGameDirConstructor() { + return s_game_dir_constructor; + } + + jmethodID GetExitEmulationActivity() { + return s_exit_emulation_activity; + } + + jmethodID GetDiskCacheLoadProgress() { + return s_disk_cache_load_progress; + } + + jmethodID GetCopyToStorage() { + return s_copy_to_storage; + } + + jmethodID GetFileExists() { + return s_file_exists; + } + + jmethodID GetFileExtension() { + return s_file_extension; + } + + jmethodID GetOnEmulationStarted() { + return s_on_emulation_started; + } + + jmethodID GetOnEmulationStopped() { + return s_on_emulation_stopped; + } + + jmethodID GetOnProgramChanged() { + return s_on_program_changed; + } + + jclass GetGameClass() { + return s_game_class; + } + + jmethodID GetGameConstructor() { + return s_game_constructor; + } + + jfieldID GetGameTitleField() { + return s_game_title_field; + } + + jfieldID GetGamePathField() { + return s_game_path_field; + } + + jfieldID GetGameProgramIdField() { + return s_game_program_id_field; + } + + jfieldID GetGameDeveloperField() { + return s_game_developer_field; + } + + jfieldID GetGameVersionField() { + return s_game_version_field; + } + + jfieldID GetGameIsHomebrewField() { + return s_game_is_homebrew_field; + } + + jclass GetStringClass() { + return s_string_class; + } + + jclass GetPairClass() { + return s_pair_class; + } + + jmethodID GetPairConstructor() { + return s_pair_constructor; + } + + jfieldID GetPairFirstField() { + return s_pair_first_field; + } + + jfieldID GetPairSecondField() { + return s_pair_second_field; + } + + jclass GetOverlayControlDataClass() { + return s_overlay_control_data_class; + } + + jmethodID GetOverlayControlDataConstructor() { + return s_overlay_control_data_constructor; + } + + jfieldID GetOverlayControlDataIdField() { + return s_overlay_control_data_id_field; + } + + jfieldID GetOverlayControlDataEnabledField() { + return s_overlay_control_data_enabled_field; + } + + jfieldID GetOverlayControlDataLandscapePositionField() { + return s_overlay_control_data_landscape_position_field; + } + + jfieldID GetOverlayControlDataPortraitPositionField() { + return s_overlay_control_data_portrait_position_field; + } + + jfieldID GetOverlayControlDataFoldablePositionField() { + return s_overlay_control_data_foldable_position_field; + } + + jclass GetPatchClass() { + return s_patch_class; + } + + jmethodID GetPatchConstructor() { + return s_patch_constructor; + } + + jfieldID GetPatchEnabledField() { + return s_patch_enabled_field; + } + + jfieldID GetPatchNameField() { + return s_patch_name_field; + } + + jfieldID GetPatchVersionField() { + return s_patch_version_field; + } + + jfieldID GetPatchTypeField() { + return s_patch_type_field; + } + + jfieldID GetPatchProgramIdField() { + return s_patch_program_id_field; + } + + jfieldID GetPatchTitleIdField() { + return s_patch_title_id_field; + } + + jclass GetDoubleClass() { + return s_double_class; + } + + jmethodID GetDoubleConstructor() { + return s_double_constructor; + } + + jfieldID GetDoubleValueField() { + return s_double_value_field; + } + + jclass GetIntegerClass() { + return s_integer_class; + } + + jmethodID GetIntegerConstructor() { + return s_integer_constructor; + } + + jfieldID GetIntegerValueField() { + return s_integer_value_field; + } + + jclass GetBooleanClass() { + return s_boolean_class; + } + + jmethodID GetBooleanConstructor() { + return s_boolean_constructor; + } + + jfieldID GetBooleanValueField() { + return s_boolean_value_field; + } + + jclass GetPlayerInputClass() { + return s_player_input_class; + } + + jmethodID GetPlayerInputConstructor() { + return s_player_input_constructor; + } + + jfieldID GetPlayerInputConnectedField() { + return s_player_input_connected_field; + } + + jfieldID GetPlayerInputButtonsField() { + return s_player_input_buttons_field; + } + + jfieldID GetPlayerInputAnalogsField() { + return s_player_input_analogs_field; + } + + jfieldID GetPlayerInputMotionsField() { + return s_player_input_motions_field; + } + + jfieldID GetPlayerInputVibrationEnabledField() { + return s_player_input_vibration_enabled_field; + } + + jfieldID GetPlayerInputVibrationStrengthField() { + return s_player_input_vibration_strength_field; + } + + jfieldID GetPlayerInputBodyColorLeftField() { + return s_player_input_body_color_left_field; + } + + jfieldID GetPlayerInputBodyColorRightField() { + return s_player_input_body_color_right_field; + } + + jfieldID GetPlayerInputButtonColorLeftField() { + return s_player_input_button_color_left_field; + } + + jfieldID GetPlayerInputButtonColorRightField() { + return s_player_input_button_color_right_field; + } + + jfieldID GetPlayerInputProfileNameField() { + return s_player_input_profile_name_field; + } + + jfieldID GetPlayerInputUseSystemVibratorField() { + return s_player_input_use_system_vibrator_field; + } + + jclass GetYuzuInputDeviceInterface() { + return s_yuzu_input_device_interface; + } + + jmethodID GetYuzuDeviceGetName() { + return s_yuzu_input_device_get_name; + } + + jmethodID GetYuzuDeviceGetGUID() { + return s_yuzu_input_device_get_guid; + } + + jmethodID GetYuzuDeviceGetPort() { + return s_yuzu_input_device_get_port; + } + + jmethodID GetYuzuDeviceGetSupportsVibration() { + return s_yuzu_input_device_get_supports_vibration; + } + + jmethodID GetYuzuDeviceVibrate() { + return s_yuzu_input_device_vibrate; + } + + jmethodID GetYuzuDeviceGetAxes() { + return s_yuzu_input_device_get_axes; + } + + jmethodID GetYuzuDeviceHasKeys() { + return s_yuzu_input_device_has_keys; + } + + jmethodID GetAddNetPlayMessage() { + return s_add_netplay_message; + } + + jmethodID ClearChat() { + return s_clear_chat; + } #ifdef __cplusplus -} + extern "C" { +#endif + + jint JNI_OnLoad(JavaVM *vm, void *reserved) { + s_java_vm = vm; + + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION) != JNI_OK) + return JNI_ERR; + + // Initialize Java classes + const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary"); + s_native_library_class = reinterpret_cast(env->NewGlobalRef(native_library_class)); + s_disk_cache_progress_class = reinterpret_cast(env->NewGlobalRef( + env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress"))); + s_load_callback_stage_class = reinterpret_cast(env->NewGlobalRef(env->FindClass( + "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage"))); + + const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir"); + s_game_dir_class = reinterpret_cast(env->NewGlobalRef(game_dir_class)); + s_game_dir_constructor = env->GetMethodID(game_dir_class, "", + "(Ljava/lang/String;Z)V"); + env->DeleteLocalRef(game_dir_class); + + // Initialize methods + s_exit_emulation_activity = + env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); + s_disk_cache_load_progress = + env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V"); + s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage", + "(Ljava/lang/String;Ljava/lang/String;)Z"); + s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists", + "(Ljava/lang/String;)Z"); + s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension", + "(Ljava/lang/String;)Ljava/lang/String;"); + s_on_emulation_started = + env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V"); + s_on_emulation_stopped = + env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V"); + s_on_program_changed = + env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V"); + + const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game"); + s_game_class = reinterpret_cast(env->NewGlobalRef(game_class)); + s_game_constructor = env->GetMethodID(game_class, "", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/" + "String;Ljava/lang/String;Ljava/lang/String;Z)V"); + s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;"); + s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;"); + s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;"); + s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;"); + s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;"); + s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z"); + env->DeleteLocalRef(game_class); + + const jclass string_class = env->FindClass("java/lang/String"); + s_string_class = reinterpret_cast(env->NewGlobalRef(string_class)); + env->DeleteLocalRef(string_class); + + const jclass pair_class = env->FindClass("kotlin/Pair"); + s_pair_class = reinterpret_cast(env->NewGlobalRef(pair_class)); + s_pair_constructor = + env->GetMethodID(pair_class, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;"); + s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); + env->DeleteLocalRef(pair_class); + + const jclass overlay_control_data_class = + env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData"); + s_overlay_control_data_class = + reinterpret_cast(env->NewGlobalRef(overlay_control_data_class)); + s_overlay_control_data_constructor = + env->GetMethodID(overlay_control_data_class, "", + "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V"); + s_overlay_control_data_id_field = + env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;"); + s_overlay_control_data_enabled_field = + env->GetFieldID(overlay_control_data_class, "enabled", "Z"); + s_overlay_control_data_landscape_position_field = + env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;"); + s_overlay_control_data_portrait_position_field = + env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;"); + s_overlay_control_data_foldable_position_field = + env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); + env->DeleteLocalRef(overlay_control_data_class); + + const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch"); + s_patch_class = reinterpret_cast(env->NewGlobalRef(patch_class)); + s_patch_constructor = env->GetMethodID( + patch_class, "", + "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"); + s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z"); + s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;"); + s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;"); + s_patch_type_field = env->GetFieldID(patch_class, "type", "I"); + s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;"); + s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;"); + env->DeleteLocalRef(patch_class); + + const jclass double_class = env->FindClass("java/lang/Double"); + s_double_class = reinterpret_cast(env->NewGlobalRef(double_class)); + s_double_constructor = env->GetMethodID(double_class, "", "(D)V"); + s_double_value_field = env->GetFieldID(double_class, "value", "D"); + env->DeleteLocalRef(double_class); + + const jclass int_class = env->FindClass("java/lang/Integer"); + s_integer_class = reinterpret_cast(env->NewGlobalRef(int_class)); + s_integer_constructor = env->GetMethodID(int_class, "", "(I)V"); + s_integer_value_field = env->GetFieldID(int_class, "value", "I"); + env->DeleteLocalRef(int_class); + + const jclass boolean_class = env->FindClass("java/lang/Boolean"); + s_boolean_class = reinterpret_cast(env->NewGlobalRef(boolean_class)); + s_boolean_constructor = env->GetMethodID(boolean_class, "", "(Z)V"); + s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z"); + env->DeleteLocalRef(boolean_class); + + const jclass player_input_class = + env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput"); + s_player_input_class = reinterpret_cast(env->NewGlobalRef(player_input_class)); + s_player_input_constructor = env->GetMethodID( + player_input_class, "", + "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V"); + s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z"); + s_player_input_buttons_field = + env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;"); + s_player_input_analogs_field = + env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;"); + s_player_input_motions_field = + env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;"); + s_player_input_vibration_enabled_field = + env->GetFieldID(player_input_class, "vibrationEnabled", "Z"); + s_player_input_vibration_strength_field = + env->GetFieldID(player_input_class, "vibrationStrength", "I"); + s_player_input_body_color_left_field = + env->GetFieldID(player_input_class, "bodyColorLeft", "J"); + s_player_input_body_color_right_field = + env->GetFieldID(player_input_class, "bodyColorRight", "J"); + s_player_input_button_color_left_field = + env->GetFieldID(player_input_class, "buttonColorLeft", "J"); + s_player_input_button_color_right_field = + env->GetFieldID(player_input_class, "buttonColorRight", "J"); + s_player_input_profile_name_field = + env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;"); + s_player_input_use_system_vibrator_field = + env->GetFieldID(player_input_class, "useSystemVibrator", "Z"); + env->DeleteLocalRef(player_input_class); + + const jclass yuzu_input_device_interface = + env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice"); + s_yuzu_input_device_interface = + reinterpret_cast(env->NewGlobalRef(yuzu_input_device_interface)); + s_yuzu_input_device_get_name = + env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;"); + s_yuzu_input_device_get_guid = + env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;"); + s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort", + "()I"); + s_yuzu_input_device_get_supports_vibration = + env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z"); + s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate", + "(F)V"); + s_yuzu_input_device_get_axes = + env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;"); + s_yuzu_input_device_has_keys = + env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z"); + env->DeleteLocalRef(yuzu_input_device_interface); + s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage", + "(ILjava/lang/String;)V"); + s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V"); + + + // Initialize Android Storage + Common::FS::Android::RegisterCallbacks(env, s_native_library_class); + + // Initialize applets + Common::Android::SoftwareKeyboard::InitJNI(env); + + return JNI_VERSION; + } + + void JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION) != JNI_OK) { + return; + } + + // UnInitialize Android Storage + Common::FS::Android::UnRegisterCallbacks(); + env->DeleteGlobalRef(s_native_library_class); + env->DeleteGlobalRef(s_disk_cache_progress_class); + env->DeleteGlobalRef(s_load_callback_stage_class); + env->DeleteGlobalRef(s_game_dir_class); + env->DeleteGlobalRef(s_game_class); + env->DeleteGlobalRef(s_string_class); + env->DeleteGlobalRef(s_pair_class); + env->DeleteGlobalRef(s_overlay_control_data_class); + env->DeleteGlobalRef(s_patch_class); + env->DeleteGlobalRef(s_double_class); + env->DeleteGlobalRef(s_integer_class); + env->DeleteGlobalRef(s_boolean_class); + env->DeleteGlobalRef(s_player_input_class); + env->DeleteGlobalRef(s_yuzu_input_device_interface); + + // UnInitialize applets + SoftwareKeyboard::CleanupJNI(env); + + AndroidMultiplayer::NetworkShutdown(); + } + +#ifdef __cplusplus + } #endif } // namespace Common::Android diff --git a/src/common/android/id_cache.h b/src/common/android/id_cache.h index cbfbf36be8..c56ffcf5c6 100644 --- a/src/common/android/id_cache.h +++ b/src/common/android/id_cache.h @@ -39,6 +39,9 @@ jclass GetDiskCacheLoadCallbackStageClass(); jclass GetGameDirClass(); jmethodID GetGameDirConstructor(); jmethodID GetDiskCacheLoadProgress(); +jmethodID GetCopyToStorage(); +jmethodID GetFileExists(); +jmethodID GetFileExtension(); jmethodID GetExitEmulationActivity(); jmethodID GetOnEmulationStarted(); diff --git a/src/common/microprofile.h b/src/common/microprofile.h index 56ef0a2dcf..25bf362500 100644 --- a/src/common/microprofile.h +++ b/src/common/microprofile.h @@ -1,11 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -// Uncomment this to disable microprofile. This will get you cleaner profiles when using +// Use this to disable microprofile. This will get you cleaner profiles when using // external sampling profilers like "Very Sleepy", and will improve performance somewhat. -// #define MICROPROFILE_ENABLED 0 +#ifdef ANDROID +#define MICROPROFILE_ENABLED 0 +#define MICROPROFILEUI_ENABLED 0 +#define MicroProfileOnThreadExit() do{}while(0) +#define MICROPROFILE_TOKEN(x) 0 +#define MicroProfileEnter(x) 0 +#define MicroProfileLeave(x, y) ignore_all(x, y) +#endif // Customized Citra settings. // This file wraps the MicroProfile header so that these are consistent everywhere. @@ -19,6 +29,12 @@ typedef void* HANDLE; #endif +#include +template +void ignore_all(Args&&... args) { + (static_cast(std::ignore = args), ...); +} + #include #define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index d21aa5aacf..afbf178349 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -201,7 +204,7 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa } // Multi-process state - config.processor_id = m_core_index; + config.processor_id = std::uint8_t(m_core_index); config.global_monitor = &m_exclusive_monitor.monitor; // Timing @@ -210,9 +213,9 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // Code cache size #ifdef ARCHITECTURE_arm64 - config.code_cache_size = 128_MiB; + config.code_cache_size = std::uint32_t(128_MiB); #else - config.code_cache_size = 512_MiB; + config.code_cache_size = std::uint32_t(512_MiB); #endif // Allow memory fault handling to work @@ -223,7 +226,7 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // null_jit if (!page_table) { // Don't waste too much memory on null_jit - config.code_cache_size = 8_MiB; + config.code_cache_size = std::uint32_t(8_MiB); } // Safe optimizations diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index c251482182..99a80644ad 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -232,7 +235,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // Memory if (page_table) { config.page_table = reinterpret_cast(page_table->pointers.data()); - config.page_table_address_space_bits = address_space_bits; + config.page_table_address_space_bits = std::uint32_t(address_space_bits); config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; config.silently_mirror_page_table = false; config.absolute_offset_page_table = true; @@ -242,7 +245,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa config.fastmem_pointer = page_table->fastmem_arena ? std::optional{reinterpret_cast(page_table->fastmem_arena)} : std::nullopt; - config.fastmem_address_space_bits = address_space_bits; + config.fastmem_address_space_bits = std::uint32_t(address_space_bits); config.silently_mirror_fastmem = false; config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt; @@ -250,7 +253,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa } // Multi-process state - config.processor_id = m_core_index; + config.processor_id = std::uint8_t(m_core_index); config.global_monitor = &m_exclusive_monitor.monitor; // System registers @@ -269,9 +272,9 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // Code cache size #ifdef ARCHITECTURE_arm64 - config.code_cache_size = 128_MiB; + config.code_cache_size = std::uint32_t(128_MiB); #else - config.code_cache_size = 512_MiB; + config.code_cache_size = std::uint32_t(512_MiB); #endif // Allow memory fault handling to work @@ -282,7 +285,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // null_jit if (!page_table) { // Don't waste too much memory on null_jit - config.code_cache_size = 8_MiB; + config.code_cache_size = std::uint32_t(8_MiB); } // Safe optimizations diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 877e8ac3c7..0e0d72fc8a 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -227,7 +227,7 @@ HaltReason ArmNce::RunThread(Kernel::KThread* thread) { if (auto it = post_handlers.find(m_guest_ctx.pc); it != post_handlers.end()) { hr = ReturnToRunCodeByTrampoline(thread_params, &m_guest_ctx, it->second); } else { - hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); + hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); // Android: Use "process handle SIGUSR2 -n true -p true -s false" (and SIGURG) in LLDB when debugging } // Critical section for thread cleanup diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index b07bd3e58e..d9f01a65b8 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -53,6 +53,16 @@ enum class NetDbError : s32 { NoData = 4, }; +const std::vector blockedDomains = {"srv.nintendo.net", "battle.net", + "microsoft.com", "mojang.com", + "xboxlive.com", "minecraftservices.com"}; + +static bool IsBlockedHost(const std::string& host) { + return std::any_of( + blockedDomains.begin(), blockedDomains.end(), + [&host](const std::string& domain) { return host.find(domain) != std::string::npos; }); +} + static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) { // These combinations have been verified on console (but are not // exhaustive). @@ -154,7 +164,7 @@ static std::pair GetHostByNameRequestImpl(HLERequestConte // For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions. // Prevent resolution of Nintendo servers - if (host.find("srv.nintendo.net") != std::string::npos) { + if (IsBlockedHost(host)) { LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host); return {0, GetAddrInfoError::AGAIN}; } @@ -271,7 +281,7 @@ static std::pair GetAddrInfoRequestImpl(HLERequestContext const std::string host = Common::StringFromBuffer(host_buffer); // Prevent resolution of Nintendo servers - if (host.find("srv.nintendo.net") != std::string::npos) { + if (IsBlockedHost(host)) { LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host); return {0, GetAddrInfoError::AGAIN}; } @@ -359,5 +369,4 @@ void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) { rb.Push(ResultSuccess); rb.Push(0); // bsd errno } - } // namespace Service::Sockets diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b033858bf8..34539cc650 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-FileCopyrightText: 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -868,35 +871,35 @@ struct Memory::Impl { [[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const { // AARCH64 masks the upper 16 bit of all memory accesses vaddr = vaddr & 0xffffffffffffULL; - if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] { on_unmapped(); return nullptr; + } else { + // Avoid adding any extra logic to this fast-path block + const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); + if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { + return reinterpret_cast(pointer + vaddr); + } else { + switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { + case Common::PageType::Unmapped: + on_unmapped(); + return nullptr; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr); + return nullptr; + case Common::PageType::DebugMemory: + return GetPointerFromDebugMemory(vaddr); + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; + on_rasterizer(); + return host_ptr; + } + default: + UNREACHABLE(); + } + return nullptr; + } } - - // Avoid adding any extra logic to this fast-path block - const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); - if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { - return reinterpret_cast(pointer + vaddr); - } - switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { - case Common::PageType::Unmapped: - on_unmapped(); - return nullptr; - case Common::PageType::Memory: - ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr); - return nullptr; - case Common::PageType::DebugMemory: - return GetPointerFromDebugMemory(vaddr); - case Common::PageType::RasterizerCachedMemory: { - u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; - on_rasterizer(); - return host_ptr; - } - default: - UNREACHABLE(); - } - return nullptr; } [[nodiscard]] u8* GetPointer(const Common::ProcessAddress vaddr) const { @@ -1149,13 +1152,19 @@ struct Memory::Impl { gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { auto& current_area = rasterizer_write_areas[core]; PAddr subaddress = address >> YUZU_PAGEBITS; - bool do_collection = current_area.last_address == subaddress; - if (!do_collection) [[unlikely]] { - do_collection = system.GPU().OnCPUWrite(address, size); - if (!do_collection) { + // Performance note: + // It may not be a good idea to assume accesses are within the same subaddress (i.e same page) + // It is often the case the games like to access wildly different addresses. Hence why I propose + // we should let the compiler just do it's thing... + if (current_area.last_address != subaddress) { + // Short circuit the need to check for address/size + auto const do_collection = (address != 0 && size != 0) + && system.GPU().OnCPUWrite(address, size); + if (do_collection) { + current_area.last_address = subaddress; + } else { return; } - current_area.last_address = subaddress; } gpu_dirty_managers[core].Collect(address, size); }); diff --git a/src/frontend_common/CMakeLists.txt b/src/frontend_common/CMakeLists.txt index 94d8cc4c3b..70e142bb0c 100644 --- a/src/frontend_common/CMakeLists.txt +++ b/src/frontend_common/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(frontend_common STATIC config.cpp config.h content_manager.h + firmware_manager.h + firmware_manager.cpp ) create_target_directory_groups(frontend_common) diff --git a/src/frontend_common/firmware_manager.cpp b/src/frontend_common/firmware_manager.cpp new file mode 100644 index 0000000000..a180693996 --- /dev/null +++ b/src/frontend_common/firmware_manager.cpp @@ -0,0 +1,139 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "firmware_manager.h" +#include +#include + +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +#include "common/logging/backend.h" + +#include "core/crypto/key_manager.h" +#include "frontend_common/content_manager.h" + +#ifdef ANDROID +#include +#include +#include +#endif + +FirmwareManager::KeyInstallResult +FirmwareManager::InstallKeys(std::string location, std::string extension) { + LOG_INFO(Frontend, "Installing key files from {}", location); + + const auto keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir); + +#ifdef ANDROID + JNIEnv *env = Common::Android::GetEnvForThread(); + + jstring jsrc = Common::Android::ToJString(env, location); + + jclass native = Common::Android::GetNativeLibraryClass(); + jmethodID getExtension = Common::Android::GetFileExtension(); + + jstring jext = static_cast(env->CallStaticObjectMethod( + native, + getExtension, + jsrc + )); + + std::string ext = Common::Android::GetJString(env, jext); + + if (ext != extension) { + return ErrorWrongFilename; + } + + jmethodID copyToStorage = Common::Android::GetCopyToStorage(); + jstring jdest = Common::Android::ToJString(env, keys_dir.string() + "/"); + + jboolean copyResult = env->CallStaticBooleanMethod( + native, + copyToStorage, + jsrc, + jdest + ); + + if (!copyResult) { + return ErrorFailedCopy; + } +#else + if (!location.ends_with(extension)) { + return ErrorWrongFilename; + } + + bool prod_keys_found = false; + + const std::filesystem::path prod_key_path = location; + const std::filesystem::path key_source_path = prod_key_path.parent_path(); + + if (!Common::FS::IsDir(key_source_path)) { + return InvalidDir; + } + + std::vector source_key_files; + + if (Common::FS::Exists(prod_key_path)) { + prod_keys_found = true; + source_key_files.emplace_back(prod_key_path); + } + + if (Common::FS::Exists(key_source_path / "title.keys")) { + source_key_files.emplace_back(key_source_path / "title.keys"); + } + + if (Common::FS::Exists(key_source_path / "key_retail.bin")) { + source_key_files.emplace_back(key_source_path / "key_retail.bin"); + } + + if (source_key_files.empty() || !prod_keys_found) { + return ErrorWrongFilename; + } + + for (const auto &key_file : source_key_files) { + std::filesystem::path destination_key_file = keys_dir / key_file.filename(); + if (!std::filesystem::copy_file(key_file, + destination_key_file, + std::filesystem::copy_options::overwrite_existing)) { + LOG_ERROR(Frontend, + "Failed to copy file {} to {}", + key_file.string(), + destination_key_file.string()); + return ErrorFailedCopy; + } + } +#endif + + // Reinitialize the key manager + Core::Crypto::KeyManager::Instance().ReloadKeys(); + + if (ContentManager::AreKeysPresent()) { + return Success; + } + + // Let the frontend handle everything else + return ErrorFailedInit; +} + +FirmwareManager::FirmwareCheckResult FirmwareManager::VerifyFirmware(Core::System &system) { + if (!CheckFirmwarePresence(system)) { + return ErrorFirmwareMissing; + } else { + const auto pair = GetFirmwareVersion(system); + const auto firmware_data = pair.first; + const auto result = pair.second; + + if (result.IsError()) { + LOG_INFO(Frontend, "Unable to read firmware"); + return ErrorFirmwareCorrupted; + } + + // TODO: update this whenever newer firmware is properly supported + if (firmware_data.major > 19) { + return ErrorFirmwareTooNew; + } + } + + return FirmwareGood; +} diff --git a/src/frontend_common/firmware_manager.h b/src/frontend_common/firmware_manager.h new file mode 100644 index 0000000000..20f3b41478 --- /dev/null +++ b/src/frontend_common/firmware_manager.h @@ -0,0 +1,148 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef FIRMWARE_MANAGER_H +#define FIRMWARE_MANAGER_H + +#include "common/common_types.h" +#include "core/core.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/hle/service/filesystem/filesystem.h" +#include +#include +#include +#include + +#include "core/hle/service/set/settings_types.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/result.h" + +namespace FirmwareManager { + +static constexpr std::array KEY_INSTALL_RESULT_STRINGS = { + "Decryption Keys were successfully installed", + "Unable to read key directory, aborting", + "One or more keys failed to copy.", + "Verify your keys file has a .keys extension and try again.", + "Decryption Keys failed to initialize. Check that your dumping tools are up to date and " + "re-dump keys.", +}; + +static constexpr std::array FIRMWARE_REQUIRED_GAMES = { + 0x0100152000022000ULL, // MK8DX +}; + +enum KeyInstallResult { + Success, + InvalidDir, + ErrorFailedCopy, + ErrorWrongFilename, + ErrorFailedInit, +}; + +/** + * @brief Installs any arbitrary set of keys for the emulator. + * @param location Where the keys are located. + * @param expected_extension What extension the file should have. + * @return A result code for the operation. + */ +KeyInstallResult InstallKeys(std::string location, std::string expected_extension); + +/** + * \brief Get a string representation of a result from InstallKeys. + * \param result The result code. + * \return A string representation of the passed result code. + */ +inline constexpr const char *GetKeyInstallResultString(KeyInstallResult result) +{ + return KEY_INSTALL_RESULT_STRINGS.at(static_cast(result)); +} + +/** + * \brief Check if the specified program requires firmware to run properly. + * It is the responsibility of the frontend to properly expose this to the user. + * \param program_id The program ID to check. + * \return Whether or not the program requires firmware to run properly. + */ +inline constexpr bool GameRequiresFirmware(u64 program_id) +{ + return std::find(FIRMWARE_REQUIRED_GAMES.begin(), FIRMWARE_REQUIRED_GAMES.end(), program_id) + != FIRMWARE_REQUIRED_GAMES.end(); +} + + +enum FirmwareCheckResult { + FirmwareGood, + ErrorFirmwareMissing, + ErrorFirmwareCorrupted, + ErrorFirmwareTooNew, +}; + +static constexpr std::array FIRMWARE_CHECK_STRINGS = { + "", + "Firmware missing. Firmware is required to run certain games and use the Home Menu. " + "Eden only works with firmware 19.0.1 and earlier.", + "Firmware reported as present, but was unable to be read. Check for decryption keys and " + "redump firmware if necessary.", + "Firmware is too new or could not be read. Eden only works with firmware 19.0.1 and earlier.", +}; + +/** + * \brief Checks for installed firmware within the system. + * \param system The system to check for firmware. + * \return Whether or not the system has installed firmware. + */ +inline bool CheckFirmwarePresence(Core::System &system) +{ + constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); + + auto bis_system = system.GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + return false; + } + + auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program); + + if (!mii_applet_nca) { + return false; + } + + return true; +} + +/** + * \brief Verifies if firmware is properly installed and is in the correct version range. + * \param system The system to check firmware on. + * \return A result code defining the status of the system's firmware. + */ +FirmwareCheckResult VerifyFirmware(Core::System &system); + +/** + * \brief Get a string representation of a result from CheckFirmwareVersion. + * \param result The result code. + * \return A string representation of the passed result code. + */ +inline constexpr const char *GetFirmwareCheckString(FirmwareCheckResult result) +{ + return FIRMWARE_CHECK_STRINGS.at(static_cast(result)); +} + +/** + * @brief Get the currently installed firmware version. + * @param system The system to check firmware on. + * @return A pair of the firmware version format and result code. + */ +inline std::pair GetFirmwareVersion(Core::System &system) +{ + Service::Set::FirmwareVersionFormat firmware_data{}; + const auto result + = Service::Set::GetFirmwareVersionImpl(firmware_data, + system, + Service::Set::GetFirmwareVersionType::Version2); + + return {firmware_data, result}; +} +} + +#endif // FIRMWARE_MANAGER_H diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp index 972eec8276..b904821619 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp @@ -7,6 +7,7 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" +#include namespace Shader::Maxwell { namespace { @@ -36,6 +37,17 @@ enum class ShuffleMode : u64 { } } +bool IsKONA() { + std::ifstream machineFile("/sys/devices/soc0/machine"); + if (machineFile.is_open()) { + std::string line; + std::getline(machineFile, line); + if (line == "KONA") + return true; + } + return false; +} + void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32& mask) { union { u64 insn; @@ -47,7 +59,10 @@ void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32 const IR::U32 result{ShuffleOperation(v.ir, v.X(shfl.src_reg), index, mask, shfl.mode)}; v.ir.SetPred(shfl.pred, v.ir.GetInBoundsFromOp(result)); - v.X(shfl.dest_reg, result); + if (IsKONA()) + v.X(shfl.dest_reg, v.ir.Imm32(0xffffffff)); // This fixes the freeze for Retroid / Snapdragon SD865 + else + v.X(shfl.dest_reg, result); } } // Anonymous namespace diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 0ce2abc627..8591378b1c 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -26,7 +26,9 @@ BufferCache

::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R void(slot_buffers.insert(runtime, NullBufferParams{})); gpu_modified_ranges.Clear(); inline_buffer_id = NULL_BUFFER_ID; - +#ifdef ANDROID + immediately_free = (Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive); +#endif if (!runtime.CanReportMemoryUsage()) { minimum_memory = DEFAULT_EXPECTED_MEMORY; critical_memory = DEFAULT_CRITICAL_MEMORY; @@ -416,7 +418,7 @@ void BufferCache

::UnbindGraphicsStorageBuffers(size_t stage) { } template -void BufferCache

::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, +bool BufferCache

::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset, bool is_written) { channel_state->enabled_storage_buffers[stage] |= 1U << ssbo_index; channel_state->written_storage_buffers[stage] |= (is_written ? 1U : 0U) << ssbo_index; @@ -425,6 +427,7 @@ void BufferCache

::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; channel_state->storage_buffers[stage][ssbo_index] = StorageBufferBinding(ssbo_addr, cbuf_index, is_written); + return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID); } template @@ -1383,6 +1386,8 @@ void BufferCache

::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, }); new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size); runtime.CopyBuffer(new_buffer, overlap, copies, true); + if (immediately_free) + runtime.Finish(); DeleteBuffer(overlap_id, true); } @@ -1674,7 +1679,9 @@ void BufferCache

::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { } Unregister(buffer_id); - delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); + + if (!do_not_mark || !immediately_free) + delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); slot_buffers.erase(buffer_id); if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index d45f595ea8..fbdf6e858b 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -159,7 +159,11 @@ template class BufferCache : public VideoCommon::ChannelSetupCaches { // Page size for caching purposes. // This is unrelated to the CPU page size and it can be changed as it seems optimal. +#ifdef ANDROID + static constexpr u32 CACHING_PAGEBITS = 12; +#else static constexpr u32 CACHING_PAGEBITS = 16; +#endif static constexpr u64 CACHING_PAGESIZE = u64{1} << CACHING_PAGEBITS; static constexpr bool IS_OPENGL = P::IS_OPENGL; @@ -173,9 +177,15 @@ class BufferCache : public VideoCommon::ChannelSetupCaches slot_buffers; - DelayedDestructionRing delayed_destruction_ring; +#ifdef ANDROID + static constexpr size_t TICKS_TO_DESTROY = 6; +#else + static constexpr size_t TICKS_TO_DESTROY = 8; +#endif + DelayedDestructionRing delayed_destruction_ring; const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{}; @@ -483,6 +498,7 @@ private: u64 minimum_memory = 0; u64 critical_memory = 0; BufferId inline_buffer_id; + bool immediately_free = false; std::array> CACHING_PAGEBITS)> page_table; Common::ScratchBuffer tmp_buffer; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 8a06adad79..538c4da85a 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -244,7 +247,7 @@ public: void InvalidateRegion(DAddr addr, u64 size); /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is - /// sensible, false otherwise + /// sensible, false otherwise, addr and size must be a valid combination bool OnCPUWrite(DAddr addr, u64 size); /// Notify rasterizer that any caches of the specified region should be flushed and invalidated diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp index 9b718f2591..d6eff2bdd7 100644 --- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp +++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp @@ -26,13 +26,14 @@ namespace { constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12; constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P; constexpr std::array PreferredGpuDecoders = { - AV_HWDEVICE_TYPE_CUDA, #ifdef _WIN32 + AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2, +#elif defined(__FreeBSD__) + AV_HWDEVICE_TYPE_VDPAU, #elif defined(__unix__) AV_HWDEVICE_TYPE_VAAPI, - AV_HWDEVICE_TYPE_VDPAU, #endif AV_HWDEVICE_TYPE_VULKAN, }; @@ -215,18 +216,16 @@ bool DecoderContext::OpenContext(const Decoder& decoder) { bool DecoderContext::SendPacket(const Packet& packet) { m_temp_frame = std::make_shared(); - - if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0) { + if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0 && ret != AVERROR_EOF) { LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret)); return false; } - return true; } std::shared_ptr DecoderContext::ReceiveFrame() { auto ReceiveImpl = [&](AVFrame* frame) -> bool { - if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0) { + if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0 && ret != AVERROR_EOF) { LOG_ERROR(HW_GPU, "avcodec_receive_frame error: {}", AVError(ret)); return false; } diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp index 293bca6d79..652d387031 100644 --- a/src/video_core/host1x/host1x.cpp +++ b/src/video_core/host1x/host1x.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -18,9 +21,11 @@ Host1x::~Host1x() = default; void Host1x::StartDevice(s32 fd, ChannelType type, u32 syncpt) { switch (type) { case ChannelType::NvDec: + std::call_once(nvdec_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer devices[fd] = std::make_unique(*this, fd, syncpt, frame_queue); break; case ChannelType::VIC: + std::call_once(vic_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer devices[fd] = std::make_unique(*this, fd, syncpt, frame_queue); break; default: diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h index 8debac93dd..5ecffa442c 100644 --- a/src/video_core/host1x/host1x.h +++ b/src/video_core/host1x/host1x.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -201,6 +204,8 @@ private: std::unique_ptr> allocator; FrameQueue frame_queue; std::unordered_map> devices; + std::once_flag nvdec_first_init; + std::once_flag vic_first_init; }; } // namespace Tegra::Host1x diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index af0a453ee7..b4417de703 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -128,7 +131,7 @@ bool Passes(const std::array& stage_infos, u32 enabled_mask) { return true; } -using ConfigureFuncPtr = void (*)(GraphicsPipeline*, bool); +using ConfigureFuncPtr = bool (*)(GraphicsPipeline*, bool); template ConfigureFuncPtr FindSpec(const std::array& stage_infos, u32 enabled_mask) { @@ -275,7 +278,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c } template -void GraphicsPipeline::ConfigureImpl(bool is_indexed) { +bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { std::array views; std::array samplers; size_t views_index{}; @@ -556,6 +559,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { if (image_binding != 0) { glBindImageTextures(0, image_binding, images.data()); } + + return true; } void GraphicsPipeline::ConfigureTransformFeedbackImpl() const { diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h index 2f70c1ae9c..66ab677919 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -80,8 +83,8 @@ public: const std::array& infos, const GraphicsPipelineKey& key_, bool force_context_flush = false); - void Configure(bool is_indexed) { - configure_func(this, is_indexed); + bool Configure(bool is_indexed) { + return configure_func(this, is_indexed); } void ConfigureTransformFeedback() const { @@ -107,7 +110,7 @@ public: template static auto MakeConfigureSpecFunc() { return [](GraphicsPipeline* pipeline, bool is_indexed) { - pipeline->ConfigureImpl(is_indexed); + return pipeline->ConfigureImpl(is_indexed); }; } @@ -118,7 +121,7 @@ public: private: template - void ConfigureImpl(bool is_indexed); + bool ConfigureImpl(bool is_indexed); void ConfigureTransformFeedbackImpl() const; @@ -134,7 +137,7 @@ private: StateTracker& state_tracker; const GraphicsPipelineKey key; - void (*configure_func)(GraphicsPipeline*, bool){}; + bool (*configure_func)(GraphicsPipeline*, bool){}; std::array source_programs; std::array assembly_programs; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 19f586518f..131b7463e0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -247,7 +250,8 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { program_manager.LocalMemoryWarmup(); } pipeline->SetEngine(maxwell3d, gpu_memory); - pipeline->Configure(is_indexed); + if (!pipeline->Configure(is_indexed)) + return; SyncState(); @@ -565,22 +569,17 @@ void RasterizerOpenGL::InvalidateRegion(DAddr addr, u64 size, VideoCommon::Cache bool RasterizerOpenGL::OnCPUWrite(DAddr addr, u64 size) { MICROPROFILE_SCOPE(OpenGL_CacheManagement); - if (addr == 0 || size == 0) { - return false; - } - + DEBUG_ASSERT(addr != 0 || size != 0); { std::scoped_lock lock{buffer_cache.mutex}; if (buffer_cache.OnCPUWrite(addr, size)) { return true; } } - { std::scoped_lock lock{texture_cache.mutex}; texture_cache.WriteMemory(addr, size); } - shader_cache.InvalidateRegion(addr, size); return false; } @@ -1204,24 +1203,24 @@ void RasterizerOpenGL::SyncLogicOpState() { } flags[Dirty::LogicOp] = false; - auto& regs = maxwell3d->regs; - - if (device.IsAmd()) { - using namespace Tegra::Engines; - struct In { - const Maxwell3D::Regs::VertexAttribute::Type d; - In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} - bool operator()(Maxwell3D::Regs::VertexAttribute n) const { - return n.type == d; - } - }; - - bool has_float = - std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), - In(Maxwell3D::Regs::VertexAttribute::Type::Float)); - regs.logic_op.enable = static_cast(!has_float); - } - + auto& regs = maxwell3d->regs; + + if (device.IsAmd()) { + using namespace Tegra::Engines; + struct In { + const Maxwell3D::Regs::VertexAttribute::Type d; + In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} + bool operator()(Maxwell3D::Regs::VertexAttribute n) const { + return n.type == d; + } + }; + + bool has_float = + std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), + In(Maxwell3D::Regs::VertexAttribute::Type::Float)); + regs.logic_op.enable = static_cast(!has_float); + } + if (regs.logic_op.enable) { glEnable(GL_COLOR_LOGIC_OP); glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.op)); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index e7cec364b6..eb757d68f5 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -175,7 +178,7 @@ bool Passes(const std::array& modules, return true; } -using ConfigureFuncPtr = void (*)(GraphicsPipeline*, bool); +using ConfigureFuncPtr = bool (*)(GraphicsPipeline*, bool); template ConfigureFuncPtr FindSpec(const std::array& modules, @@ -302,7 +305,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) { } template -void GraphicsPipeline::ConfigureImpl(bool is_indexed) { +bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { std::array views; std::array samplers; size_t sampler_index{}; @@ -321,8 +324,9 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { size_t ssbo_index{}; for (const auto& desc : info.storage_buffers_descriptors) { ASSERT(desc.count == 1); - buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index, - desc.cbuf_offset, desc.is_written); + if (!buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index, + desc.cbuf_offset, desc.is_written)) + return false; ++ssbo_index; } } @@ -382,6 +386,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { add_image(desc, desc.is_written); } } + + return true; }}; if constexpr (Spec::enabled_stages[0]) { config_stage(0); @@ -396,7 +402,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { config_stage(3); } if constexpr (Spec::enabled_stages[4]) { - config_stage(4); + if (!config_stage(4)) + return false; } texture_cache.FillGraphicsImageViews(std::span(views.data(), view_index)); @@ -490,6 +497,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { texture_cache.UpdateRenderTargets(false); texture_cache.CheckFeedbackLoop(views); ConfigureDraw(rescaling, render_area); + + return true; } void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 99e56e9ad8..7e9dbb583a 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -86,8 +89,8 @@ public: void AddTransition(GraphicsPipeline* transition); - void Configure(bool is_indexed) { - configure_func(this, is_indexed); + bool Configure(bool is_indexed) { + return configure_func(this, is_indexed); } [[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept { @@ -105,7 +108,7 @@ public: template static auto MakeConfigureSpecFunc() { - return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl(is_indexed); }; + return [](GraphicsPipeline* pl, bool is_indexed) { return pl->ConfigureImpl(is_indexed); }; } void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) { @@ -115,7 +118,7 @@ public: private: template - void ConfigureImpl(bool is_indexed); + bool ConfigureImpl(bool is_indexed); void ConfigureDraw(const RescalingPushConstant& rescaling, const RenderAreaPushConstant& render_are); @@ -134,7 +137,7 @@ private: Scheduler& scheduler; GuestDescriptorQueue& guest_descriptor_queue; - void (*configure_func)(GraphicsPipeline*, bool){}; + bool (*configure_func)(GraphicsPipeline*, bool){}; std::vector transition_keys; std::vector transitions; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 66f4668026..0243693049 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -226,7 +226,8 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; // update engine as channel may be different. pipeline->SetEngine(maxwell3d, gpu_memory); - pipeline->Configure(is_indexed); + if (!pipeline->Configure(is_indexed)) + return; UpdateDynamicStates(); @@ -636,22 +637,17 @@ void RasterizerVulkan::InnerInvalidation(std::span::max()}; + #ifdef ANDROID + static constexpr s64 TARGET_THRESHOLD = 3_GiB; + static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB; + static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB; + static constexpr size_t GC_EMERGENCY_COUNTS = 2; + #else static constexpr s64 TARGET_THRESHOLD = 4_GiB; static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB; static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB; static constexpr size_t GC_EMERGENCY_COUNTS = 2; + #endif using Runtime = typename P::Runtime; using Image = typename P::Image; @@ -479,7 +486,11 @@ private: }; Common::LeastRecentlyUsedCache lru_cache; + #ifdef ANDROID + static constexpr size_t TICKS_TO_DESTROY = 6; + #else static constexpr size_t TICKS_TO_DESTROY = 8; +#endif DelayedDestructionRing sentenced_images; DelayedDestructionRing sentenced_image_view; DelayedDestructionRing sentenced_framebuffers; diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e80808621b..04b362f9b0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -271,7 +271,10 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa VmaAllocation allocation{}; VkMemoryPropertyFlags property_flags{}; - vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); + VkResult result = vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info); + if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + LOG_ERROR(Render_Vulkan, "Out of memory creating buffer (size: {})", ci.size); + } vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); u8* data = reinterpret_cast(alloc_info.pMappedData); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 0dc6f562b8..34f2ba455a 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -462,8 +462,8 @@ if (WIN32 AND NOT YUZU_USE_BUNDLED_QT AND QT_VERSION VERSION_GREATER_EQUAL 6) endif() if (YUZU_USE_BUNDLED_QT) - include(CopyYuzuQt6Deps) - copy_yuzu_Qt6_deps(yuzu) + include(CopyYuzuQt6Deps) + copy_yuzu_Qt6_deps(yuzu) endif() if (ENABLE_SDL2) @@ -494,4 +494,8 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE yuzu-room) endif() +# Extra deps +add_subdirectory(externals) +target_link_libraries(yuzu PRIVATE QuaZip::QuaZip) + create_target_directory_groups(yuzu) diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 155dac412b..5408d485b4 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -157,13 +157,6 @@ Logging - - - - Open Log Location - - - @@ -224,6 +217,13 @@ + + + + Open Log Location + + + diff --git a/src/yuzu/externals/CMakeLists.txt b/src/yuzu/externals/CMakeLists.txt new file mode 100644 index 0000000000..d606e27108 --- /dev/null +++ b/src/yuzu/externals/CMakeLists.txt @@ -0,0 +1,17 @@ +# Disable tests in all externals supporting the standard option name +set(BUILD_TESTING OFF) + +# Build only static externals +set(BUILD_SHARED_LIBS OFF) + +# QuaZip +include(CPM) +set(CPM_SOURCE_CACHE ${CMAKE_SOURCE_DIR}/.cache/cpm) +set(CPM_USE_LOCAL_PACKAGES ON) + +CPMAddPackage( + NAME QuaZip-Qt6 + VERSION 1.3 + GIT_REPOSITORY "https://github.com/crueter/quazip-qt6.git" + GIT_TAG v1.5-qt6 +) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 13d2373f5d..6a575cfa87 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -10,6 +10,9 @@ #include "core/hle/service/am/applet_manager.h" #include "core/loader/nca.h" #include "core/tools/renderdoc.h" +#include "frontend_common/firmware_manager.h" + +#include #ifdef __APPLE__ #include // for chdir @@ -211,7 +214,7 @@ enum class CalloutFlag : uint32_t { * Some games perform worse or straight-up don't work with updates, * so this tracks which games are bad in this regard. */ -static const QList bad_update_games{ +constexpr std::array bad_update_games{ 0x0100F2C0115B6000 // Tears of the Kingdom }; @@ -1674,10 +1677,16 @@ void GMainWindow::ConnectMenuEvents() { connect_menu(ui->action_Configure_Tas, &GMainWindow::OnConfigureTas); // Help - connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); + connect_menu(ui->action_Root_Data_Folder, &GMainWindow::OnOpenRootDataFolder); + connect_menu(ui->action_NAND_Folder, &GMainWindow::OnOpenNANDFolder); + connect_menu(ui->action_SDMC_Folder, &GMainWindow::OnOpenSDMCFolder); + connect_menu(ui->action_Mod_Folder, &GMainWindow::OnOpenModFolder); + connect_menu(ui->action_Log_Folder, &GMainWindow::OnOpenLogFolder); + connect_menu(ui->action_Discord, &GMainWindow::OnOpenDiscord); connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); - connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); + connect_menu(ui->action_Firmware_From_Folder, &GMainWindow::OnInstallFirmware); + connect_menu(ui->action_Firmware_From_ZIP, &GMainWindow::OnInstallFirmwareFromZIP); connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys); connect_menu(ui->action_About, &GMainWindow::OnAbout); } @@ -1708,7 +1717,8 @@ void GMainWindow::UpdateMenuState() { action->setEnabled(emulation_running); } - ui->action_Install_Firmware->setEnabled(!emulation_running); + ui->action_Firmware_From_Folder->setEnabled(!emulation_running); + ui->action_Firmware_From_ZIP->setEnabled(!emulation_running); ui->action_Install_Keys->setEnabled(!emulation_running); for (QAction* action : applet_actions) { @@ -1884,46 +1894,61 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa QSettings settings; QStringList currentIgnored = settings.value("ignoredBadUpdates", {}).toStringList(); - for (const u64 id : bad_update_games) { - const bool ignored = currentIgnored.contains(QString::number(id)); + if (std::find(bad_update_games.begin(), bad_update_games.end(), params.program_id) != bad_update_games.end() + && !currentIgnored.contains(QString::number(params.program_id))) { + QMessageBox *msg = new QMessageBox(this); + msg->setWindowTitle(tr("Game Updates Warning")); + msg->setIcon(QMessageBox::Warning); + msg->setText(tr("The game you are trying to launch is known to have performance or booting " + "issues when updates are applied. Please try increasing the memory layout to " + "6GB or 8GB if any issues occur.

Press \"OK\" to continue launching, or " + "\"Cancel\" to cancel the launch.")); - if (params.program_id == id && !ignored) { - QMessageBox *msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Updates Warning")); - msg->setIcon(QMessageBox::Warning); - msg->setText(tr("The game you are trying to launch is known to have performance or booting " - "issues when updates are applied. Please try increasing the memory layout to " - "6GB or 8GB if any issues occur.

Press \"OK\" to continue launching, or " - "\"Cancel\" to cancel the launch.")); + msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - // TODO: TMP: Recommends more memory for TotK. + QCheckBox *dontShowAgain = new QCheckBox(msg); + dontShowAgain->setText(tr("Don't show again for this game")); + msg->setCheckBox(dontShowAgain); - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + int result = msg->exec(); - QCheckBox *dontShowAgain = new QCheckBox(msg); - dontShowAgain->setText(tr("Don't show again for this game")); - msg->setCheckBox(dontShowAgain); + // wtf + QMessageBox::ButtonRole role = msg->buttonRole(msg->button((QMessageBox::StandardButton) result)); - int result = msg->exec(); - - // wtf - QMessageBox::ButtonRole role = msg->buttonRole(msg->button((QMessageBox::StandardButton) result)); - - switch (role) { - - case QMessageBox::RejectRole: - return false; - - case QMessageBox::AcceptRole: - default: - if (dontShowAgain->isChecked()) { - currentIgnored << QString::number(params.program_id); - - settings.setValue("ignoredBadUpdates", currentIgnored); - settings.sync(); - } - break; + switch (role) { + case QMessageBox::RejectRole: + return false; + case QMessageBox::AcceptRole: + default: + if (dontShowAgain->isChecked()) { + currentIgnored << QString::number(params.program_id); + settings.setValue("ignoredBadUpdates", currentIgnored); + settings.sync(); } + break; + } + } + + if (FirmwareManager::GameRequiresFirmware(params.program_id) && !FirmwareManager::CheckFirmwarePresence(*system)) { + QMessageBox *msg = new QMessageBox(this); + msg->setWindowTitle(tr("Game Requires Firmware")); + msg->setIcon(QMessageBox::Warning); + msg->setText(tr("The game you are trying to launch requires firmware to boot or to get past the " + "opening menu. Please " + "dump and install firmware, or press \"OK\" to launch anyways.")); + + msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + + int exec_result = msg->exec(); + + QMessageBox::ButtonRole role = msg->buttonRole(msg->button((QMessageBox::StandardButton) exec_result)); + + switch (role) { + case QMessageBox::RejectRole: + return false; + case QMessageBox::AcceptRole: + default: + break; } } @@ -1940,7 +1965,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() | static_cast(CalloutFlag::DRDDeprecation); QMessageBox::warning( - this, tr("Warning Outdated Game Format"), + this, tr("Warning: Outdated Game Format"), tr("You are using the deconstructed ROM directory format for this game, which is an " "outdated format that has been superseded by others such as NCA, NAX, XCI, or " "NSP. Deconstructed ROM directories lack icons, metadata, and update " @@ -1963,7 +1988,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa "This is usually caused by outdated GPU drivers, including integrated ones. " "Please see the log for more details. " "For more information on accessing the log, please see the following page: " - "" + "" "How to Upload the Log File. ")); break; default: @@ -4159,11 +4184,35 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } } -void GMainWindow::OnOpenYuzuFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( +void GMainWindow::OnOpenRootDataFolder() { + QDesktopServices::openUrl(QUrl( QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); } +void GMainWindow::OnOpenNANDFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +} + +void GMainWindow::OnOpenSDMCFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +} + +void GMainWindow::OnOpenModFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +} + +void GMainWindow::OnOpenLogFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +} + void GMainWindow::OnVerifyInstalledContents() { // Initialize a progress dialog. QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); @@ -4194,26 +4243,8 @@ void GMainWindow::OnVerifyInstalledContents() { } } -void GMainWindow::OnInstallFirmware() { - // Don't do this while emulation is running, that'd probably be a bad idea. - if (emu_thread != nullptr && emu_thread->IsRunning()) { - return; - } - - // Check for installed keys, error out, suggest restart? - if (!ContentManager::AreKeysPresent()) { - QMessageBox::information( - this, tr("Keys not installed"), - tr("Install decryption keys and restart eden before attempting to install firmware.")); - return; - } - - const QString firmware_source_location = QFileDialog::getExistingDirectory( - this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly); - if (firmware_source_location.isEmpty()) { - return; - } - +void GMainWindow::InstallFirmware(const QString &location, bool recursive) +{ QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(100); @@ -4227,11 +4258,11 @@ void GMainWindow::OnInstallFirmware() { return progress.wasCanceled(); }; - LOG_INFO(Frontend, "Installing firmware from {}", firmware_source_location.toStdString()); + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in // there.) - std::filesystem::path firmware_source_path = firmware_source_location.toStdString(); + std::filesystem::path firmware_source_path = location.toStdString(); if (!Common::FS::IsDir(firmware_source_path)) { progress.close(); return; @@ -4249,7 +4280,12 @@ void GMainWindow::OnInstallFirmware() { QtProgressCallback(100, 10); - Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File); + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File); + } + if (out.size() <= 0) { progress.close(); QMessageBox::warning(this, tr("Firmware install failed"), @@ -4293,8 +4329,8 @@ void GMainWindow::OnInstallFirmware() { progress.close(); QMessageBox::warning( this, tr("Firmware install failed"), - tr("Firmware installation cancelled, firmware may be in bad state, " - "restart eden or re-install firmware.")); + tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " + "Restart Eden or re-install firmware.")); return; } } @@ -4332,6 +4368,93 @@ void GMainWindow::OnInstallFirmware() { OnCheckFirmware(); } +void GMainWindow::OnInstallFirmware() { + // Don't do this while emulation is running, that'd probably be a bad idea. + if (emu_thread != nullptr && emu_thread->IsRunning()) { + return; + } + + // Check for installed keys, error out, suggest restart? + if (!ContentManager::AreKeysPresent()) { + QMessageBox::information( + this, tr("Keys not installed"), + tr("Install decryption keys and restart Eden before attempting to install firmware.")); + return; + } + + const QString firmware_source_location = QFileDialog::getExistingDirectory( + this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly); + if (firmware_source_location.isEmpty()) { + return; + } + + InstallFirmware(firmware_source_location); +} + +void GMainWindow::OnInstallFirmwareFromZIP() +{ + // Don't do this while emulation is running, that'd probably be a bad idea. + if (emu_thread != nullptr && emu_thread->IsRunning()) { + return; + } + + // Check for installed keys, error out, suggest restart? + if (!ContentManager::AreKeysPresent()) { + QMessageBox::information( + this, tr("Keys not installed"), + tr("Install decryption keys and restart Eden before attempting to install firmware.")); + return; + } + + const QString firmware_zip_location = QFileDialog::getOpenFileName( + this, tr("Select Dumped Firmware ZIP"), {}, tr("Zipped Archives (*.zip)")); + if (firmware_zip_location.isEmpty()) { + return; + } + + namespace fs = std::filesystem; + fs::path tmp{std::filesystem::temp_directory_path()}; + + if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) { + goto unzipFailed; + } + + { + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(firmware_zip_location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + goto unzipFailed; + } + + // In this case, it has to be done recursively, since sometimes people + // will pack it into a subdirectory after dumping + InstallFirmware(qCacheDir, true); + + std::error_code ec; + std::filesystem::remove_all(tmp, ec); + + if (ec) { + QMessageBox::warning(this, tr("Firmware cleanup failed"), + tr("Failed to clean up extracted firmware cache.\n" + "Check write permissions in the system temp directory and try again.\nOS reported error: %1") + .arg(QString::fromStdString(ec.message()))); + } + + return; + } +unzipFailed: + QMessageBox::critical(this, tr("Firmware unzip failed"), + tr("Check write permissions in the system temp directory and try again.")); + return; + +} + void GMainWindow::OnInstallDecryptionKeys() { // Don't do this while emulation is running. if (emu_thread != nullptr && emu_thread->IsRunning()) { @@ -4339,72 +4462,27 @@ void GMainWindow::OnInstallDecryptionKeys() { } const QString key_source_location = QFileDialog::getOpenFileName( - this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {}, + this, tr("Select Dumped Keys Location"), {}, QStringLiteral("Decryption Keys (*.keys)"), {}, QFileDialog::ReadOnly); if (key_source_location.isEmpty()) { return; } - // Verify that it contains prod.keys, title.keys and optionally, key_retail.bin - LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString()); + FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys"); - const std::filesystem::path prod_key_path = key_source_location.toStdString(); - const std::filesystem::path key_source_path = prod_key_path.parent_path(); - if (!Common::FS::IsDir(key_source_path)) { - return; - } - - bool prod_keys_found = false; - std::vector source_key_files; - - if (Common::FS::Exists(prod_key_path)) { - prod_keys_found = true; - source_key_files.emplace_back(prod_key_path); - } - - if (Common::FS::Exists(key_source_path / "title.keys")) { - source_key_files.emplace_back(key_source_path / "title.keys"); - } - - if (Common::FS::Exists(key_source_path / "key_retail.bin")) { - source_key_files.emplace_back(key_source_path / "key_retail.bin"); - } - - // There should be at least prod.keys. - if (source_key_files.empty() || !prod_keys_found) { - QMessageBox::warning(this, tr("Decryption Keys install failed"), - tr("prod.keys is a required decryption key file.")); - return; - } - - const auto yuzu_keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir); - for (auto key_file : source_key_files) { - std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename(); - if (!std::filesystem::copy_file(key_file, destination_key_file, - std::filesystem::copy_options::overwrite_existing)) { - LOG_ERROR(Frontend, "Failed to copy file {} to {}", key_file.string(), - destination_key_file.string()); - QMessageBox::critical(this, tr("Decryption Keys install failed"), - tr("One or more keys failed to copy.")); - return; - } - } - - // Reinitialize the key manager, re-read the vfs (for update/dlc files), - // and re-populate the game list in the UI if the user has already added - // game folders. - Core::Crypto::KeyManager::Instance().ReloadKeys(); system->GetFileSystemController().CreateFactories(*vfs); game_list->PopulateAsync(UISettings::values.game_dirs); - if (ContentManager::AreKeysPresent()) { + switch (result) { + case FirmwareManager::KeyInstallResult::Success: QMessageBox::information(this, tr("Decryption Keys install succeeded"), tr("Decryption Keys were successfully installed")); - } else { + break; + default: QMessageBox::critical( this, tr("Decryption Keys install failed"), - tr("Decryption Keys failed to initialize. Check that your dumping tools are " - "up to date and re-dump keys.")); + tr(FirmwareManager::GetKeyInstallResultString(result))); + break; } OnCheckFirmwareDecryption(); @@ -5074,52 +5152,27 @@ void GMainWindow::OnCheckFirmwareDecryption() { void GMainWindow::OnCheckFirmware() { - if (!CheckFirmwarePresence()) { + auto result = FirmwareManager::VerifyFirmware(*system.get()); + + switch (result) { + case FirmwareManager::FirmwareGood: + break; + default: QMessageBox::warning( - this, tr("Firmware Missing"), - tr("Firmware missing. Firmware is required to run certain games and use the Home Menu.\n" - "Eden only works with firmware 19.0.1 and earlier.")); - } else { - Service::Set::FirmwareVersionFormat firmware_data{}; - const auto result = Service::Set::GetFirmwareVersionImpl( - firmware_data, *system, Service::Set::GetFirmwareVersionType::Version2); - - if (result.IsError()) { - LOG_INFO(Frontend, "Unable to read firmware"); - QMessageBox::warning( - this, tr("Firmware Corrupted"), - tr("Firmware reported as present, but was unable to be read. Check for decryption keys and redump firmware if necessary.")); - return; - } - - if (firmware_data.major > 19) { - QMessageBox::warning( - this, tr("Firmware Too New"), - tr("Firmware is too new. Eden only works with firmware 19.0.1 and earlier.")); - } + this, tr("Firmware Read Error"), + tr(FirmwareManager::GetFirmwareCheckString(result))); + break; } } bool GMainWindow::CheckFirmwarePresence() { - constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); - - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); - if (!bis_system) { - return false; - } - - auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program); - if (!mii_applet_nca) { - return false; - } - - return true; + return FirmwareManager::CheckFirmwarePresence(*system.get()); } void GMainWindow::SetFirmwareVersion() { - Service::Set::FirmwareVersionFormat firmware_data{}; - const auto result = Service::Set::GetFirmwareVersionImpl( - firmware_data, *system, Service::Set::GetFirmwareVersionType::Version2); + const auto pair = FirmwareManager::GetFirmwareVersion(*system.get()); + const auto firmware_data = pair.first; + const auto result = pair.second; if (result.IsError() || !CheckFirmwarePresence()) { LOG_INFO(Frontend, "Installed firmware: No firmware available"); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 84588f641a..7e7c00ec0b 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -387,9 +387,14 @@ private slots: void OnToggleAdaptingFilter(); void OnConfigurePerGame(); void OnLoadAmiibo(); - void OnOpenYuzuFolder(); + void OnOpenRootDataFolder(); + void OnOpenNANDFolder(); + void OnOpenSDMCFolder(); + void OnOpenModFolder(); + void OnOpenLogFolder(); void OnVerifyInstalledContents(); void OnInstallFirmware(); + void OnInstallFirmwareFromZIP(); void OnInstallDecryptionKeys(); void OnAbout(); void OnToggleFilterBar(); @@ -610,6 +615,8 @@ private: std::string arguments, const bool needs_title); + void InstallFirmware(const QString& location, bool recursive = false); + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 6b19d1f8f5..970f8d2901 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -57,6 +57,16 @@ &Recent Files + + + Open &Eden Folders + + + + + + + @@ -66,7 +76,7 @@ - + @@ -172,8 +182,15 @@ + + + Install Firmware + + + + - + @@ -388,11 +405,6 @@ &FAQ - - - Open &eden Folder - - false @@ -479,11 +491,6 @@ Open &Controller Menu - - - Install Firmware - - Install Decryption Keys @@ -517,6 +524,41 @@ &Application Menu + + + &Root Data Folder + + + + + &NAND Folder + + + + + &SDMC Folder + + + + + &Mod Folder + + + + + &Log Folder + + + + + From Folder + + + + + From ZIP + + diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 005f5bf1db..c1d714be77 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -80,6 +83,7 @@ static void PrintHelp(const char* argv0) { " Nickname, password, address and port for multiplayer\n" "-p, --program Pass following string as arguments to executable\n" "-u, --user Select a specific user profile from 0 to 7\n" + "-d, --debug Run the GDB stub on a port from 1 to 65535\n" "-v, --version Output version information and exit\n"; } @@ -162,24 +166,22 @@ static void OnMessageReceived(const Network::ChatEntry& msg) { } static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) { - std::string message; - switch (msg.type) { - case Network::IdMemberJoin: - message = fmt::format("{} has joined", msg.nickname); - break; - case Network::IdMemberLeave: - message = fmt::format("{} has left", msg.nickname); - break; - case Network::IdMemberKicked: - message = fmt::format("{} has been kicked", msg.nickname); - break; - case Network::IdMemberBanned: - message = fmt::format("{} has been banned", msg.nickname); - break; - case Network::IdAddressUnbanned: - message = fmt::format("{} has been unbanned", msg.nickname); - break; - } + std::string message = [&]() { + switch (msg.type) { + case Network::IdMemberJoin: + return fmt::format("{} has joined", msg.nickname); + case Network::IdMemberLeave: + return fmt::format("{} has left", msg.nickname); + case Network::IdMemberKicked: + return fmt::format("{} has been kicked", msg.nickname); + case Network::IdMemberBanned: + return fmt::format("{} has been banned", msg.nickname); + case Network::IdAddressUnbanned: + return fmt::format("{} has been unbanned", msg.nickname); + default: + return std::string{}; + } + }(); if (!message.empty()) std::cout << std::endl << "* " << message << std::endl << std::endl; } @@ -209,10 +211,10 @@ int main(int argc, char** argv) { } #endif std::string filepath; - std::optional config_path; + std::optional config_path{}; std::string program_args; - std::optional selected_user; - + std::optional selected_user{}; + std::optional override_gdb_port{}; bool use_multiplayer = false; bool fullscreen = false; std::string nickname{}; @@ -222,6 +224,7 @@ int main(int argc, char** argv) { static struct option long_options[] = { // clang-format off + {"debug", no_argument, 0, 'd'}, {"config", required_argument, 0, 'c'}, {"fullscreen", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, @@ -235,9 +238,12 @@ int main(int argc, char** argv) { }; while (optind < argc) { - int arg = getopt_long(argc, argv, "g:fhvp::c:u:", long_options, &option_index); + int arg = getopt_long(argc, argv, "g:fhvp::c:u:d:", long_options, &option_index); if (arg != -1) { switch (static_cast(arg)) { + case 'd': + override_gdb_port = static_cast(atoi(optarg)); + break; case 'c': config_path = optarg; break; @@ -323,6 +329,11 @@ int main(int argc, char** argv) { Settings::values.current_user = std::clamp(*selected_user, 0, 7); } + if (override_gdb_port.has_value()) { + Settings::values.use_gdbstub = true; + Settings::values.gdbstub_port = *override_gdb_port; + } + #ifdef _WIN32 LocalFree(argv_w); #endif diff --git a/tools/update-cpm.sh b/tools/update-cpm.sh new file mode 100755 index 0000000000..30e400209d --- /dev/null +++ b/tools/update-cpm.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +wget -O CMakeModules/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake