diff --git a/.github/workflows/LINUX_BUILD_TEST.yml b/.github/workflows/LINUX_BUILD_TEST.yml index 11545d9870..d3dcb86516 100644 --- a/.github/workflows/LINUX_BUILD_TEST.yml +++ b/.github/workflows/LINUX_BUILD_TEST.yml @@ -13,7 +13,7 @@ on: env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true - LLVM-VERSION: 14 + LLVM-VERSION: 18 BENCHMARK_BRANCH: 'make-file-build-system' # The branch inside the benchmark repo that has the script to run all benchmarks. PAT: ${{ secrets.SIMENGUOB_PAT }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 542049f2f8..b8f4379b98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.13) include(FetchContent) include(CheckCXXCompilerFlag) +include(ProcessorCount) set(FETCHCONTENT_QUIET OFF) # FetchContent_MakeAvailable was introduced in 3.14 @@ -14,21 +15,15 @@ macro(FetchContent_MakeAvailable_Args NAME ARGS) endif() endmacro() -# Need an additional macro for LLVM as a sub-directory needs to be targeted for llvm-14.0.5 -macro(FetchContent_MakeAvailable_SubDir_Args NAME SUBDIR ARGS) - FetchContent_GetProperties(${NAME}) - if(NOT ${NAME}_POPULATED) - FetchContent_Populate(${NAME}) - add_subdirectory(${${NAME}_SOURCE_DIR}/${SUBDIR}/ ${${NAME}_BINARY_DIR} ${ARGS}) - endif() -endmacro() - -# we don't use git for LLVM here as it clones the entire LLVM repo which takes too long and we only need a small part of it +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") + cmake_policy(SET CMP0135 NEW) +endif() +# we don't use git for LLVM here as it clones the entire LLVM repo which takes too long and we only need a relatively small part of it FetchContent_Declare( - llvm - URL https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.5/llvm-14.0.5.src.tar.xz - URL_HASH MD5=6bd202e403d950c78985048ce499a518 + llvm + URL https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/llvm-project-18.1.8.src.tar.xz + URL_HASH MD5=81cd0be5ae6f1ad8961746116d426a96 ) FetchContent_Declare( @@ -39,14 +34,13 @@ FetchContent_Declare( GIT_PROGRESS TRUE ) +# WARNING: When updating capstone version, we MUST make a new, discrete branch in the UoB-HPC Capstone fork to ensure +# current / previous SimEng versions continue to operate correctly. FetchContent_Declare( capstone-lib GIT_REPOSITORY https://github.com/UoB-HPC/capstone.git - GIT_TAG next + GIT_TAG next-update # Branch for SimEng version 0.9.7 GIT_PROGRESS TRUE - - # Old Git tag pre-Armv9.2 - # GIT_TAG e7be7d99e718ef9741026b80fc6f5e100fdf4f94 # trunk ) cmake_policy(SET CMP0048 NEW) @@ -89,20 +83,26 @@ set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable Capstone shared library") set(CAPSTONE_BUILD_CSTOOL OFF CACHE BOOL "Disable cstool build") set(CAPSTONE_INSTALL OFF CACHE BOOL "Disable install of capstone") -set(CAPSTONE_ARM_SUPPORT OFF CACHE BOOL "Disable A32 support") +set(CAPSTONE_ARM_SUPPORT OFF CACHE BOOL "Disable Arm32 support") set(CAPSTONE_MIPS_SUPPORT OFF CACHE BOOL "Disable MIPS support") -set(CAPSTONE_X86_SUPPORT OFF CACHE BOOL "Disable x86 support") set(CAPSTONE_PPC_SUPPORT OFF CACHE BOOL "Disable PowerPC support") +set(CAPSTONE_X86_SUPPORT OFF CACHE BOOL "Disable x86 support") set(CAPSTONE_SPARC_SUPPORT OFF CACHE BOOL "Disable Sparc support") -set(CAPSTONE_SYSZ_SUPPORT OFF CACHE BOOL "Disable SystemZ support") +set(CAPSTONE_SYSTEMZ_SUPPORT OFF CACHE BOOL "Disable SystemZ support") set(CAPSTONE_XCORE_SUPPORT OFF CACHE BOOL "Disable XCore support") set(CAPSTONE_M68K_SUPPORT OFF CACHE BOOL "Disable M68K support") -set(CAPSTONE_TMS320C64X_SUPPORT OFF CACHE BOOL "Disable TMS320C64x") +set(CAPSTONE_TMS320C64X_SUPPORT OFF CACHE BOOL "Disable TMS320C64x support") set(CAPSTONE_M680X_SUPPORT OFF CACHE BOOL "Disable M680x support") set(CAPSTONE_EVM_SUPPORT OFF CACHE BOOL "Disable EVM support") -set(CAPSTONE_MOS65XX_SUPPORT OFF CACHE BOOL "Disable MSO65XX support") set(CAPSTONE_WASM_SUPPORT OFF CACHE BOOL "Disable WASM support") +set(CAPSTONE_MOS65XX_SUPPORT OFF CACHE BOOL "Disable MSO65XX support") set(CAPSTONE_BPF_SUPPORT OFF CACHE BOOL "Disable BPF support") +set(CAPSTONE_SH_SUPPORT OFF CACHE BOOL "Disable SH support") +set(CAPSTONE_TRICORE_SUPPORT OFF CACHE BOOL "Disable TriCore support") +set(CAPSTONE_ALPHA_SUPPORT OFF CACHE BOOL "Disable Alpha support") +set(CAPSTONE_HPPA_SUPPORT OFF CACHE BOOL "Disable HPPA support") +set(CAPSTONE_LOONGARCH_SUPPORT OFF CACHE BOOL "Disable LoongArch support") + FetchContent_MakeAvailable_Args(capstone-lib EXCLUDE_FROM_ALL) include_directories("${capstone_BINARY_DIR}/include" "${capstone_SOURCE_DIR}/include") @@ -149,46 +149,89 @@ if(SIMENG_ENABLE_TESTS) find_package(LLVM REQUIRED CONFIG NO_CMAKE_BUILDS_PATH) # Check LLVM version - if ((${LLVM_PACKAGE_VERSION} VERSION_LESS "8.0") OR (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL "14.1")) - message(FATAL_ERROR "LLVM version must be >= 8.0 and <= 14.0") + if ((${LLVM_PACKAGE_VERSION} VERSION_LESS "8.0") OR (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL "18.2")) + message(FATAL_ERROR "LLVM version must be >= 8.0 and < 18.2") endif() # Print message containing if the full test suite will run if (${LLVM_PACKAGE_VERSION} VERSION_LESS "14.0") message(STATUS "LLVM version does not support AArch64 extensions SME or SVE2. These test suites will be skipped.") endif() + if (${LLVM_PACKAGE_VERSION} VERSION_LESS "18.0") + message(STATUS "LLVM version does not support AArch64 extensions SME2. These test suites will be skipped.") + endif() else() - - set(LLVM_TARGETS_TO_BUILD "AArch64;RISCV" CACHE INTERNAL "") - - set(LLVM_BUILD_RUNTIME OFF) - - set(LLVM_BUILD_TOOLS OFF) - set(LLVM_INCLUDE_TOOLS OFF) - - set(LLVM_BUILD_EXAMPLES OFF) - set(LLVM_INCLUDE_EXAMPLES OFF) - - set(LLVM_BUILD_TESTS OFF) - set(LLVM_INCLUDE_TESTS OFF) - - set(LLVM_BUILD_BENCHMARKS OFF) - set(LLVM_INCLUDE_BENCHMARKS OFF) - - set(LLVM_BUILD_DOCS OFF) - set(LLVM_INCLUDE_DOCS OFF) - - set(LLVM_INCLUDE_DOCS OFF) - set(LLVM_ENABLE_BINDINGS OFF) - set(LLVM_INSTALL_UTILS OFF) - - set(LLVM_ENABLE_WARNINGS OFF) - - # XXX all LLVM specific cmake variables must be set BEFORE FetchContent_MakeAvailable otherwise they have no effect - FetchContent_MakeAvailable_SubDir_Args(llvm llvm-14.0.5.src EXCLUDE_FROM_ALL) - # make sure we get the headers too - include_directories("${llvm_BINARY_DIR}/include" "${llvm_SOURCE_DIR}/include") + # If external LLVM not provided, download LLVM and build only what we need. Then point SimEng to use this sub-build + FetchContent_GetProperties(llvm) + if(NOT llvm_POPULATED) + FetchContent_Populate(llvm) + + set(COMMAND_ECHO_OPTION "") + # COMMAND_ECHO supported only in CMake >= 3.15 + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.15") + set(COMMAND_ECHO_OPTION COMMAND_ECHO STDOUT) + endif() + + execute_process( + COMMAND ${CMAKE_COMMAND} + -S ${llvm_SOURCE_DIR}/llvm + -B ${llvm_BINARY_DIR} + -DCMAKE_WARN_DEPRECATED=OFF + -DCMAKE_INSTALL_MESSAGE=LAZY + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${llvm_BINARY_DIR}/dist + -DCMAKE_SKIP_RPATH=OFF # keep the rpath prefix to avoid libLLVM.so + -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE_MAKEFILE} + -G${CMAKE_GENERATOR} + + -DLLVM_INCLUDE_BENCHMARKS=OFF + -DLLVM_INCLUDE_TESTS=OFF + -DLLVM_INCLUDE_DOCS=OFF + -DLLVM_INCLUDE_EXAMPLES=OFF + -DLLVM_BUILD_TESTS=OFF + -DLLVM_BUILD_DOCS=OFF + -DLLVM_BUILD_RUNTIME=OFF + -DLLVM_BUILD_TOOLS=OFF + -DLLVM_BUILD_EXAMPLES=OFF + -DLLVM_ENABLE_BINDINGS=OFF + -DLLVM_ENABLE_WARNINGS=OFF + "-DLLVM_TARGETS_TO_BUILD=AArch64\\;RISCV" + + ${COMMAND_ECHO_OPTION} + RESULT_VARIABLE SUCCESS) + + # TODO: replace with COMMAND_ERROR_IS_FATAL in the future (>= 3.19) + if (NOT SUCCESS EQUAL "0") + message(FATAL_ERROR "LLVM configure did not succeed") + else () + message(STATUS "LLVM configuration complete, starting build...") + endif () + + ProcessorCount(NPROC) + execute_process( + COMMAND ${CMAKE_COMMAND} + --build ${llvm_BINARY_DIR} + --target + # The full list of targets can be discovered via `ninja -t targets` inside the build + install-LLVMObject + install-LLVMAArch64AsmParser + install-LLVMRISCVAsmParser + # We also include the headers and CMake exports for a *complete* build + install-llvm-headers + install-cmake-exports + -j ${NPROC} + + ${COMMAND_ECHO_OPTION} + RESULT_VARIABLE SUCCESS) + + # TODO: replace with COMMAND_ERROR_IS_FATAL in the future (>= 3.19) + if (NOT SUCCESS EQUAL "0") + message(FATAL_ERROR "LLVM build did not succeed") + endif () + endif() find_package(LLVM REQUIRED CONFIG NO_DEFAULT_PATH PATHS "${llvm_BINARY_DIR}/lib/cmake/llvm") @@ -238,10 +281,10 @@ if (SIMENG_ENABLE_SST) endif() else() message(WARNING "SST build was selected but SST install directory was not specified. - Please specify -DSST_INSTALL_DIR= for the SST build to proceed.") + Please specify -DSST_INSTALL_DIR= for the SST build to proceed.") endif() endif() # Install SimEng model configs in the build directory set(SIMENG_CONFIG_INSTALL_DIR "${CMAKE_BINARY_DIR}/simeng-configs") -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/configs/ DESTINATION ${SIMENG_CONFIG_INSTALL_DIR}) \ No newline at end of file +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/configs/ DESTINATION ${SIMENG_CONFIG_INSTALL_DIR}) diff --git a/configs/a64fx_SME.yaml b/configs/a64fx_SME.yaml index b10f955f6f..7fe7086d5e 100644 --- a/configs/a64fx_SME.yaml +++ b/configs/a64fx_SME.yaml @@ -21,7 +21,8 @@ Register-Set: FloatingPoint/SVE-Count: 128 Predicate-Count: 48 Conditional-Count: 128 - Matrix-Count: 2 + SME-Matrix-Count: 2 + SME-Lookup-Table-Count: 8 Pipeline-Widths: Commit: 4 FrontEnd: 4 diff --git a/docs/sphinx/developer/arch/index.rst b/docs/sphinx/developer/arch/index.rst index 6541ba55e2..e8f90085fd 100644 --- a/docs/sphinx/developer/arch/index.rst +++ b/docs/sphinx/developer/arch/index.rst @@ -5,7 +5,7 @@ SimEng architecture definitions are responsible for describing the features and To achieve this, SimEng defines a set of abstract architecture-related classes. Discrete implementations of these classes are provided for each of the ISAs SimEng supports by default, and must also be implemented for adding support for new or custom ISAs. -ISA support is achieved through the use of the `Capstone `_ disassembly framework, which disassembles a binary instruction into a C/C++ object that include operand registers, access types, and immediate values to name a few. In order to update SimEng's AArch64 support from Armv8.4-a to Armv9.2-a, we undertook a Capstone update to allow for disassembly of the Armv9.2-a ISA. The work done for this can be found `here `_, and other useful ISA updating tools present in Capstone can be found `here `_. +ISA support is achieved through the use of an in-house fork of the `Capstone `_ disassembly framework, which disassembles a binary instruction into a C/C++ object that includes operand registers, access types, and immediate values to name a few. In order to update SimEng's AArch64 support from Armv8.4-a to Armv9.2-a, we undertook a Capstone update to allow for disassembly of the Armv9.2-a ISA. The work done for this can be found `here `_. Extensive work continues to be done to Capstone by its community in order to allow for easier updating of ISA versions. This facilitated the recent update of SimEng's AArch64 ISA support to Armv9.4-a. Below provides more information on the abstract structure of a SimEng architecture and currently supported ISAs. diff --git a/docs/sphinx/developer/arch/supported/aarch64.rst b/docs/sphinx/developer/arch/supported/aarch64.rst index 092264e991..464113e8fc 100644 --- a/docs/sphinx/developer/arch/supported/aarch64.rst +++ b/docs/sphinx/developer/arch/supported/aarch64.rst @@ -1,7 +1,7 @@ AArch64 ======= -SimEng provides an implementation of the 64-bit AArch64 architecture, specifically the Armv9.2-a ISA. This implementation provides support for decoding and executing a range of common instructions, sufficient to run a number of simple benchmarks. It is also capable of handling supervisor call (syscall) exceptions via basic system call emulation, allowing the execution of programs that have been statically compiled with the standard library. +SimEng provides an implementation of the 64-bit AArch64 architecture, specifically the Armv9.4-a ISA. This implementation provides support for decoding and executing a range of common instructions, sufficient to run a number of simple benchmarks. It is also capable of handling supervisor call (syscall) exceptions via basic system call emulation, allowing the execution of programs that have been statically compiled with the standard library. .. contents:: Contents @@ -135,7 +135,8 @@ There are several useful variables that execution behaviours have access to: ``results`` This is the output vector, into which ``RegisterValue`` instances containing the results should be placed. Each entry in the vector corresponds to a destination register. - Some instructions have "implicit" destination registers: in these cases, the implicit destinations are added to the start of the results vector. For example, ``subs w0, w1, #1`` writes explicitly to ``w0``, but also implicitly sets the "NZCV" comparison flags. In this case, ``results[0]`` is expected to be the updated NZCV flags, while ``results[1]`` is expected to be the new value of ``w0``. + Some instructions have "implicit" destination registers: in these cases, the implicit destinations are added to the **start** of the results vector. For example, ``subs w0, w1, #1`` writes explicitly to ``w0``, but also implicitly sets the "NZCV" comparison flags. In this case, ``results[0]`` is expected to be the updated NZCV flags, while ``results[1]`` is expected to be the new value of ``w0``. + Some Load and Store instructions update the base memory address register (pre- or post-indexing). These registers are also classed as implicit destination registers and thus will be added to the start of the results vector. For example, ``ldr x1, [x0], #8`` writes explicitly to ``x1`` but also writes implicitly to ``x0``. In this case, ``results[0]`` is expected to be the updated ``x0`` value (``x0 + 8``) and ``results[1]`` is expected to be the new value of ``x1``. Memory instructions may have a "writeback" variant, where the register containing the address is updated by an offset during execution. In these cases, the address register is added as a destination *after* the other registers, corresponding with the textual representation of the registers. E.g., the instruction ``ldr x1, [x2, #8]!`` will expect the value of ``x1`` in ``results[0]``, while the updated address ``x2`` should be placed in ``results[1]``. @@ -158,6 +159,8 @@ SME instructions can also operate on sub-tile slices; individual rows or columns Furthermore, a similar situation is present when a sub-tile slice is a destination operand. The ``results`` vector will expect a ``registerValue`` entry for each row of the targeted sub-tile, again due to the same two reasons listed previously. But, when a sub-tile slice is a destination operand, **all** associated rows of the sub-tile will also be added to the ``sourceValues_`` vector. Again, this is down to two key, similar reasons. First, when a destination is a sub-tile slice, we only want to update that row or column. As the we are unable to calculate which slice will be our destination before execution has commenced, all possible slices must be added to the ``results`` vector. If we were to not provide a ``RegisterValue`` to each entry of the ``results`` vector, the default value is 0. Therefore, in order to not zero-out the other slices within the sub-tile we will need access to their current values. Secondly, if the destination is a vertical slice (or sub-tile column) then only one element per row should be updated; the rest should remain unchanged. +Additionally, a fixed width 512-bit register ``ZT0`` was introduced with SME2 and is also now supported by SimEng. It can be treated in the same way as an SVE vector register. + Before implementing any further SME functionality we highly recommend familiarising yourself with the specification; found `here `_. .. Note:: We strongly encourage adding regression tests for each implemented instruction at the same time as adding execution behaviour to ensure functional validity. @@ -184,7 +187,7 @@ cstool Capstone provides a ``cstool`` utility, which provides a visual representation of the ``metadata`` information available for any given instruction. For example, feeding it the bytes for the ``str`` instruction displayed above results in the following:: - $ cstool -d arm64 f30f1ef8 + $ cstool -d -r aarch64 f30f1ef8 0 f3 0f 1e f8 str x19, [sp, #-0x20]! op_count: 2 operands[0].type: REG = x19 @@ -223,9 +226,7 @@ Concerning SVE & SME loads and stores, an effort should be made to merge contigu Instruction aliases ******************* -As Capstone is primarily a disassembler, it will attempt to generate the correct aliases for instructions: for example, the ``cmp w0, #0`` instruction is an alias for ``subs wzr, w0, #0``. As it's the underlying instruction that is of use (in this case, the ``subs`` instruction), this implementation includes a de-aliasing component that reverses this conversion. The logic for this may be found in ``src/lib/arch/aarch64/InstructionMetadata``. - -If a known but unsupported alias is encountered, it will generate an invalid instruction error, and the output will identify the instruction as unknown in place of the usual textual representation. It is recommended to reference a disassembled version of the program to identify what the instruction at this address should be correctly disassembled to, and implement the necessary dealiasing logic accordingly. +Although Capstone has been configured to produce the disassembly information for the "real" instruction rather than that of its (preferred) alias, the instruction's mnemonic and operand string will still be that of its alias. Hence, if an exception occurs the printed instruction information may not match the internal opcode used. Common Instruction Execution behaviour issues ********************************************* diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index ac7026f9a9..55d09d38ac 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -50,7 +50,7 @@ SimEng places an emphasis on performance and ease of use, whilst maintaining a c Features -------- -Currently, SimEng targets the Armv9.2-a ISA with support for the SVE, SVE2, and SME extensions as well as RISC-V rv64imafdc. SimEng has the ability to model up to out-of-order, superscalar, single-core processors, and to emulate a subset of Linux system-calls. It supports statically compiled C and Fortran binaries that run on real hardware, with additional support for single-threaded OpenMP binaries too. Internally, SimEng currently models memory as an infinite L1 cache, i.e. it assumes that all loads and stores hit the L1 cache. However, we have a tested integration with the `Structural Simulation Toolkit `_ (SST) allowing for a full memory model to be simulated; more information can be found in the :doc:`SST Integration section `. +Currently, SimEng targets the Armv9.4-a ISA with support for the SVE, SVE2, SME, and SME2 extensions as well as RISC-V rv64imafdc. SimEng has the ability to model up to out-of-order, superscalar, single-core processors, and to emulate a subset of Linux system-calls. It supports statically compiled C and Fortran binaries that run on real hardware, with additional support for single-threaded OpenMP binaries too. Internally, SimEng currently models memory as an infinite L1 cache, i.e. it assumes that all loads and stores hit the L1 cache. However, we have a tested integration with the `Structural Simulation Toolkit `_ (SST) allowing for a full memory model to be simulated; more information can be found in the :doc:`SST Integration section `. The main component provided by the simulator is a discrete processor core model, shown in diagrammatic form below. This model accepts a clock signal and supports a memory access interface. A single YAML format configuration file can be passed to the simulation to specify models of existing microarchitectures, such as Marvell's ThunderX2 or Fujitsu's A64fx, or to model hypothetical core designs. @@ -107,7 +107,6 @@ Current development team: - Jack Jones (lead developer) - Finn Wilkinson -- Rahat Muneeb - Dan Weaver - Alex Cockrean - Joseph Moore @@ -121,6 +120,7 @@ Additional Contributors: - Ainsley Rutterford - Andrei Poenaru +- Rahat Muneeb - Harry Waugh - Mutalib Mohammed - Seunghun Lee diff --git a/docs/sphinx/user/building_simeng.rst b/docs/sphinx/user/building_simeng.rst index 1a5cd41123..ed701ada40 100644 --- a/docs/sphinx/user/building_simeng.rst +++ b/docs/sphinx/user/building_simeng.rst @@ -41,7 +41,7 @@ With this configuration, the build files will be generated in a directory called More information about the LLVM_DIR value can be found `here `_. .. Note:: - LLVM versions greater than 14 or less than 8 are not supported. We'd recommend using LLVM 14.0.5 where possible as this has been verified by us to work correctly. + LLVM versions greater than 18.2 or less than 8 are not supported. We'd recommend using LLVM 18.1.8 where possible as this has been verified by us to work correctly for the most recent version of SimEng. LLVM versions less than 14 will likely not support AArch64 SVE2, SME, or SME2 instructions. b. Two additional flags are available when building SimEng. Firstly is ``-DSIMENG_SANITIZE={ON, OFF}`` which adds a selection of sanitisation compilation flags (primarily used during the development of the framework). Secondly is ``-SIMENG_OPTIMIZE={ON, OFF}`` which attempts to optimise the framework's compilation for the host machine through a set of compiler flags and options. diff --git a/docs/sphinx/user/configuring_simeng.rst b/docs/sphinx/user/configuring_simeng.rst index 765e8c7e45..9a49893375 100644 --- a/docs/sphinx/user/configuring_simeng.rst +++ b/docs/sphinx/user/configuring_simeng.rst @@ -99,9 +99,12 @@ AArch64 - Conditional-Count The number of physical status/flag/conditional-code registers. -- Matrix-Count (Optional) +- SME-Matrix-Count (Optional) The number of physical ``za`` Arm SME registers. +- SME-Lookup-Table-Count (Optional) + The number of physical SME Lookup Table registers (``zt0``). + RISC-V - GeneralPurpose-Count diff --git a/src/include/simeng/arch/aarch64/ArchInfo.hh b/src/include/simeng/arch/aarch64/ArchInfo.hh index bbd764c757..1403da08f8 100644 --- a/src/include/simeng/arch/aarch64/ArchInfo.hh +++ b/src/include/simeng/arch/aarch64/ArchInfo.hh @@ -11,14 +11,14 @@ namespace aarch64 { class ArchInfo : public simeng::arch::ArchInfo { public: ArchInfo(ryml::ConstNodeRef config) - : sysRegisterEnums_({arm64_sysreg::ARM64_SYSREG_DCZID_EL0, - arm64_sysreg::ARM64_SYSREG_FPCR, - arm64_sysreg::ARM64_SYSREG_FPSR, - arm64_sysreg::ARM64_SYSREG_TPIDR_EL0, - arm64_sysreg::ARM64_SYSREG_MIDR_EL1, - arm64_sysreg::ARM64_SYSREG_CNTVCT_EL0, - arm64_sysreg::ARM64_SYSREG_PMCCNTR_EL0, - arm64_sysreg::ARM64_SYSREG_SVCR}), + : sysRegisterEnums_({aarch64_sysreg::AARCH64_SYSREG_DCZID_EL0, + aarch64_sysreg::AARCH64_SYSREG_FPCR, + aarch64_sysreg::AARCH64_SYSREG_FPSR, + aarch64_sysreg::AARCH64_SYSREG_TPIDR_EL0, + aarch64_sysreg::AARCH64_SYSREG_MIDR_EL1, + aarch64_sysreg::AARCH64_SYSREG_CNTVCT_EL0, + aarch64_sysreg::AARCH64_SYSREG_PMCCNTR_EL0, + aarch64_sysreg::AARCH64_SYSREG_SVCR}), zaSize_(config["Core"]["Streaming-Vector-Length"].as() / 8) { // Generate the architecture-defined architectural register structure archRegStruct_ = { @@ -27,7 +27,8 @@ class ArchInfo : public simeng::arch::ArchInfo { {32, 17}, // Predicate {1, 1}, // NZCV {8, static_cast(sysRegisterEnums_.size())}, // System - {256, zaSize_} // Matrix (Each row is a register) + {256, zaSize_}, // Matrix (Each row is a register) + {64, 1} // SME ZT0 table register (fixed width of 512-bit) }; // Generate the config-defined physical register structure and quantities @@ -36,23 +37,26 @@ class ArchInfo : public simeng::arch::ArchInfo { uint16_t fpCount = regConfig["FloatingPoint/SVE-Count"].as(); uint16_t predCount = regConfig["Predicate-Count"].as(); uint16_t condCount = regConfig["Conditional-Count"].as(); - uint16_t matCount = regConfig["Matrix-Count"].as(); - // Matrix-Count multiplied by (SVL/8) as internal representation of ZA is a - // block of row-vector-registers. Therefore, we need to convert physical - // counts from whole-ZA to rows-in-ZA. + uint16_t matCount = regConfig["SME-Matrix-Count"].as(); + uint16_t tabCount = regConfig["SME-Lookup-Table-Count"].as(); + // SME-Matrix-Count multiplied by (SVL/8) as internal representation of ZA + // is a block of row-vector-registers. Therefore, we need to convert + // physical counts from whole-ZA to rows-in-ZA. matCount *= zaSize_; physRegStruct_ = {{8, gpCount}, {256, fpCount}, {32, predCount}, {1, condCount}, {8, static_cast(sysRegisterEnums_.size())}, - {256, matCount}}; + {256, matCount}, + {64, tabCount}}; physRegQuantities_ = {gpCount, fpCount, predCount, condCount, static_cast(sysRegisterEnums_.size()), - matCount}; + matCount, + tabCount}; } /** Get the set of system register enums currently supported. */ diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 76e74d7eb7..b5f1f07cc5 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -8,7 +8,7 @@ #include "simeng/arch/aarch64/operandContainer.hh" #include "simeng/branchpredictors/BranchPredictor.hh" -struct cs_arm64_op; +struct cs_aarch64_op; namespace simeng { namespace arch { @@ -38,6 +38,8 @@ const uint8_t NZCV = 3; const uint8_t SYSTEM = 4; /** The [256-byte x (SVL / 8)] SME matrix register za. */ const uint8_t MATRIX = 5; +/** The fixed width (512-bit) SME ZT0 table register. */ +const uint8_t TABLE = 6; /** A special register value representing the zero register. */ const Register ZERO_REGISTER = {GENERAL, (uint16_t)-1}; @@ -48,7 +50,6 @@ enum class InstructionException { None = 0, EncodingUnallocated, ExecutionNotYetImplemented, - AliasNotYetImplemented, MisalignedPC, DataAbort, SupervisorCall, @@ -84,140 +85,160 @@ struct MicroOpInfo { }; /** Get the size of the data to be accessed from/to memory. */ -inline uint8_t getDataSize(cs_arm64_op op) { - // Check from top of the range downwards - - // ARM64_REG_V0 -> {end} are vector registers - if (op.reg >= ARM64_REG_V0) { - // Data size for vector registers relies on opcode, get vector access - // specifier - arm64_vas vas = op.vas; - assert(vas != ARM64_VAS_INVALID && "Invalid VAS type"); +inline uint8_t getDataSize(cs_aarch64_op op) { + // No V-register enum identifiers exist. Instead, depending on whether a full + // or half vector is accessed, a Q or D register is used instead. + // A `is_vreg` bool in `op` defines if we are using v-vector registers. + if (op.is_vreg && ((AARCH64_REG_D0 <= op.reg && op.reg <= AARCH64_REG_D31) || + (AARCH64_REG_Q0 <= op.reg && op.reg <= AARCH64_REG_Q31))) { + AArch64Layout_VectorLayout vas = op.vas; + assert(vas != AARCH64LAYOUT_INVALID && "Invalid VAS type"); switch (vas) { - case ARM64_VAS_16B: - case ARM64_VAS_8H: - case ARM64_VAS_4S: - case ARM64_VAS_2D: - case ARM64_VAS_1Q: { + case AARCH64LAYOUT_VL_16B: + case AARCH64LAYOUT_VL_8H: + case AARCH64LAYOUT_VL_4S: + case AARCH64LAYOUT_VL_2D: + case AARCH64LAYOUT_VL_1Q: + case AARCH64LAYOUT_VL_Q: return 16; - } - case ARM64_VAS_8B: - case ARM64_VAS_4H: - case ARM64_VAS_2S: - case ARM64_VAS_1D: { + case AARCH64LAYOUT_VL_8B: + case AARCH64LAYOUT_VL_4H: + case AARCH64LAYOUT_VL_2S: + case AARCH64LAYOUT_VL_1D: + case AARCH64LAYOUT_VL_D: return 8; - } - case ARM64_VAS_4B: - case ARM64_VAS_2H: - case ARM64_VAS_1S: { + case AARCH64LAYOUT_VL_4B: + case AARCH64LAYOUT_VL_2H: + case AARCH64LAYOUT_VL_1S: + case AARCH64LAYOUT_VL_S: return 4; - } - case ARM64_VAS_1H: { + case AARCH64LAYOUT_VL_H: return 2; - } - case ARM64_VAS_1B: { + case AARCH64LAYOUT_VL_B: return 1; - } - default: { - assert(false && "Unknown VAS type"); - } + default: + std::cerr << "[SimEng] Cannot determine size of Arm V vector register " + "elements with `reg` value " + << op.reg << " and `vas` value of " << vas << ". Exiting..." + << std::endl; + exit(1); + break; } } - // ARM64_REG_ZAB0 -> +31 are tiles of the matrix register (ZA) - if (op.reg >= ARM64_REG_ZAB0 || op.reg == ARM64_REG_ZA) { + // SME ZA Tiles, SVE Z registers, and SVE P predicates also have Vector + // Arrangement Specifier set + /** TODO: When SME, SVE instruction splitting is supported / implemented, + * update the data size returned based on VAS. */ + + // Work top down through register enums (highest value -> lowest value) + if (op.reg >= AARCH64_REG_D0_D1) { + // Multi-register currently not supported. Return 0. + return 0; + } + + // AARCH64_REG_ZAB0 -> +31 are tiles of the matrix register (ZA) + // AARCH64_REG_ZT0 is new 512-bit register from SME2 + if (op.reg >= AARCH64_REG_ZAB0 || op.reg == AARCH64_REG_ZA || + op.reg == AARCH64_REG_ZT0) { // Data size for tile registers relies on opcode thus return 0 return 0; } - // ARM64_REG_Z0 -> +31 are scalable vector registers (Z) - if (op.reg >= ARM64_REG_Z0) { + // AARCH64_REG_Z0 -> +31 are scalable vector registers (Z) + if (op.reg >= AARCH64_REG_Z0) { // Data size for vector registers relies on opcode thus return 0 return 0; } - // ARM64_REG_X0 -> +28 are 64-bit (X) registers - if (op.reg >= ARM64_REG_X0) { + // AARCH64_REG_X0 -> +28 are 64-bit (X) registers + if (op.reg >= AARCH64_REG_X0) { return 8; } - // ARM64_REG_W0 -> +30 are 32-bit (W) registers - if (op.reg >= ARM64_REG_W0) { + // AARCH64_REG_W0 -> +30 are 32-bit (W) registers + if (op.reg >= AARCH64_REG_W0) { return 4; } - // ARM64_REG_S0 -> +31 are 32-bit arranged (S) neon registers - if (op.reg >= ARM64_REG_S0) { + // AARCH64_REG_S0 -> +31 are 32-bit arranged (S) neon registers + if (op.reg >= AARCH64_REG_S0) { return 4; } - // ARM64_REG_Q0 -> +31 are 128-bit arranged (Q) neon registers - if (op.reg >= ARM64_REG_Q0) { + // AARCH64_REG_Q0 -> +31 are 128-bit arranged (Q) neon registers + if (op.reg >= AARCH64_REG_Q0) { return 16; } - // ARM64_REG_P0 -> +15 are 256-bit (P) registers - if (op.reg >= ARM64_REG_P0) { - return 1; + // ARCH64_REG_PN0 -> +15 are 256-bit (P) registers + if (op.reg >= AARCH64_REG_PN0) { + return 32; + } + + // AARCH64_REG_P0 -> +15 are 256-bit (P) registers + if (op.reg >= AARCH64_REG_P0) { + return 32; } - // ARM64_REG_H0 -> +31 are 16-bit arranged (H) neon registers - if (op.reg >= ARM64_REG_H0) { + // AARCH64_REG_H0 -> +31 are 16-bit arranged (H) neon registers + if (op.reg >= AARCH64_REG_H0) { return 2; } - // ARM64_REG_D0 -> +31 are 64-bit arranged (D) neon registers - if (op.reg >= ARM64_REG_D0) { + // AARCH64_REG_D0 -> +31 are 64-bit arranged (D) neon registers + if (op.reg >= AARCH64_REG_D0) { return 8; } - // ARM64_REG_B0 -> +31 are 8-bit arranged (B) neon registers - if (op.reg >= ARM64_REG_B0) { + // AARCH64_REG_B0 -> +31 are 8-bit arranged (B) neon registers + if (op.reg >= AARCH64_REG_B0) { return 1; } - // ARM64_REG_XZR is the 64-bit zero register - if (op.reg == ARM64_REG_XZR) { + // AARCH64_REG_XZR is the 64-bit zero register + if (op.reg == AARCH64_REG_XZR) { return 8; } - // ARM64_REG_WZR is the 32-bit zero register - if (op.reg == ARM64_REG_WZR) { + // AARCH64_REG_WZR is the 32-bit zero register + if (op.reg == AARCH64_REG_WZR) { return 4; } - // ARM64_REG_WSP (w31) is the 32-bit stack pointer register - if (op.reg == ARM64_REG_WSP) { + // AARCH64_REG_WSP (w31) is the 32-bit stack pointer register + if (op.reg == AARCH64_REG_WSP) { return 4; } - // ARM64_REG_SP (x31) is the 64-bit stack pointer register - if (op.reg == ARM64_REG_SP) { + // AARCH64_REG_SP (x31) is the 64-bit stack pointer register + if (op.reg == AARCH64_REG_SP) { return 8; } - // ARM64_REG_NZCV is the NZCV flag register - if (op.reg == ARM64_REG_NZCV) { + // AARCH64_REG_NZCV is the NZCV flag register + if (op.reg == AARCH64_REG_NZCV) { return 1; } - // ARM64_REG_X30 is the 64-bit link register - if (op.reg == ARM64_REG_X30) { + // AARCH64_REG_X30 is the 64-bit link register + if (op.reg == AARCH64_REG_X30) { return 8; } - // ARM64_REG_X29 is the 64-bit frame pointer - if (op.reg == ARM64_REG_X29) { + // AARCH64_REG_X29 is the 64-bit frame pointer + if (op.reg == AARCH64_REG_X29) { return 8; } - // ARM64_REG_FFR (p15) is a special purpose predicate register - if (op.reg == ARM64_REG_FFR) { + // AARCH64_REG_FFR (p15) is a special purpose predicate register + if (op.reg == AARCH64_REG_FFR) { return 1; } - // ARM64_REG_INVALID is an invalid capstone register so return 0 bytes as size - if (op.reg == ARM64_REG_INVALID) { + // AARCH64_REG_INVALID is an invalid capstone register so return 0 bytes as + // size + if (op.reg == AARCH64_REG_INVALID) { return 0; } diff --git a/src/include/simeng/arch/aarch64/MicroDecoder.hh b/src/include/simeng/arch/aarch64/MicroDecoder.hh index d4524c8abc..6503d370e8 100644 --- a/src/include/simeng/arch/aarch64/MicroDecoder.hh +++ b/src/include/simeng/arch/aarch64/MicroDecoder.hh @@ -9,9 +9,9 @@ namespace simeng { namespace arch { namespace aarch64 { -/** A struct to hold information to construct a default cs_arm64_op from. */ +/** A struct to hold information to construct a default cs_aarch64_op from. */ struct OpType { - arm64_op_type type; + aarch64_op_type type; bool isDestination = false; }; @@ -33,38 +33,38 @@ class MicroDecoder { private: /** Detect if there's an overlap between the underlying hardware registers * (e.g. z5, v5, q5, d5, s5, h5, and b5). */ - bool detectOverlap(arm64_reg registerA, arm64_reg registerB); + bool detectOverlap(aarch64_reg registerA, aarch64_reg registerB); /** Create a default cs_detail object from a vector of operand types. */ cs_detail createDefaultDetail(std::vector opTypes); /** Create an address offset uop from a base register and an immediate. */ Instruction createImmOffsetUop(const Architecture& architecture, - arm64_reg base, int64_t offset, + aarch64_reg base, int64_t offset, csh capstoneHandle, bool lastMicroOp = false, int microOpIndex = 0); /** Create an address offset uop from a base register and a register. */ Instruction createRegOffsetUop(const Architecture& architecture, - arm64_reg base, arm64_reg offset, + aarch64_reg base, aarch64_reg offset, csh capstoneHandle, bool lastMicroOp = false, int microOpIndex = 0); /** Create a load uop from a destination register and a capstone memory * operand. */ - Instruction createLdrUop(const Architecture& architecture, arm64_reg dest, - arm64_op_mem mem, csh capstoneHandle, + Instruction createLdrUop(const Architecture& architecture, aarch64_reg dest, + aarch64_op_mem mem, csh capstoneHandle, bool lastMicroOp = false, int microOpIndex = 0, uint8_t dataSize = 0); /** Create a store data uop from a source register. */ - Instruction createSDUop(const Architecture& architecture, arm64_reg src, + Instruction createSDUop(const Architecture& architecture, aarch64_reg src, csh capstoneHandle, bool lastMicroOp = false, int microOpIndex = 0); /** Create a store address uop from a capstone memory * operand. */ - Instruction createStrUop(const Architecture& architecture, arm64_op_mem mem, + Instruction createStrUop(const Architecture& architecture, aarch64_op_mem mem, csh capstoneHandle, bool lastMicroOp = false, int microOpIndex = 0, uint8_t dataSize = 0); @@ -84,17 +84,19 @@ class MicroDecoder { // Default objects /** Default capstone instruction structure. */ - cs_arm64 default_info = {ARM64_CC_INVALID, false, false, 0, {}}; + cs_aarch64 default_info = {AArch64CC_Invalid, false, false, false, 0, {}}; /** Default register. */ - cs_arm64_op default_op = {0, - ARM64_VAS_INVALID, - {ARM64_SFT_INVALID, 0}, - ARM64_EXT_INVALID, - ARM64_OP_INVALID, - ARM64_SVCR_INVALID, - {}, - CS_AC_READ}; + cs_aarch64_op default_op = {0, + AARCH64LAYOUT_INVALID, + {AARCH64_SFT_INVALID, 0}, + AARCH64_EXT_INVALID, + AARCH64_OP_INVALID, + false, + {}, + {}, + CS_AC_READ, + false}; /** Default capstone instruction detail. */ cs_detail default_detail = {{}, 0, {}, 0, {}, 0, {}}; diff --git a/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh b/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh index a16029bf5c..5880a75da9 100644 --- a/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh +++ b/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh @@ -164,7 +164,7 @@ inline bool conditionHolds(uint8_t cond, uint8_t nzcv) { /** Extend `value` according to `extendType`, and left-shift the result by * `shift`. Replicated from Instruction.cc */ inline uint64_t extendValue(uint64_t value, uint8_t extendType, uint8_t shift) { - if (extendType == ARM64_EXT_INVALID && shift == 0) { + if (extendType == AARCH64_EXT_INVALID && shift == 0) { // Special case: an invalid shift type with a shift amount of 0 implies an // identity operation return value; @@ -172,28 +172,28 @@ inline uint64_t extendValue(uint64_t value, uint8_t extendType, uint8_t shift) { uint64_t extended; switch (extendType) { - case ARM64_EXT_UXTB: + case AARCH64_EXT_UXTB: extended = static_cast(value); break; - case ARM64_EXT_UXTH: + case AARCH64_EXT_UXTH: extended = static_cast(value); break; - case ARM64_EXT_UXTW: + case AARCH64_EXT_UXTW: extended = static_cast(value); break; - case ARM64_EXT_UXTX: + case AARCH64_EXT_UXTX: extended = value; break; - case ARM64_EXT_SXTB: + case AARCH64_EXT_SXTB: extended = static_cast(value); break; - case ARM64_EXT_SXTH: + case AARCH64_EXT_SXTH: extended = static_cast(value); break; - case ARM64_EXT_SXTW: + case AARCH64_EXT_SXTW: extended = static_cast(value); break; - case ARM64_EXT_SXTX: + case AARCH64_EXT_SXTX: extended = value; break; default: @@ -205,13 +205,13 @@ inline uint64_t extendValue(uint64_t value, uint8_t extendType, uint8_t shift) { } /** Extend `value` using extension/shifting rules defined in `op`. */ -inline uint64_t extendOffset(uint64_t value, const cs_arm64_op& op) { +inline uint64_t extendOffset(uint64_t value, const cs_aarch64_op& op) { if (op.ext == 0) { if (op.shift.value == 0) { return value; } if (op.shift.type == 1) { - return extendValue(value, ARM64_EXT_UXTX, op.shift.value); + return extendValue(value, AARCH64_EXT_UXTX, op.shift.value); } } return extendValue(value, op.ext, op.shift.value); @@ -262,63 +262,54 @@ inline uint64_t mulhi(uint64_t a, uint64_t b) { return multhi; } -/** Decode the instruction pattern from OperandStr. */ -inline uint16_t sveGetPattern(const std::string operandStr, const uint8_t esize, - const uint16_t VL_) { +/** Get the number of elements to work on for SVE instructions. */ +inline uint16_t getElemsFromPattern(const aarch64_svepredpat svePattern, + const uint8_t esize, const uint16_t VL_) { const uint16_t elements = VL_ / esize; - const std::vector patterns = { - "pow2", "vl1", "vl2", "vl3", "vl4", "vl5", "vl6", "vl7", "vl8", - "vl16", "vl32", "vl64", "vl128", "vl256", "mul3", "mul4", "all"}; - - // If no pattern present in operandStr then same behaviour as ALL - std::string pattern = "all"; - for (uint8_t i = 0; i < patterns.size(); i++) { - if (operandStr.find(patterns[i]) != std::string::npos) { - pattern = patterns[i]; - // Don't break when pattern found as vl1 will be found in vl128 etc + switch (svePattern) { + case AARCH64_SVEPREDPAT_ALL: + return elements; + case AARCH64_SVEPREDPAT_MUL3: + return elements - (elements % 3); + case AARCH64_SVEPREDPAT_MUL4: + return elements - (elements % 4); + case AARCH64_SVEPREDPAT_POW2: { + int n = 1; + while (elements >= std::pow(2, n)) { + n = n + 1; + } + return std::pow(2, n - 1); } + case AARCH64_SVEPREDPAT_VL1: + return (elements >= 1) ? 1 : 0; + case AARCH64_SVEPREDPAT_VL128: + return (elements >= 128) ? 128 : 0; + case AARCH64_SVEPREDPAT_VL16: + return (elements >= 16) ? 16 : 0; + case AARCH64_SVEPREDPAT_VL2: + return (elements >= 2) ? 2 : 0; + case AARCH64_SVEPREDPAT_VL256: + return (elements >= 256) ? 256 : 0; + case AARCH64_SVEPREDPAT_VL3: + return (elements >= 3) ? 3 : 0; + case AARCH64_SVEPREDPAT_VL32: + return (elements >= 32) ? 32 : 0; + case AARCH64_SVEPREDPAT_VL4: + return (elements >= 4) ? 4 : 0; + case AARCH64_SVEPREDPAT_VL5: + return (elements >= 5) ? 5 : 0; + case AARCH64_SVEPREDPAT_VL6: + return (elements >= 6) ? 6 : 0; + case AARCH64_SVEPREDPAT_VL64: + return (elements >= 64) ? 64 : 0; + case AARCH64_SVEPREDPAT_VL7: + return (elements >= 7) ? 7 : 0; + case AARCH64_SVEPREDPAT_VL8: + return (elements >= 8) ? 8 : 0; + default: + assert(false && "Unknown SVE Predicate Pattern."); + return 0; } - - if (pattern == "all") - return elements; - else if (pattern == "pow2") { - int n = 1; - while (elements >= std::pow(2, n)) { - n = n + 1; - } - return std::pow(2, n - 1); - } else if (pattern == "vl1") - return (elements >= 1) ? 1 : 0; - else if (pattern == "vl2") - return (elements >= 2) ? 2 : 0; - else if (pattern == "vl3") - return (elements >= 3) ? 3 : 0; - else if (pattern == "vl4") - return (elements >= 4) ? 4 : 0; - else if (pattern == "vl5") - return (elements >= 5) ? 5 : 0; - else if (pattern == "vl6") - return (elements >= 6) ? 6 : 0; - else if (pattern == "vl7") - return (elements >= 7) ? 7 : 0; - else if (pattern == "vl8") - return (elements >= 8) ? 8 : 0; - else if (pattern == "vl16") - return (elements >= 16) ? 16 : 0; - else if (pattern == "vl32") - return (elements >= 32) ? 32 : 0; - else if (pattern == "vl64") - return (elements >= 64) ? 64 : 0; - else if (pattern == "vl128") - return (elements >= 128) ? 128 : 0; - else if (pattern == "vl256") - return (elements >= 256) ? 256 : 0; - else if (pattern == "mul4") - return elements - (elements % 4); - else if (pattern == "mul3") - return elements - (elements % 3); - - return 0; } /** Apply the shift specified by `shiftType` to the unsigned integer `value`, @@ -327,25 +318,25 @@ template inline std::enable_if_t && std::is_unsigned_v, T> shiftValue(T value, uint8_t shiftType, uint8_t amount) { switch (shiftType) { - case ARM64_SFT_LSL: + case AARCH64_SFT_LSL: return value << amount; - case ARM64_SFT_LSR: + case AARCH64_SFT_LSR: return value >> amount; - case ARM64_SFT_ASR: + case AARCH64_SFT_ASR: return static_cast>(value) >> amount; - case ARM64_SFT_ROR: { + case AARCH64_SFT_ROR: { // Assuming sizeof(T) is a power of 2. const T mask = sizeof(T) * 8 - 1; assert((amount <= mask) && "Rotate amount exceeds type width"); amount &= mask; return (value >> amount) | (value << ((-amount) & mask)); } - case ARM64_SFT_MSL: { + case AARCH64_SFT_MSL: { // pad in with ones instead of zeros const T mask = (static_cast(1) << static_cast(amount)) - 1; return (value << amount) | mask; } - case ARM64_SFT_INVALID: + case AARCH64_SFT_INVALID: return value; default: assert(false && "Unknown shift type"); diff --git a/src/include/simeng/arch/aarch64/helpers/neon.hh b/src/include/simeng/arch/aarch64/helpers/neon.hh index 0fcf04f03f..c2626b7e91 100644 --- a/src/include/simeng/arch/aarch64/helpers/neon.hh +++ b/src/include/simeng/arch/aarch64/helpers/neon.hh @@ -752,7 +752,7 @@ template RegisterValue vecSshrShift_imm( srcValContainer& sourceValues, const simeng::arch::aarch64::InstructionMetadata& metadata) { - const T* n = sourceValues[1].getAsVector(); + const T* n = sourceValues[0].getAsVector(); uint64_t shift = metadata.operands[2].imm; T out[16 / sizeof(T)] = {0}; for (int i = 0; i < I; i++) { diff --git a/src/include/simeng/arch/aarch64/helpers/sve.hh b/src/include/simeng/arch/aarch64/helpers/sve.hh index 076a2f29c1..2c33ccfbe6 100644 --- a/src/include/simeng/arch/aarch64/helpers/sve.hh +++ b/src/include/simeng/arch/aarch64/helpers/sve.hh @@ -177,10 +177,10 @@ std::tuple, uint8_t> sveCmpPredicated_toPred( template uint64_t sveCnt_gpr(const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { - const uint8_t imm = static_cast(metadata.operands[1].imm); + const uint8_t imm = static_cast(metadata.operands[2].imm); - const uint16_t elems = - sveGetPattern(metadata.operandStr, (sizeof(T) * 8), VL_bits); + const uint16_t elems = getElemsFromPattern( + metadata.operands[1].sysop.alias.svepredpat, (sizeof(T) * 8), VL_bits); return (uint64_t)(elems * imm); } @@ -267,9 +267,9 @@ int64_t sveDec_scalar( const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { const int64_t n = sourceValues[0].get(); - const uint8_t imm = static_cast(metadata.operands[1].imm); - const uint16_t elems = - sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + const uint8_t imm = static_cast(metadata.operands[2].imm); + const uint16_t elems = getElemsFromPattern( + metadata.operands[1].sysop.alias.svepredpat, sizeof(T) * 8, VL_bits); return (n - static_cast(elems * imm)); } @@ -859,9 +859,10 @@ int64_t sveInc_gprImm( const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { const int64_t n = sourceValues[0].get(); - const uint8_t imm = static_cast(metadata.operands[1].imm); - const uint16_t elems = - sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + + const uint8_t imm = static_cast(metadata.operands[2].imm); + const uint16_t elems = getElemsFromPattern( + metadata.operands[1].sysop.alias.svepredpat, sizeof(T) * 8, VL_bits); int64_t out = n + (elems * imm); return out; } @@ -876,12 +877,13 @@ RegisterValue sveInc_imm( const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { const T* n = sourceValues[0].getAsVector(); - const uint8_t imm = static_cast(metadata.operands[1].imm); + + const uint8_t imm = static_cast(metadata.operands[2].imm); const uint16_t partition_num = VL_bits / (sizeof(T) * 8); typename std::make_signed::type out[256 / sizeof(T)] = {0}; - const uint16_t elems = - sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + const uint16_t elems = getElemsFromPattern( + metadata.operands[1].sysop.alias.svepredpat, sizeof(T) * 8, VL_bits); for (int i = 0; i < partition_num; i++) { out[i] = n[i] + (elems * imm); @@ -1044,17 +1046,16 @@ RegisterValue sveMax_vecImm( return {out, 256}; } -/** Helper function for SVE instructions with the format `max zdn, zdn, - * #imm`. +/** Helper function for SVE instructions with the format `max zdn, pg/m, zdn, + * zm`. * T represents the type of sourceValues (e.g. for zdn.d, T = uint64_t). * Returns correctly formatted RegisterValue. */ template RegisterValue sveMaxPredicated_vecs(srcValContainer& sourceValues, const uint16_t VL_bits) { - const T* d = sourceValues[0].getAsVector(); - const uint64_t* p = sourceValues[1].getAsVector(); - const T* n = sourceValues[2].getAsVector(); - const T* m = sourceValues[3].getAsVector(); + const uint64_t* p = sourceValues[0].getAsVector(); + const T* n = sourceValues[1].getAsVector(); + const T* m = sourceValues[2].getAsVector(); const uint16_t partition_num = VL_bits / (sizeof(T) * 8); T out[256 / sizeof(T)] = {0}; @@ -1064,7 +1065,7 @@ RegisterValue sveMaxPredicated_vecs(srcValContainer& sourceValues, if (p[i / (64 / sizeof(T))] & shifted_active) { out[i] = std::max(n[i], m[i]); } else - out[i] = d[i]; + out[i] = n[i]; } return {out, 256}; } @@ -1276,7 +1277,8 @@ std::array svePsel( const uint64_t* pn = sourceValues[0].getAsVector(); const uint64_t* pm = sourceValues[1].getAsVector(); const uint32_t wa = sourceValues[2].get(); - const uint32_t imm = metadata.operands[2].sme_index.disp; + const uint32_t imm = + static_cast(metadata.operands[2].pred.imm_index); const uint16_t partition_num = VL_bits / (sizeof(T) * 8); @@ -1303,8 +1305,8 @@ std::array svePtrue( std::array out = {0, 0, 0, 0}; // Get pattern - const uint16_t count = - sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + const uint16_t count = getElemsFromPattern( + metadata.operands[1].sysop.alias.svepredpat, sizeof(T) * 8, VL_bits); // Exit early if count == 0 if (count == 0) return out; @@ -1592,8 +1594,10 @@ uint64_t sveUqdec(srcValContainer& sourceValues, const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { const D d = sourceValues[0].get(); - const uint8_t imm = metadata.operands[1].imm; - const uint16_t count = sveGetPattern(metadata.operandStr, N, VL_bits); + + const uint8_t imm = metadata.operands[2].imm; + const uint16_t count = getElemsFromPattern( + metadata.operands[1].sysop.alias.svepredpat, N, VL_bits); // The range of possible values does not fit in the range of any integral // type, so a double is used as an intermediate value. The end result must diff --git a/src/include/simeng/arch/aarch64/operandContainer.hh b/src/include/simeng/arch/aarch64/operandContainer.hh index 802c5466d4..c73b8881da 100644 --- a/src/include/simeng/arch/aarch64/operandContainer.hh +++ b/src/include/simeng/arch/aarch64/operandContainer.hh @@ -18,7 +18,7 @@ const uint8_t MAX_DESTINATION_REGISTERS = 5; /** The maximum number of source/destination operands an SME instruction can * have in addition to any ZA operands. */ -const uint8_t ADDITIONAL_SME_REGISTERS = 8; +const uint8_t ADDITIONAL_SME_REGISTERS = 11; /** Simple class to allow AArch64 instructions to use std::array for operands in * most cases, but for SME instructions a std::vector can be utilised to allow diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index e27ea8f0f9..015dba62b1 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -14,13 +14,16 @@ Architecture::Architecture(kernel::Linux& kernel, ryml::ConstNodeRef config) SVL_(config["Core"]["Streaming-Vector-Length"].as()), vctModulo_((config["Core"]["Clock-Frequency-GHz"].as() * 1e9) / (config["Core"]["Timer-Frequency-MHz"].as() * 1e6)) { - if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &capstoneHandle_) != CS_ERR_OK) { + if (cs_open(CS_ARCH_AARCH64, CS_MODE_ARM, &capstoneHandle_) != CS_ERR_OK) { std::cerr << "[SimEng:Architecture] Could not create capstone handle" << std::endl; exit(1); } cs_option(capstoneHandle_, CS_OPT_DETAIL, CS_OPT_ON); + // This second Capstone option reverses instruction aliases, and instead + // means all operand information is that of the "real" underlying instruction. + cs_option(capstoneHandle_, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL); // Generate zero-indexed system register map std::vector sysRegs = config::SimInfo::getSysRegVec(); @@ -31,10 +34,10 @@ Architecture::Architecture(kernel::Linux& kernel, ryml::ConstNodeRef config) // Get Virtual Counter Timer and Processor Cycle Counter system registers. VCTreg_ = { RegisterType::SYSTEM, - static_cast(getSystemRegisterTag(ARM64_SYSREG_CNTVCT_EL0))}; + static_cast(getSystemRegisterTag(AARCH64_SYSREG_CNTVCT_EL0))}; PCCreg_ = { RegisterType::SYSTEM, - static_cast(getSystemRegisterTag(ARM64_SYSREG_PMCCNTR_EL0))}; + static_cast(getSystemRegisterTag(AARCH64_SYSREG_PMCCNTR_EL0))}; // Instantiate an ExecutionInfo entry for each group in the // InstructionGroup namespace. @@ -231,7 +234,7 @@ ProcessStateChange Architecture::getInitialState() const { // but is disabled due to bit 4 being set changes.modifiedRegisters.push_back( {RegisterType::SYSTEM, - static_cast(getSystemRegisterTag(ARM64_SYSREG_DCZID_EL0))}); + static_cast(getSystemRegisterTag(AARCH64_SYSREG_DCZID_EL0))}); changes.modifiedRegisterValues.push_back(static_cast(0b10100)); return changes; diff --git a/src/lib/arch/aarch64/ExceptionHandler.cc b/src/lib/arch/aarch64/ExceptionHandler.cc index 36aff03781..ae98dddb1a 100644 --- a/src/lib/arch/aarch64/ExceptionHandler.cc +++ b/src/lib/arch/aarch64/ExceptionHandler.cc @@ -658,8 +658,17 @@ bool ExceptionHandler::init() { if (metadata.opcode == Opcode::AArch64_MSR) { newSVCR = instruction_.getSourceOperands()[0].get(); } else if (metadata.opcode == Opcode::AArch64_MSRpstatesvcrImm1) { + // Ensure operand metadata is as expected + assert(metadata.operands[0].type == AARCH64_OP_SYSALIAS); + assert(metadata.operands[0].sysop.sub_type == AARCH64_OP_SVCR); + // extract SVCR bits const uint64_t svcrBits = - static_cast(metadata.operands[0].svcr); + static_cast(metadata.operands[0].sysop.alias.svcr); + // Ensure SVCR Bits are valid + assert(svcrBits == AARCH64_SVCR_SVCRSM || + svcrBits == AARCH64_SVCR_SVCRZA || + svcrBits == AARCH64_SVCR_SVCRSMZA); + const uint64_t imm = metadata.operands[1].imm; assert((imm == 0 || imm == 1) && "[SimEng:ExceptionHandler] SVCR Instruction invalid - Imm value " @@ -680,20 +689,22 @@ bool ExceptionHandler::init() { std::vector regs; std::vector regValues; - // If SVCR.ZA has changed state then zero out ZA register, else don't + // If SVCR.ZA has changed state then zero out ZA and ZT0 registers if (exception != InstructionException::StreamingModeUpdate) { - if ((newSVCR & ARM64_SVCR_SVCRZA) != (currSVCR & ARM64_SVCR_SVCRZA)) { + if ((newSVCR & AARCH64_SVCR_SVCRZA) != (currSVCR & AARCH64_SVCR_SVCRZA)) { for (uint16_t i = 0; i < regFileStruct[RegisterType::MATRIX].quantity; i++) { regs.push_back({RegisterType::MATRIX, i}); regValues.push_back(RegisterValue(0, 256)); } + regs.push_back({RegisterType::TABLE, 0}); + regValues.push_back(RegisterValue(0, 64)); } } // If SVCR.SM has changed state then zero out SVE, NEON, Predicate // registers, else don't if (exception != InstructionException::ZAregisterStatusUpdate) { - if ((newSVCR & ARM64_SVCR_SVCRSM) != (currSVCR & ARM64_SVCR_SVCRSM)) { + if ((newSVCR & AARCH64_SVCR_SVCRSM) != (currSVCR & AARCH64_SVCR_SVCRSM)) { for (uint16_t i = 0; i < regFileStruct[RegisterType::VECTOR].quantity; i++) { regs.push_back({RegisterType::VECTOR, i}); @@ -707,9 +718,9 @@ bool ExceptionHandler::init() { } // Update SVCR system register in regFile - regs.push_back( - {RegisterType::SYSTEM, - static_cast(arch.getSystemRegisterTag(ARM64_SYSREG_SVCR))}); + regs.push_back({RegisterType::SYSTEM, + static_cast( + arch.getSystemRegisterTag(AARCH64_SYSREG_SVCR))}); regValues.push_back(RegisterValue(newSVCR, 8)); ProcessStateChange stateChange = {ChangeType::REPLACEMENT, regs, regValues}; @@ -877,9 +888,6 @@ void ExceptionHandler::printException(const Instruction& insn) const { case InstructionException::ExecutionNotYetImplemented: std::cout << "execution not-yet-implemented"; break; - case InstructionException::AliasNotYetImplemented: - std::cout << "alias not-yet-implemented"; - break; case InstructionException::MisalignedPC: std::cout << "misaligned program counter"; break; diff --git a/src/lib/arch/aarch64/InstructionMetadata.cc b/src/lib/arch/aarch64/InstructionMetadata.cc index e0106f97f8..34ddca07d7 100644 --- a/src/lib/arch/aarch64/InstructionMetadata.cc +++ b/src/lib/arch/aarch64/InstructionMetadata.cc @@ -13,13 +13,13 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) implicitSourceCount(insn.detail->regs_read_count), implicitDestinationCount(insn.detail->regs_write_count), groupCount(insn.detail->groups_count), - cc(insn.detail->arm64.cc - 1), - setsFlags(insn.detail->arm64.update_flags), - writeback(insn.detail->arm64.writeback), - operandCount(insn.detail->arm64.op_count) { + cc(insn.detail->aarch64.cc), + setsFlags(insn.detail->aarch64.update_flags), + isAlias(insn.is_alias), + operandCount(insn.detail->aarch64.op_count) { std::memcpy(encoding, insn.bytes, sizeof(encoding)); // Copy printed output - std::strncpy(mnemonic, insn.mnemonic, CS_MNEMONIC_SIZE); + mnemonic = std::string(insn.mnemonic); operandStr = std::string(insn.op_str); // Copy register/group/operand information @@ -28,12 +28,20 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) std::memcpy(implicitDestinations, insn.detail->regs_write, sizeof(uint16_t) * implicitDestinationCount); std::memcpy(groups, insn.detail->groups, sizeof(uint8_t) * groupCount); - std::memcpy(operands, insn.detail->arm64.operands, - sizeof(cs_arm64_op) * operandCount); + std::memcpy(operands, insn.detail->aarch64.operands, + sizeof(cs_aarch64_op) * operandCount); // Fix some inaccuracies in the decoded metadata switch (opcode) { - case Opcode::AArch64_ADR_LSL_ZZZ_D_0: + case Opcode::AArch64_FMOVXDHighr: // Example bytecode - 4100af9e + // FMOVXDHighr incorrectly flags destination as WRITE only + operands[0].access = CS_AC_READ | CS_AC_WRITE; + break; + case Opcode::AArch64_FCVTNv4i32: // Example bytecode - 0168614e + // Wrong access type for destination operand + operands[0].access = CS_AC_WRITE; + break; + case Opcode::AArch64_ADR_LSL_ZZZ_D_0: // example bytecode = c8a0e704 [[fallthrough]]; case Opcode::AArch64_ADR_LSL_ZZZ_D_1: [[fallthrough]]; @@ -48,531 +56,162 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) case Opcode::AArch64_ADR_LSL_ZZZ_S_2: [[fallthrough]]; case Opcode::AArch64_ADR_LSL_ZZZ_S_3: { - // No defined access types + // Change the last 2 Z-regs from one MEM operand to two REG operands operandCount = 3; - operands[0].access = CS_AC_WRITE; + operands[1].type = AARCH64_OP_REG; operands[1].access = CS_AC_READ; + operands[1].reg = operands[1].mem.base; + operands[1].vas = operands[1].vas; + operands[2].type = AARCH64_OP_REG; operands[2].access = CS_AC_READ; - operands[2].type = ARM64_OP_REG; + operands[2].reg = operands[1].mem.index; + operands[2].vas = operands[1].vas; + operands[2].shift = operands[1].shift; break; } - case Opcode::AArch64_SMIN_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_EOR_ZPmZ_B: - [[fallthrough]]; - case Opcode::AArch64_EOR_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_EOR_ZPmZ_H: - [[fallthrough]]; - case Opcode::AArch64_EOR_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_AND_ZPmZ_B: - [[fallthrough]]; - case Opcode::AArch64_AND_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_AND_ZPmZ_H: - [[fallthrough]]; - case Opcode::AArch64_AND_ZPmZ_S: - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - break; - case Opcode::AArch64_BICv4i32: - // BIC incorrectly flags destination as WRITE only - operands[0].access = CS_AC_WRITE | CS_AC_READ; - break; - case Opcode::AArch64_ADDSWri: - // adds incorrectly flags destination as READ - operands[0].access = CS_AC_WRITE; - break; - case Opcode::AArch64_BICv8i16: - operands[0].access = CS_AC_WRITE | CS_AC_READ; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_BICv8i8: - // access specifier for last operand was missing - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_CASALW: + case Opcode::AArch64_CASALW: // Example bytecode - 02fce188 [[fallthrough]]; case Opcode::AArch64_CASALX: - operandCount = 3; - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_CBNZW: - [[fallthrough]]; - case Opcode::AArch64_CBNZX: - [[fallthrough]]; - case Opcode::AArch64_CBZW: - [[fallthrough]]; - case Opcode::AArch64_CBZX: - // incorrectly adds implicit nzcv dependency - implicitSourceCount = 0; - break; - case Opcode::AArch64_CMPHI_PPzZZ_B: - [[fallthrough]]; - case Opcode::AArch64_CMPHI_PPzZZ_D: - [[fallthrough]]; - case Opcode::AArch64_CMPHI_PPzZZ_H: - [[fallthrough]]; - case Opcode::AArch64_CMPHI_PPzZZ_S: - [[fallthrough]]; - case Opcode::AArch64_CMPGT_PPzZZ_B: - [[fallthrough]]; - case Opcode::AArch64_CMPGT_PPzZZ_D: - [[fallthrough]]; - case Opcode::AArch64_CMPGT_PPzZZ_H: - [[fallthrough]]; - case Opcode::AArch64_CMPGT_PPzZZ_S: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZI_B: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZI_D: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZI_H: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZI_S: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZZ_B: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZZ_D: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZZ_H: - [[fallthrough]]; - case Opcode::AArch64_CMPEQ_PPzZZ_S: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZZ_B: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZZ_D: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZZ_H: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZZ_S: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZI_B: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZI_D: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZI_H: - [[fallthrough]]; - case Opcode::AArch64_CMPNE_PPzZI_S: - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - // Doesn't identify implicit NZCV destination - implicitDestinationCount = 1; - implicitDestinations[0] = ARM64_REG_NZCV; - break; - case Opcode::AArch64_CNTB_XPiI: - [[fallthrough]]; - case Opcode::AArch64_CNTH_XPiI: - [[fallthrough]]; - case Opcode::AArch64_CNTD_XPiI: - [[fallthrough]]; - case Opcode::AArch64_CNTW_XPiI: { - // lacking access specifiers for destination - operands[0].access = CS_AC_WRITE; - if (operandStr.length() < 4) { - operandCount = 2; - operands[1].type = ARM64_OP_IMM; - operands[1].imm = 1; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - operands[1].ext = ARM64_EXT_INVALID; - operands[1].vector_index = -1; - } + // Remove implicit destination (MEM base reg) + implicitDestinationCount = 0; break; - } - case Opcode::AArch64_ADD_ZI_B: + case Opcode::AArch64_ADD_ZI_B: // Example bytecode - 00c12025 [[fallthrough]]; case Opcode::AArch64_ADD_ZI_D: [[fallthrough]]; case Opcode::AArch64_ADD_ZI_H: [[fallthrough]]; case Opcode::AArch64_ADD_ZI_S: { + // Incorrect access types operands[0].access = CS_AC_WRITE; operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[2].type = ARM64_OP_IMM; - operandCount = 3; - - // Extract immediate in SVE add with immediate instruction - size_t start = operandStr.find("#"); - // Identify whether the immediate value is in base-10 or base-16 - if (start != std::string::npos) { - start++; - bool hex = false; - if (operandStr[start + 1] == 'x') { - hex = true; - start += 2; - } - - uint8_t end = operandStr.size(); - size_t shifted = operandStr.find("LSL"); - if (shifted != std::string::npos) { - std::cerr << "[SimEng:arch] SVE add with immediate has shift value " - "in operandStr which is unsupported." - << std::endl; - exit(1); - } - // Convert extracted immediate from string to int64_t - std::string sub = operandStr.substr(start, end); - if (hex) { - operands[2].imm = std::stoul(sub, 0, 16); - } else { - operands[2].imm = stoi(sub); - } - } else { - operands[2].imm = 0; - } - break; - } - case Opcode::AArch64_AND_ZI: { - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[2].type = ARM64_OP_IMM; - operandCount = 3; - - char specifier = operandStr[operandStr.find(".") + 1]; - switch (specifier) { - case 'b': { - uint8_t mask = static_cast(operands[2].imm); - operands[2].imm = static_cast(0); - for (int i = 0; i < 8; i++) - operands[2].imm |= (static_cast(mask) << (i * 8)); - break; - } - case 'h': { - uint16_t mask = static_cast(operands[2].imm); - operands[2].imm = static_cast(0); - for (int i = 0; i < 4; i++) - operands[2].imm |= (static_cast(mask) << (i * 16)); - break; - } - case 's': { - uint32_t mask = static_cast(operands[2].imm); - operands[2].imm = static_cast(0); - for (int i = 0; i < 2; i++) - operands[2].imm |= (static_cast(mask) << (i * 32)); - break; - } - default: - break; - } break; } - case Opcode::AArch64_CNTP_XPP_B: - [[fallthrough]]; - case Opcode::AArch64_CNTP_XPP_D: + case Opcode::AArch64_SMAX_ZI_B: [[fallthrough]]; - case Opcode::AArch64_CNTP_XPP_H: + case Opcode::AArch64_SMAX_ZI_D: [[fallthrough]]; - case Opcode::AArch64_CNTP_XPP_S: + case Opcode::AArch64_SMAX_ZI_H: [[fallthrough]]; - case Opcode::AArch64_EOR_ZZZ: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_DECD_XPiI: + case Opcode::AArch64_SMAX_ZI_S: // Example bytecode - 03c0a825 [[fallthrough]]; - case Opcode::AArch64_DECB_XPiI: { - // lacking access specifiers for destination - operands[0].access = CS_AC_READ | CS_AC_WRITE; - std::string str(operandStr); - if (str.length() < 4) { - operandCount = 2; - operands[1].type = ARM64_OP_IMM; - operands[1].imm = 1; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - operands[1].ext = ARM64_EXT_INVALID; - operands[1].vector_index = -1; - } - break; - } - case Opcode::AArch64_EOR_PPzPP: { + case Opcode::AArch64_AND_ZI: // Example bytecode - 00068005 + // Incorrect access types operands[0].access = CS_AC_WRITE; operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - break; - } - case Opcode::AArch64_FMOVXDHighr: - // FMOVXDHighr incorrectly flags destination as only WRITE - operands[0].access = CS_AC_READ | CS_AC_WRITE; break; - case Opcode::AArch64_FNMSB_ZPmZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FNMSB_ZPmZZ_S: - [[fallthrough]]; - case Opcode::AArch64_FNMLS_ZPmZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FNMLS_ZPmZZ_S: - [[fallthrough]]; - case Opcode::AArch64_FMAD_ZPmZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FMAD_ZPmZZ_S: - [[fallthrough]]; - case Opcode::AArch64_FMLA_ZPmZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FMLA_ZPmZZ_S: - [[fallthrough]]; - case Opcode::AArch64_FMLS_ZPmZZ_D: + case Opcode::AArch64_FSUB_ZPmI_D: [[fallthrough]]; - case Opcode::AArch64_FMLS_ZPmZZ_S: + case Opcode::AArch64_FSUB_ZPmI_H: [[fallthrough]]; - case Opcode::AArch64_FMSB_ZPmZZ_D: + case Opcode::AArch64_FSUB_ZPmI_S: // Example bytecode - 00849965 [[fallthrough]]; - case Opcode::AArch64_FMSB_ZPmZZ_S: + case Opcode::AArch64_FMUL_ZPmI_D: [[fallthrough]]; - case Opcode::AArch64_MLA_ZPmZZ_B: + case Opcode::AArch64_FMUL_ZPmI_H: [[fallthrough]]; - case Opcode::AArch64_MLA_ZPmZZ_D: + case Opcode::AArch64_FMUL_ZPmI_S: // Example bytecode - 00809a65 [[fallthrough]]; - case Opcode::AArch64_MLA_ZPmZZ_H: + case Opcode::AArch64_FADD_ZPmI_D: // Example bytecode - 0584d865 [[fallthrough]]; - case Opcode::AArch64_MLA_ZPmZZ_S: + case Opcode::AArch64_FADD_ZPmI_H: [[fallthrough]]; - case Opcode::AArch64_SMAX_ZPmZ_S: - // No defined access types - operands[0].access = CS_AC_READ | CS_AC_WRITE; + case Opcode::AArch64_FADD_ZPmI_S: { + // Incorrect access types + operands[0].access = CS_AC_WRITE; operands[1].access = CS_AC_READ; operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; break; - case Opcode::AArch64_ADDPL_XXI: - [[fallthrough]]; - case Opcode::AArch64_ADDVL_XXI: - [[fallthrough]]; - case Opcode::AArch64_UADDV_VPZ_B: - [[fallthrough]]; - case Opcode::AArch64_UADDV_VPZ_D: - [[fallthrough]]; - case Opcode::AArch64_UADDV_VPZ_H: - [[fallthrough]]; - case Opcode::AArch64_UADDV_VPZ_S: - [[fallthrough]]; - case Opcode::AArch64_MOVPRFX_ZPzZ_D: - [[fallthrough]]; - case Opcode::AArch64_MOVPRFX_ZPzZ_S: - [[fallthrough]]; - case Opcode::AArch64_SUB_ZZZ_B: - [[fallthrough]]; - case Opcode::AArch64_SUB_ZZZ_H: - [[fallthrough]]; - case Opcode::AArch64_SUB_ZZZ_S: - [[fallthrough]]; - case Opcode::AArch64_SUB_ZZZ_D: - [[fallthrough]]; - case Opcode::AArch64_INDEX_II_B: - [[fallthrough]]; - case Opcode::AArch64_INDEX_II_H: - [[fallthrough]]; - case Opcode::AArch64_INDEX_II_S: - [[fallthrough]]; - case Opcode::AArch64_INDEX_II_D: - [[fallthrough]]; - case Opcode::AArch64_INDEX_IR_B: - [[fallthrough]]; - case Opcode::AArch64_INDEX_IR_D: - [[fallthrough]]; - case Opcode::AArch64_INDEX_IR_H: - [[fallthrough]]; - case Opcode::AArch64_INDEX_IR_S: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RI_B: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RI_D: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RI_H: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RI_S: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RR_B: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RR_D: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RR_H: - [[fallthrough]]; - case Opcode::AArch64_INDEX_RR_S: - [[fallthrough]]; - case Opcode::AArch64_ADD_ZZZ_B: + } + case Opcode::AArch64_AND_ZPmZ_D: // Example bytecode - 4901da04 [[fallthrough]]; - case Opcode::AArch64_ADD_ZZZ_D: + case Opcode::AArch64_AND_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_ADD_ZZZ_H: + case Opcode::AArch64_AND_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_ADD_ZZZ_S: + case Opcode::AArch64_AND_ZPmZ_B: [[fallthrough]]; - case Opcode::AArch64_FADD_ZZZ_D: + case Opcode::AArch64_SMULH_ZPmZ_B: // Example bytecode - 20001204 [[fallthrough]]; - case Opcode::AArch64_FADD_ZZZ_S: + case Opcode::AArch64_SMULH_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_FSUB_ZZZ_D: + case Opcode::AArch64_SMULH_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FSUB_ZZZ_S: + case Opcode::AArch64_SMULH_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_FMUL_ZZZ_D: + case Opcode::AArch64_SMIN_ZPmZ_B: [[fallthrough]]; - case Opcode::AArch64_FMUL_ZZZ_S: + case Opcode::AArch64_SMIN_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_SMAX_ZI_S: + case Opcode::AArch64_SMIN_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_SMINV_VPZ_S: + case Opcode::AArch64_SMIN_ZPmZ_S: // Example bytecode - 01008a04 [[fallthrough]]; - case Opcode::AArch64_TRN1_ZZZ_B: + case Opcode::AArch64_SMAX_ZPmZ_B: [[fallthrough]]; - case Opcode::AArch64_TRN1_ZZZ_D: + case Opcode::AArch64_SMAX_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_TRN1_ZZZ_H: + case Opcode::AArch64_SMAX_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_TRN1_ZZZ_S: + case Opcode::AArch64_SMAX_ZPmZ_S: // Example bytecode - 01008804 [[fallthrough]]; - case Opcode::AArch64_TRN2_ZZZ_B: + case Opcode::AArch64_MUL_ZPmZ_B: // Example bytecode - 40001004 [[fallthrough]]; - case Opcode::AArch64_TRN2_ZZZ_D: + case Opcode::AArch64_MUL_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_TRN2_ZZZ_H: + case Opcode::AArch64_MUL_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_TRN2_ZZZ_S: + case Opcode::AArch64_MUL_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_UZP1_ZZZ_S: - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_MOVPRFX_ZPmZ_D: + case Opcode::AArch64_FSUBR_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_FCPY_ZPmI_D: + case Opcode::AArch64_FSUBR_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FCPY_ZPmI_S: + case Opcode::AArch64_FSUBR_ZPmZ_S: // Example bytecode - 24808365 [[fallthrough]]; - case Opcode::AArch64_FNEG_ZPmZ_D: + case Opcode::AArch64_FSUB_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_FNEG_ZPmZ_S: + case Opcode::AArch64_FSUB_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FRINTN_ZPmZ_D: + case Opcode::AArch64_FSUB_ZPmZ_S: // Example bytecode - 24808165 [[fallthrough]]; - case Opcode::AArch64_FRINTN_ZPmZ_S: + case Opcode::AArch64_FMUL_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_FABS_ZPmZ_D: + case Opcode::AArch64_FMUL_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FABS_ZPmZ_S: + case Opcode::AArch64_FMUL_ZPmZ_S: // Example bytecode - 83808265 [[fallthrough]]; - case Opcode::AArch64_FSQRT_ZPmZ_S: + case Opcode::AArch64_FDIV_ZPmZ_D: // Example bytecode - 0184cd65 [[fallthrough]]; - case Opcode::AArch64_FSQRT_ZPmZ_D: + case Opcode::AArch64_FDIV_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FCVTZS_ZPmZ_DtoD: + case Opcode::AArch64_FDIV_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_FCVTZS_ZPmZ_StoD: + case Opcode::AArch64_FDIVR_ZPmZ_D: // Example bytecode - 0184cc65 [[fallthrough]]; - case Opcode::AArch64_FCVTZS_ZPmZ_StoS: + case Opcode::AArch64_FDIVR_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FCVTZS_ZPmZ_DtoS: - // No defined access types - operands[0].access = CS_AC_READ | CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_FMUL_ZPmI_D: + case Opcode::AArch64_FDIVR_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_FMUL_ZPmI_S: { - // No defined access types - operandCount = 4; - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].type = ARM64_OP_FP; - operands[3].access = CS_AC_READ; - // Doesn't recognise immediate operands - // Extract two possible values, 0.5 or 2.0 - if (operandStr.substr(operandStr.length() - 1, 1) == "5") { - operands[3].fp = 0.5f; - } else { - operands[3].fp = 2.0f; - } - - break; - } - case Opcode::AArch64_FCMLA_ZPmZZ_D: { - // No defined access types - operands[0].access = CS_AC_READ | CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - operands[4].type = ARM64_OP_IMM; - break; - } - case Opcode::AArch64_FCADD_ZPmZ_D: { - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - operands[4].type = ARM64_OP_IMM; - break; - } - case Opcode::AArch64_FSUB_ZPmI_D: + case Opcode::AArch64_FADDA_VPZ_D: [[fallthrough]]; - case Opcode::AArch64_FSUB_ZPmI_S: + case Opcode::AArch64_FADDA_VPZ_H: [[fallthrough]]; - case Opcode::AArch64_FADD_ZPmI_D: + case Opcode::AArch64_FADDA_VPZ_S: // Example bytecode - 01249865 [[fallthrough]]; - case Opcode::AArch64_FADD_ZPmI_S: - // No defined access types - operandCount = 4; - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].type = ARM64_OP_FP; - operands[3].access = CS_AC_READ; - // Doesn't recognise immediate operands - // Extract two possible values, 0.5 or 1.0 - if (operandStr.substr(operandStr.length() - 1, 1) == "5") { - operands[3].fp = 0.5f; - } else { - operands[3].fp = 1.0f; - } - break; - case Opcode::AArch64_FCMGT_PPzZ0_D: + case Opcode::AArch64_FADD_ZPmZ_D: // Example bytecode - 6480c065 [[fallthrough]]; - case Opcode::AArch64_FCMGT_PPzZ0_S: { - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - } - case Opcode::AArch64_FMLA_ZZZI_D: + case Opcode::AArch64_FADD_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_FMLA_ZZZI_S: { - // Need to define missing access types - operands[0].access = CS_AC_READ | CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - } - case Opcode::AArch64_FDIVR_ZPmZ_D: + case Opcode::AArch64_FADD_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_FDIVR_ZPmZ_S: + case Opcode::AArch64_FCADD_ZPmZ_D: // Example bytecode - 2080c064 [[fallthrough]]; - case Opcode::AArch64_FDIV_ZPmZ_D: + case Opcode::AArch64_FCADD_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_AND_PPzPP: + case Opcode::AArch64_FCADD_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_ADD_ZPmZ_B: + case Opcode::AArch64_ADD_ZPmZ_B: // Example bytecode - 00000004 [[fallthrough]]; case Opcode::AArch64_ADD_ZPmZ_D: [[fallthrough]]; @@ -580,1189 +219,44 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) [[fallthrough]]; case Opcode::AArch64_ADD_ZPmZ_S: [[fallthrough]]; - case Opcode::AArch64_FADD_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_FADD_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_FCMGE_PPzZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FCMGE_PPzZZ_S: - [[fallthrough]]; - case Opcode::AArch64_FCMGE_PPzZ0_D: - [[fallthrough]]; - case Opcode::AArch64_FCMGE_PPzZ0_S: - [[fallthrough]]; - case Opcode::AArch64_FCMGT_PPzZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FCMGT_PPzZZ_S: - [[fallthrough]]; - case Opcode::AArch64_FCMLE_PPzZ0_D: - [[fallthrough]]; - case Opcode::AArch64_FCMLE_PPzZ0_S: - [[fallthrough]]; - case Opcode::AArch64_FCMLT_PPzZ0_S: - [[fallthrough]]; - case Opcode::AArch64_FMUL_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_FMUL_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_FSUBR_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_FSUBR_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_FSUB_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_FSUB_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_FADDA_VPZ_S: + case Opcode::AArch64_EOR_ZPmZ_B: // Example bytecode - 20001904 [[fallthrough]]; - case Opcode::AArch64_MUL_ZPmZ_B: - [[fallthrough]]; - case Opcode::AArch64_MUL_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_MUL_ZPmZ_H: - [[fallthrough]]; - case Opcode::AArch64_MUL_ZPmZ_S: - [[fallthrough]]; - case Opcode::AArch64_ORR_PPzPP: - [[fallthrough]]; - case Opcode::AArch64_SMULH_ZPmZ_B: - [[fallthrough]]; - case Opcode::AArch64_SMULH_ZPmZ_H: - [[fallthrough]]; - case Opcode::AArch64_SMULH_ZPmZ_S: + case Opcode::AArch64_EOR_ZPmZ_D: [[fallthrough]]; - case Opcode::AArch64_SEL_ZPZZ_D: + case Opcode::AArch64_EOR_ZPmZ_H: [[fallthrough]]; - case Opcode::AArch64_SEL_ZPZZ_S: - // No defined access types + case Opcode::AArch64_EOR_ZPmZ_S: + // Incorrect access types operands[0].access = CS_AC_WRITE; operands[1].access = CS_AC_READ; operands[2].access = CS_AC_READ; operands[3].access = CS_AC_READ; break; - case Opcode::AArch64_FRINTPDr: - [[fallthrough]]; - case Opcode::AArch64_FRINTPSr: - [[fallthrough]]; - case Opcode::AArch64_FDUP_ZI_D: - [[fallthrough]]; - case Opcode::AArch64_FDUP_ZI_S: - [[fallthrough]]; - case Opcode::AArch64_PUNPKHI_PP: - [[fallthrough]]; - case Opcode::AArch64_PUNPKLO_PP: - [[fallthrough]]; - case Opcode::AArch64_RDVLI_XI: - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_INCB_XPiI: - [[fallthrough]]; - case Opcode::AArch64_INCD_XPiI: - [[fallthrough]]; - case Opcode::AArch64_INCH_XPiI: - [[fallthrough]]; - case Opcode::AArch64_INCW_XPiI: { - // lacking access specifiers for destination - operands[0].access = CS_AC_READ | CS_AC_WRITE; - if (operandStr.length() < 4) { - operandCount = 2; - operands[1].type = ARM64_OP_IMM; - operands[1].imm = 1; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - operands[1].ext = ARM64_EXT_INVALID; - operands[1].vector_index = -1; - } - break; - } - case Opcode::AArch64_INCD_ZPiI: - [[fallthrough]]; - case Opcode::AArch64_INCH_ZPiI: - [[fallthrough]]; - case Opcode::AArch64_INCW_ZPiI: { - // lacking access specifiers for destination - operands[0].access = CS_AC_READ | CS_AC_WRITE; - if (operandStr.length() < 6) { - operandCount = 2; - operands[1].type = ARM64_OP_IMM; - operands[1].imm = 1; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - operands[1].ext = ARM64_EXT_INVALID; - operands[1].vector_index = -1; - } - break; - } - case Opcode::AArch64_INCP_XP_B: - [[fallthrough]]; - case Opcode::AArch64_INCP_XP_D: - [[fallthrough]]; - case Opcode::AArch64_INCP_XP_H: - [[fallthrough]]; - case Opcode::AArch64_INCP_XP_S: - operands[0].access = CS_AC_READ | CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1i32: - [[fallthrough]]; - case Opcode::AArch64_LD1i64: - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_GLD1W_D_SCALED_REAL: - [[fallthrough]]; - case Opcode::AArch64_GLD1W_SXTW_REAL: { - // Access types are not set correctly - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - } - case Opcode::AArch64_GLD1D_SCALED_REAL: - [[fallthrough]]; - case Opcode::AArch64_GLD1D_REAL: { - // LD1D gather instruction doesn't correctly identify destination - // register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - operands[0].reg = static_cast(reg_enum); - - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - // LD1D gather instruction doesn't correctly identify memory operands - operands[2].type = ARM64_OP_MEM; - operands[2].access = CS_AC_READ; - - // LD1D doesn't correctly identify vector memory register correctly - uint16_t vec_enum = ARM64_REG_Z0; - std::string tmp_str(operandStr.substr(operandStr.find("["))); - // Single or double digit Z register identifier - if (tmp_str.substr(tmp_str.find("z"))[2] == '.') { - vec_enum += std::stoi(tmp_str.substr(tmp_str.find("z") + 1, 1)); - } else { - vec_enum += std::stoi(tmp_str.substr(tmp_str.find("z") + 1, 2)); - } - operands[2].mem.index = static_cast(vec_enum); - break; - } - case Opcode::AArch64_LD1RQ_W: - [[fallthrough]]; - case Opcode::AArch64_LD1RQ_W_IMM: { - // LD1RQW doesn't identify correct access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - } - case Opcode::AArch64_LD1RQ_D_IMM: { - // LD1RQ gather instruction doesn't correctly identify destination - // register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - operands[0].reg = static_cast(reg_enum); - - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - // LD1RQ gather instruction doesn't correctly identify memory operands - operands[2].type = ARM64_OP_MEM; - operands[2].access = CS_AC_READ; - break; - } - case Opcode::AArch64_GLD1SW_D_IMM_REAL: - [[fallthrough]]; - case Opcode::AArch64_GLD1D_IMM_REAL: { - // LD1D gather instruction doesn't correctly identify destination - // register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - - operands[0].reg = static_cast(reg_enum); - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - // LD1D gather instruction doesn't correctly identify second Z reg as - // memory operand - operands[2].type = ARM64_OP_MEM; - operands[2].access = CS_AC_READ; - // LD1D gather instruction doesn't recognise memory-offset immediate - // correctly - if (operandStr[operandStr.length() - 3] != '.') { - int64_t startPos = operandStr.find('#') + 1; - int64_t immSize = (operandStr.length() - 1) - startPos; - if (immSize == 1) { - operands[2].mem.disp = - std::stoi(operandStr.substr(startPos, immSize)); - } else { - // double or triple digit immediates are converted to hex, and so - // require a different conversion to uint - operands[2].mem.disp = - std::stoul(operandStr.substr(startPos, immSize), nullptr, 16); - } - } - break; - } - case Opcode::AArch64_LD1B: - [[fallthrough]]; - case Opcode::AArch64_LD1D: - [[fallthrough]]; - case Opcode::AArch64_LD1B_IMM_REAL: - [[fallthrough]]; - case Opcode::AArch64_LD1D_IMM_REAL: - [[fallthrough]]; - case Opcode::AArch64_LD1RD_IMM: - [[fallthrough]]; - case Opcode::AArch64_LD1RW_IMM: - [[fallthrough]]; - case Opcode::AArch64_LD1H: - [[fallthrough]]; - case Opcode::AArch64_LD1W: - [[fallthrough]]; - case Opcode::AArch64_LD1W_IMM_REAL: { - // LD1RW doesn't correctly identify destination register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - - operands[0].reg = static_cast(reg_enum); - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - } - case Opcode::AArch64_LD1Rv4s: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv1d: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv2d: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv2s: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv8b: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv16b: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv8h: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv4h: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1Rv4h_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv8h_POST: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ | CS_AC_WRITE; - // Fix for exclusion of post_index immediate in disassembly - operandCount = 3; - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - // For vector arrangement of 16-bit, post_index immediate is 2 - operands[2].imm = 2; - break; - case Opcode::AArch64_LD1Rv1d_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv2d_POST: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ | CS_AC_WRITE; - // Fix for exclusion of post_index immediate in disassembly - operandCount = 3; - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - // For vector arrangement of 64-bit, post_index immediate is 8 - operands[2].imm = 8; - break; - case Opcode::AArch64_LD1Rv16b_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv8b_POST: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ | CS_AC_WRITE; - - // Fix for exclusion of post_index immediate in disassembly - operandCount = 3; - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - // For vector arrangement of 8-bit, post_index immediate is 1 - operands[2].imm = 1; - break; - case Opcode::AArch64_LD1Rv2s_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Rv4s_POST: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ | CS_AC_WRITE; - - // Fix for exclusion of post_index immediate in disassembly - operandCount = 3; - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - // For vector arrangement of 32-bit, post_index immediate is 4 - operands[2].imm = 4; - break; - case Opcode::AArch64_LD1Fourv16b: - [[fallthrough]]; - case Opcode::AArch64_LD1Fourv4s: - [[fallthrough]]; - case Opcode::AArch64_LD1Fourv2d: - // Fix incorrect access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_WRITE; - operands[2].access = CS_AC_WRITE; - operands[3].access = CS_AC_WRITE; - operands[4].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1Fourv16b_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Fourv2d_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Fourv4s_POST: - // Fix incorrect access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_WRITE; - operands[2].access = CS_AC_WRITE; - operands[3].access = CS_AC_WRITE; - operands[4].access = CS_AC_READ | CS_AC_WRITE; - operands[5].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1Onev16b: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1Onev16b_POST: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ | CS_AC_WRITE; - break; - case Opcode::AArch64_LD1Twov16b: - [[fallthrough]]; - case Opcode::AArch64_LD1Twov4s: - [[fallthrough]]; - case Opcode::AArch64_LD1Twov2d: - // Fix incorrect access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_WRITE; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1Twov16b_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Twov2d_POST: - [[fallthrough]]; - case Opcode::AArch64_LD1Twov4s_POST: - // Fix incorrect access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_WRITE; - operands[2].access = CS_AC_READ | CS_AC_WRITE; - operands[3].access = CS_AC_READ; - break; - case Opcode::AArch64_LDADDLW: - [[fallthrough]]; - case Opcode::AArch64_LDADDW: - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_WRITE; - break; - case Opcode::AArch64_LD2Twov4s_POST: - // Fixing wrong access flag for offset register operand - if (operandCount == 4) { - operands[3].access = CS_AC_READ; - } - break; - case Opcode::AArch64_LDR_PXI: - [[fallthrough]]; - case Opcode::AArch64_LDR_ZXI: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_LSL_ZZI_S: - // No defined access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - // No instruction id assigned - id = ARM64_INS_LSL; - break; - case Opcode::AArch64_LD2D: - case Opcode::AArch64_LD2D_IMM: { - // LD2D doesn't correctly identify destination registers - uint16_t reg_enum0 = ARM64_REG_Z0; - uint16_t reg_enum1 = ARM64_REG_Z0; - - // tmpOpStr = "zxx.d, zyy.d" - std::string tmpOpStr(operandStr.substr(1, operandStr.find("}") - 1)); - // get dest0, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest1, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 1)); - } else { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 2)); - } - - operands[0].reg = static_cast(reg_enum0); - operands[0].access = CS_AC_WRITE; - operands[1].reg = static_cast(reg_enum1); - operands[1].access = CS_AC_WRITE; - - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - break; - } - case Opcode::AArch64_LD3D_IMM: { - // LD3D doesn't correctly identify destination registers - uint16_t reg_enum0 = ARM64_REG_Z0; - uint16_t reg_enum1 = ARM64_REG_Z0; - uint16_t reg_enum2 = ARM64_REG_Z0; - - // tmpOpStr = "zxx.d, zyy.d, znn.d" - std::string tmpOpStr(operandStr.substr(1, operandStr.find("}") - 1)); - // get dest0, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest1, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest2 - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum2 += std::stoi(tmpOpStr.substr(1, 1)); - } else { - reg_enum2 += std::stoi(tmpOpStr.substr(1, 2)); - } - - operands[0].reg = static_cast(reg_enum0); - operands[0].access = CS_AC_WRITE; - operands[1].reg = static_cast(reg_enum1); - operands[1].access = CS_AC_WRITE; - operands[2].reg = static_cast(reg_enum2); - operands[2].access = CS_AC_WRITE; - - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - break; - } - case Opcode::AArch64_LD4D_IMM: { - // LD4D doesn't correctly identify destination registers - uint16_t reg_enum0 = ARM64_REG_Z0; - uint16_t reg_enum1 = ARM64_REG_Z0; - uint16_t reg_enum2 = ARM64_REG_Z0; - uint16_t reg_enum3 = ARM64_REG_Z0; - - // tmpOpStr = "zxx.d, zyy.d, znn.d, zmm.d" - std::string tmpOpStr(operandStr.substr(1, operandStr.find("}") - 1)); - // get dest0, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest1, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest2 - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum2 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum2 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest3 - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum3 += std::stoi(tmpOpStr.substr(1, 1)); - } else { - reg_enum3 += std::stoi(tmpOpStr.substr(1, 2)); - } - - operands[0].reg = static_cast(reg_enum0); - operands[0].access = CS_AC_WRITE; - operands[1].reg = static_cast(reg_enum1); - operands[1].access = CS_AC_WRITE; - operands[2].reg = static_cast(reg_enum2); - operands[2].access = CS_AC_WRITE; - operands[3].reg = static_cast(reg_enum3); - operands[3].access = CS_AC_WRITE; - - operands[4].access = CS_AC_READ; - operands[5].access = CS_AC_READ; - break; - } - case Opcode::AArch64_MOVNWi: - [[fallthrough]]; - case Opcode::AArch64_MOVNXi: - [[fallthrough]]; - case Opcode::AArch64_MOVZWi: - [[fallthrough]]; - case Opcode::AArch64_MOVZXi: - // MOVZ incorrectly flags destination as READ | WRITE - operands[0].access = CS_AC_WRITE; - break; - case Opcode::AArch64_MOVPRFX_ZZ: - // Assign operand access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_MRS: - // MRS incorrectly flags source/destination as READ | WRITE - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - // MRS incorrectly tags ARM64_OP_REG_MRS as ARM64_OP_SYS - operands[1].type = ARM64_OP_REG_MRS; - break; - case Opcode::AArch64_MSR: - // MSR incorrectly flags source/destination as READ | WRITE - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - // MSR incorrectly tags ARM64_OP_REG_MSR as ARM64_OP_SYS - operands[0].type = ARM64_OP_REG_MSR; - break; - case Opcode::AArch64_PTEST_PP: { - // PTEST doesn't label access types for operands - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - // Doesn't identify implicit NZCV destination - implicitDestinationCount = 1; - implicitDestinations[0] = ARM64_REG_NZCV; - break; - } - case Opcode::AArch64_PTRUE_B: - [[fallthrough]]; - case Opcode::AArch64_PTRUE_H: - [[fallthrough]]; - case Opcode::AArch64_PTRUE_D: - [[fallthrough]]; - case Opcode::AArch64_PTRUE_S: - // PTRUE doesn't label access - operands[0].access = CS_AC_WRITE; - break; - case Opcode::AArch64_RET: - // If no register supplied to RET, default to x30 (LR) - if (operandCount == 0) { - operandCount = 1; - operands[0].type = ARM64_OP_REG; - operands[0].reg = ARM64_REG_LR; - operands[0].access = CS_AC_READ; - } - groupCount = 1; - groups[0] = CS_GRP_JUMP; - break; - case Opcode::AArch64_REV_ZZ_B: - [[fallthrough]]; - case Opcode::AArch64_REV_ZZ_D: - [[fallthrough]]; - case Opcode::AArch64_REV_ZZ_H: - [[fallthrough]]; - case Opcode::AArch64_REV_ZZ_S: - [[fallthrough]]; - case Opcode::AArch64_REV_PP_B: - [[fallthrough]]; - case Opcode::AArch64_REV_PP_D: - [[fallthrough]]; - case Opcode::AArch64_REV_PP_H: - [[fallthrough]]; - case Opcode::AArch64_REV_PP_S: { - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - } - case Opcode::AArch64_SST1B_D_REAL: - [[fallthrough]]; - case Opcode::AArch64_SST1D_REAL: - [[fallthrough]]; - case Opcode::AArch64_SST1D_SCALED_SCALED_REAL: { - // ST1W doesn't correctly identify first source register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - - operands[0].reg = static_cast(reg_enum); - // No defined access types - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - // SST1D{_SCALED} gather instruction doesn't correctly identify memory - // operands - operands[2].type = ARM64_OP_MEM; - operands[2].access = CS_AC_READ; - - // ST1D doesn't correctly identify vector memory register correctly - uint16_t vec_enum = ARM64_REG_Z0; - std::string tmp_str(operandStr.substr(operandStr.find("["))); - // Single or double digit Z register identifier - if (tmp_str.substr(tmp_str.find("z"))[2] == '.') { - vec_enum += std::stoi(tmp_str.substr(tmp_str.find("z") + 1, 1)); - } else { - vec_enum += std::stoi(tmp_str.substr(tmp_str.find("z") + 1, 2)); - } - operands[2].mem.index = static_cast(vec_enum); - break; - } - case Opcode::AArch64_ST2D_IMM: { - // ST2D doesn't correctly identify destination registers - uint16_t reg_enum0 = ARM64_REG_Z0; - uint16_t reg_enum1 = ARM64_REG_Z0; - - // tmpOpStr = "zxx.d, zyy.d" - std::string tmpOpStr(operandStr.substr(1, operandStr.find("}") - 1)); - // get dest0, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum0 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - // get dest1, then remove from string - // Single or double digit Z register identifier - if (tmpOpStr[2] == '.') { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 1)); - tmpOpStr.erase(0, 6); - } else { - reg_enum1 += std::stoi(tmpOpStr.substr(1, 2)); - tmpOpStr.erase(0, 7); - } - - operands[0].reg = static_cast(reg_enum0); - operands[0].access = CS_AC_READ; - operands[1].reg = static_cast(reg_enum1); - operands[1].access = CS_AC_READ; - - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - break; - } - case Opcode::AArch64_ST1B: - [[fallthrough]]; - case Opcode::AArch64_ST1D: - [[fallthrough]]; - case Opcode::AArch64_ST1B_IMM: - [[fallthrough]]; - case Opcode::AArch64_ST1D_IMM: - [[fallthrough]]; - case Opcode::AArch64_ST1W_IMM: { - // ST1W doesn't correctly identify first source register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - - operands[0].reg = static_cast(reg_enum); - // No defined access types - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - } - case Opcode::AArch64_ST1W: - [[fallthrough]]; - case Opcode::AArch64_ST1W_D: { - // ST1W doesn't correctly identify first source register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - - operands[0].reg = static_cast(reg_enum); - // No defined access types - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - break; - } - case Opcode::AArch64_SST1D_IMM: - [[fallthrough]]; - case Opcode::AArch64_SST1W_D_IMM: - [[fallthrough]]; - case Opcode::AArch64_SST1W_IMM: { - // ST1W scatter instruction doesn't correctly identify first source - // register - uint16_t reg_enum = ARM64_REG_Z0; - // Single or double digit Z register identifier - if (operandStr[3] == '.') { - reg_enum += std::stoi(operandStr.substr(2, 1)); - } else { - reg_enum += std::stoi(operandStr.substr(2, 2)); - } - - operands[0].reg = static_cast(reg_enum); - // No defined access types - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - // ST1W scatter instruction doesn't correctly identify second Z reg as - // memory operand - operands[2].type = ARM64_OP_MEM; - operands[2].access = CS_AC_READ; - // ST1W scatter instruction doesn't recognise memory-offset immediate - // correctly - if (operandStr[operandStr.length() - 3] != '.') { - int64_t startPos = operandStr.find('#') + 1; - int64_t immSize = (operandStr.length() - 1) - startPos; - if (immSize == 1) { - operands[2].mem.disp = - std::stoi(operandStr.substr(startPos, immSize)); - } else { - // double or triple digit immediates are converted to hex, and so - // require a different conversion to uint - operands[2].mem.disp = - std::stoul(operandStr.substr(startPos, immSize), nullptr, 16); - } - } - break; - } - case Opcode::AArch64_ST1i8_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1i16_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1i32_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1i64_POST: - // fixing incorrect access type for register offset - if (operandCount == 3) { - operands[2].access = CS_AC_READ; - } - break; - case Opcode::AArch64_ST1Fourv16b: - [[fallthrough]]; - case Opcode::AArch64_ST1Fourv2d: - [[fallthrough]]; - case Opcode::AArch64_ST1Fourv4s: - // ST1 incorrectly flags read and write - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - break; - case Opcode::AArch64_ST1Fourv16b_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1Fourv2d_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1Fourv2s_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1Fourv4s_POST: - // ST1 incorrectly flags read and write - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ | CS_AC_WRITE; - operands[5].access = CS_AC_READ; - // determine correct type for operand 5 - if (operandStr.find("#") != std::string::npos) { - operands[5].type = ARM64_OP_IMM; - } else { - operands[5].type = ARM64_OP_REG; - } - break; - case Opcode::AArch64_ST1Twov16b: - [[fallthrough]]; - case Opcode::AArch64_ST1Twov2d: - [[fallthrough]]; - case Opcode::AArch64_ST1Twov4s: - // ST1 incorrectly flags read and write - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_ST1Twov16b_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1Twov2d_POST: - [[fallthrough]]; - case Opcode::AArch64_ST1Twov4s_POST: - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ | CS_AC_WRITE; - operands[3].access = CS_AC_READ; - // determine correct type for operand 3 - if (operandStr.find("#") != std::string::npos) { - operands[3].type = ARM64_OP_IMM; - } else { - operands[3].type = ARM64_OP_REG; - } - break; - case Opcode::AArch64_ST2Twov4s_POST: - // ST2 post incorrectly flags read and write - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ | CS_AC_WRITE; - // Another incorrect access flag for register offset operand - if (operandCount == 4) { - operands[3].access = CS_AC_READ; - } - break; - case Opcode::AArch64_STRBui: - [[fallthrough]]; - case Opcode::AArch64_STRDui: - [[fallthrough]]; - case Opcode::AArch64_STRHui: - [[fallthrough]]; - case Opcode::AArch64_STRQui: - [[fallthrough]]; - case Opcode::AArch64_STRSui: - [[fallthrough]]; - case Opcode::AArch64_STRWui: - [[fallthrough]]; - case Opcode::AArch64_STRXui: - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_PFALSE: - operands[0].access = CS_AC_WRITE; - break; - case Opcode::AArch64_STR_PXI: - [[fallthrough]]; - case Opcode::AArch64_STR_ZXI: - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_SBFMWri: - [[fallthrough]]; - case Opcode::AArch64_SBFMXri: - // SBFM incorrectly flags destination as READ | WRITE - operands[0].access = CS_AC_WRITE; - break; - case Opcode::AArch64_SVC: - // SVC is incorrectly marked as setting x30 - implicitDestinationCount = 0; - break; - case Opcode::AArch64_SYSxt: - // No defined metadata.id for SYS instructions - id = ARM64_INS_SYS; - break; - case Opcode::AArch64_PSEL_PPPRI_B: - [[fallthrough]]; - case Opcode::AArch64_PSEL_PPPRI_D: - [[fallthrough]]; - case Opcode::AArch64_PSEL_PPPRI_H: - [[fallthrough]]; - case Opcode::AArch64_PSEL_PPPRI_S: - // Add correct access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_UBFMWri: - [[fallthrough]]; - case Opcode::AArch64_UBFMXri: - // UBFM incorrectly flags destination as READ | WRITE - operands[0].access = CS_AC_WRITE; - break; - case Opcode::AArch64_UQDECB_WPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECB_XPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECD_WPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECD_XPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECH_WPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECH_XPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECW_WPiI: - [[fallthrough]]; - case Opcode::AArch64_UQDECW_XPiI: - // UQDEC lacks access types - operands[0].access = CS_AC_READ | CS_AC_WRITE; - if (operandCount == 1) { - operandCount = 2; - operands[1].type = ARM64_OP_IMM; - operands[1].imm = 1; - } - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_UUNPKHI_ZZ_D: - [[fallthrough]]; - case Opcode::AArch64_UUNPKHI_ZZ_H: - [[fallthrough]]; - case Opcode::AArch64_UUNPKHI_ZZ_S: - [[fallthrough]]; - case Opcode::AArch64_UUNPKLO_ZZ_D: - [[fallthrough]]; - case Opcode::AArch64_UUNPKLO_ZZ_H: - [[fallthrough]]; - case Opcode::AArch64_UUNPKLO_ZZ_S: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_WHILELT_PXX_B: - [[fallthrough]]; - case Opcode::AArch64_WHILELT_PXX_D: - [[fallthrough]]; - case Opcode::AArch64_WHILELT_PXX_H: - [[fallthrough]]; - case Opcode::AArch64_WHILELT_PXX_S: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PWW_B: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PWW_D: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PWW_H: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PWW_S: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PXX_B: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PXX_D: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PXX_H: - [[fallthrough]]; - case Opcode::AArch64_WHILELO_PXX_S: - // WHILELO doesn't label access or vector specifiers - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - // Doesn't identify implicit NZCV destination - implicitDestinationCount = 1; - implicitDestinations[0] = ARM64_REG_NZCV; - break; - case Opcode::AArch64_XTNv16i8: - case Opcode::AArch64_XTNv4i32: - case Opcode::AArch64_XTNv8i16: - // XTN2 incorrectly flags destination as only WRITE - operands[0].access = CS_AC_READ | CS_AC_WRITE; - break; - case Opcode::AArch64_ZIP1_PPP_B: - [[fallthrough]]; - case Opcode::AArch64_ZIP1_PPP_D: - [[fallthrough]]; - case Opcode::AArch64_ZIP1_PPP_H: - [[fallthrough]]; - case Opcode::AArch64_ZIP1_PPP_S: - [[fallthrough]]; - case Opcode::AArch64_ZIP1_ZZZ_S: - [[fallthrough]]; - case Opcode::AArch64_ZIP1_ZZZ_D: - [[fallthrough]]; - case Opcode::AArch64_ZIP2_PPP_B: - [[fallthrough]]; - case Opcode::AArch64_ZIP2_PPP_D: - [[fallthrough]]; - case Opcode::AArch64_ZIP2_PPP_H: - [[fallthrough]]; - case Opcode::AArch64_ZIP2_PPP_S: - [[fallthrough]]; - case Opcode::AArch64_ZIP2_ZZZ_S: - [[fallthrough]]; - case Opcode::AArch64_ZIP2_ZZZ_D: - // ZIP lacks access types - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_SXTW_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_FCVT_ZPmZ_DtoS: - [[fallthrough]]; - case Opcode::AArch64_FCVT_ZPmZ_StoD: - [[fallthrough]]; - case Opcode::AArch64_SCVTF_ZPmZ_DtoS: - [[fallthrough]]; - case Opcode::AArch64_SCVTF_ZPmZ_StoD: - [[fallthrough]]; - case Opcode::AArch64_SCVTF_ZPmZ_StoS: - [[fallthrough]]; - case Opcode::AArch64_SCVTF_ZPmZ_DtoD: - // Need to see if Destination vector elements are active - operands[0].access = CS_AC_READ | CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_TBLv8i8One: - [[fallthrough]]; - case Opcode::AArch64_TBLv16i8One: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - break; - case Opcode::AArch64_TBLv8i8Two: - [[fallthrough]]; - case Opcode::AArch64_TBLv16i8Two: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - break; - case Opcode::AArch64_TBLv8i8Three: - [[fallthrough]]; - case Opcode::AArch64_TBLv16i8Three: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - break; - case Opcode::AArch64_TBLv8i8Four: - [[fallthrough]]; - case Opcode::AArch64_TBLv16i8Four: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - operands[5].access = CS_AC_READ; - break; - case Opcode::AArch64_LD1_MXIPXX_H_D: - [[fallthrough]]; - case Opcode::AArch64_LD1_MXIPXX_V_D: - [[fallthrough]]; - case Opcode::AArch64_LD1_MXIPXX_V_S: - [[fallthrough]]; - case Opcode::AArch64_LD1_MXIPXX_H_S: { - // Lacking access specifiers - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - break; - } - case Opcode::AArch64_ST1_MXIPXX_H_D: - [[fallthrough]]; - case Opcode::AArch64_ST1_MXIPXX_V_D: - [[fallthrough]]; - case Opcode::AArch64_ST1_MXIPXX_H_S: - [[fallthrough]]; - case Opcode::AArch64_ST1_MXIPXX_V_S: - // Access types are not defined - operands[0].access = CS_AC_READ; - operands[1].access = CS_AC_READ; - break; - case Opcode::AArch64_FMOPA_MPPZZ_D: - [[fallthrough]]; - case Opcode::AArch64_FMOPA_MPPZZ_S: { - // Need to add access specifiers - // although operands[0] should be READ | WRITE, due to the implemented - // decode logic for SME tile destinations, the register will be added as - // both source and destination with just WRITE access. - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].access = CS_AC_READ; - operands[4].access = CS_AC_READ; - operands[5].access = CS_AC_READ; - break; - } - case Opcode::AArch64_EXTRACT_ZPMXI_H_B: { - operandCount = 4; - operands[0].access = CS_AC_READ | CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3].reg = operands[2].sme_index.base; - operands[3].access = CS_AC_READ; - break; - } - case Opcode::AArch64_ZERO_M: { - // Operands often mangled from ZA tile overlap aliasing in decode. Need to - // re-extract relevant tiles from operandStr - operandCount = 0; - size_t pos = operandStr.find("za", 0); - while (pos != std::string::npos) { - size_t pos_2 = operandStr.find(".", pos); - if (pos_2 != std::string::npos) { - char type = operandStr[pos_2 + 1]; - // Tile Number can only ever be 1 digit - uint8_t tileNum = std::stoi(operandStr.substr((pos + 2), 1)); - switch (type) { - case 'b': - operands[operandCount].reg = ARM64_REG_ZAB0; - break; - case 'h': - operands[operandCount].reg = - static_cast(ARM64_REG_ZAH0 + tileNum); - break; - case 's': - operands[operandCount].reg = - static_cast(ARM64_REG_ZAS0 + tileNum); - break; - case 'd': - operands[operandCount].reg = - static_cast(ARM64_REG_ZAD0 + tileNum); - break; - case 'q': - operands[operandCount].reg = - static_cast(ARM64_REG_ZAQ0 + tileNum); - break; - } - } else { - operands[operandCount].reg = ARM64_REG_ZA; - } - operands[operandCount].type = ARM64_OP_REG; - operands[operandCount].access = CS_AC_WRITE; - operandCount++; - pos = operandStr.find("za", pos + 1); + case Opcode::AArch64_ZERO_M: { + // Incorrect access type: All are READ but should all be WRITE + for (int i = 0; i < operandCount; i++) { + operands[i].access = CS_AC_WRITE; } break; } } - revertAliasing(); + if (isAlias) { + exceptionString_ = + "This instruction is an alias. The printed mnemonic and operand string " + "differ from what is expected of the Capstone opcode."; + } } InstructionMetadata::InstructionMetadata(const uint8_t* invalidEncoding, uint8_t bytes) - : id(ARM64_INS_INVALID), - opcode(Opcode::AArch64_INSTRUCTION_LIST_END), + : id(AARCH64_INS_INVALID), + opcode(Opcode::INSTRUCTION_LIST_END), implicitSourceCount(0), implicitDestinationCount(0), groupCount(0), setsFlags(false), - writeback(false), + isAlias(false), operandCount(0) { assert(bytes <= sizeof(encoding)); std::memcpy(encoding, invalidEncoding, bytes); @@ -1770,835 +264,6 @@ InstructionMetadata::InstructionMetadata(const uint8_t* invalidEncoding, operandStr[0] = '\0'; } -void InstructionMetadata::revertAliasing() { - // Check mnemonics known to be aliases and see if their opcode matches - // something else - switch (id) { - case ARM64_INS_ASR: - if (opcode == Opcode::AArch64_ASRVWr || - opcode == Opcode::AArch64_ASRVXr) { - // asr rd, rn, rm; alias for: asrv rd, rn, rm - return; - } - if (opcode == Opcode::AArch64_SBFMWri || - opcode == Opcode::AArch64_SBFMXri) { - operandCount = 4; - - operands[3].type = ARM64_OP_IMM; - operands[3].access = CS_AC_READ; - if (opcode == Opcode::AArch64_SBFMWri) { - // 32-bit - operands[3].imm = 31; - } else { - operands[3].imm = 63; - } - return; - } - return aliasNYI(); - case ARM64_INS_AT: - return aliasNYI(); - case ARM64_INS_BFI: - // TODO no tests of alias - if (opcode == Opcode::AArch64_BFMWri) { - // bfi wd, wn, #lsb, #width; alias for - // bfm wd, wn, #(-lsb MOD 32), #(width - 1) - operands[2].imm = static_cast(-operands[2].imm) % 32; - operands[3].imm = operands[3].imm - 1; - return; - } - if (opcode == Opcode::AArch64_BFMXri) { - // bfi xd, xn, #lsb, #width; alias for - // bfm xd, xn, #(-lsb MOD 64), #(width - 1) - operands[2].imm = static_cast(-operands[2].imm) % 64; - operands[3].imm = operands[3].imm - 1; - return; - } - return aliasNYI(); - case ARM64_INS_BFXIL: - // TODO no tests for alias - if (opcode == Opcode::AArch64_BFMWri || - opcode == Opcode::AArch64_BFMXri) { - // bfxil rd, rn, #lsb, #width; alias for - // bfm rd, rn, #lsb, #(lsb + width - 1) - operands[3].imm = operands[2].imm + operands[3].imm - 1; - return; - } - return aliasNYI(); - case ARM64_INS_CINC: - if (opcode == Opcode::AArch64_CSINCWr || - opcode == Opcode::AArch64_CSINCXr) { - // cinc rd, rn, cc; alias for: csinc rd, rn, rn, invert(cc) - operandCount = 3; - - operands[2].type = ARM64_OP_REG; - operands[2].access = CS_AC_READ; - operands[2].reg = operands[1].reg; - - cc ^= 1; // invert lowest bit to negate cc - return; - } - return aliasNYI(); - case ARM64_INS_CINV: - return aliasNYI(); - case ARM64_INS_CMN: - // cmn , alias for adds - operandCount = 3; - operands[2] = operands[1]; - operands[1] = operands[0]; - operands[1].access = CS_AC_READ; - - operands[0].type = ARM64_OP_REG; - operands[0].access = CS_AC_WRITE; - - if (opcode == Opcode::AArch64_ADDSXri || - opcode == Opcode::AArch64_ADDSXrr || - opcode == Opcode::AArch64_ADDSXrs) { - // 64-bit version - operands[0].reg = ARM64_REG_XZR; - } else { - // 32-bit version - operands[0].reg = ARM64_REG_WZR; - } - return; - case ARM64_INS_CMP: - if (opcode == Opcode::AArch64_SUBSWri || - opcode == Opcode::AArch64_SUBSWrs || - opcode == Opcode::AArch64_SUBSWrx || - opcode == Opcode::AArch64_SUBSXri || - opcode == Opcode::AArch64_SUBSXrs || - opcode == Opcode::AArch64_SUBSXrx || - opcode == Opcode::AArch64_SUBSXrx64) { - operandCount = 3; - operands[2] = operands[1]; - - operands[1] = operands[0]; - operands[1].access = CS_AC_READ; - - operands[0].type = ARM64_OP_REG; - operands[0].access = CS_AC_WRITE; - - if (opcode == Opcode::AArch64_SUBSWri || - opcode == Opcode::AArch64_SUBSWrs || - opcode == Opcode::AArch64_SUBSWrx) { - operands[0].reg = ARM64_REG_WZR; - } else { - operands[0].reg = ARM64_REG_XZR; - } - return; - } - return aliasNYI(); - case ARM64_INS_CNEG: - if (opcode == Opcode::AArch64_CSNEGWr || - opcode == Opcode::AArch64_CSNEGXr) { - // cneg rd, rn, cc; alias for: csneg rd, rn, rn, invert(cc) - operandCount = 3; - operands[2] = operands[1]; - cc ^= 1; // invert lowest bit to negate cc - return; - } - return aliasNYI(); - case ARM64_INS_CSET: - // TODO no usage in regression tests - if (opcode == Opcode::AArch64_CSINCWr || - opcode == Opcode::AArch64_CSINCXr) { - // cset rd, cc; alias for: csinc rd, zr, zr, invert(cc) - operandCount = 3; - - operands[1].type = ARM64_OP_REG; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - - operands[2].type = ARM64_OP_REG; - operands[2].access = CS_AC_READ; - operands[2].shift = {ARM64_SFT_INVALID, 0}; - - if (opcode == Opcode::AArch64_CSINCWr) { - operands[1].reg = ARM64_REG_WZR; - operands[2].reg = ARM64_REG_WZR; - } else { - operands[1].reg = ARM64_REG_XZR; - operands[2].reg = ARM64_REG_XZR; - } - - cc ^= 1; // invert lowest bit to negate cc - - return; - } - return aliasNYI(); - case ARM64_INS_CSETM: - if (opcode == Opcode::AArch64_CSINVWr || - opcode == Opcode::AArch64_CSINVXr) { - // csetm rd, cc; alias for: csinv rd, zr, zr, invert(cc) - operandCount = 3; - - operands[1].type = ARM64_OP_REG; - operands[1].access = CS_AC_READ; - - operands[2].type = ARM64_OP_REG; - operands[2].access = CS_AC_READ; - - if (opcode == Opcode::AArch64_CSINVWr) { - operands[1].reg = ARM64_REG_WZR; - operands[2].reg = ARM64_REG_WZR; - } else { - operands[1].reg = ARM64_REG_XZR; - operands[2].reg = ARM64_REG_XZR; - } - - cc ^= 1; // invert lowest bit to negate cc - - return; - } - return aliasNYI(); - case ARM64_INS_DC: - return aliasNYI(); - case ARM64_INS_IC: - return aliasNYI(); - case ARM64_INS_LSL: - // TODO no usage in regression tests - if (opcode == Opcode::AArch64_UBFMWri || - opcode == Opcode::AArch64_UBFMXri) { - // lsl rd, rn, #shift; alias for: - // ubfm rd, rn, #(-shift MOD <32|64>), #(<31|63> - shift) - operandCount = 4; - uint8_t highestBit = 63; - if (opcode == Opcode::AArch64_UBFMWri) { - highestBit = 31; - } - - auto shift = operands[2].imm; - operands[2].imm = (-shift) & highestBit; - operands[3].type = ARM64_OP_IMM; - operands[3].imm = highestBit - shift; - operands[3].access = CS_AC_READ; - return; - } - if (opcode == Opcode::AArch64_LSLVWr || - opcode == Opcode::AArch64_LSLVXr || - opcode == Opcode::AArch64_LSL_ZZI_S) { - return; - } - return aliasNYI(); - case ARM64_INS_LSR: - if (opcode == Opcode::AArch64_LSRVWr || - opcode == Opcode::AArch64_LSRVXr) { - // lsr rd, rn, rm; alias for lsrv rd, rn, rm - return; - } - if (opcode == Opcode::AArch64_UBFMWri || - opcode == Opcode::AArch64_UBFMXri) { - // lsr rd, rn, #amount; alias for ubfm rd, rn, #amount, #<31|63> - operandCount = 4; - - operands[3].type = ARM64_OP_IMM; - operands[3].access = CS_AC_READ; - - if (opcode == Opcode::AArch64_UBFMWri) { - operands[3].imm = 31; - } else { - operands[3].imm = 63; - } - return; - } - return aliasNYI(); - case ARM64_INS_MNEG: - // TODO no test - if (opcode == Opcode::AArch64_MSUBXrrr) { - // mneg xd, xn, xm; alias for msub xd, xn, xm, xzr - operandCount = 4; - operands[3].type = ARM64_OP_REG; - operands[3].access = CS_AC_READ; - operands[3].reg = ARM64_REG_XZR; - return; - } - if (opcode == Opcode::AArch64_MSUBWrrr) { - // mneg wd, wn, wm; alias for msub wd, wn, wm, wzr - operandCount = 4; - operands[3].type = ARM64_OP_REG; - operands[3].access = CS_AC_READ; - operands[3].reg = ARM64_REG_WZR; - return; - } - return aliasNYI(); - case ARM64_INS_MOV: - // TODO no specific tests - if (opcode == Opcode::AArch64_AND_PPzPP) { - // mov pd.b, pg/z, pn.b; alias for: and pd.b, pg/z, pn.b, pn.b - operandCount = 4; - operands[3] = operands[2]; - return; - } - if (opcode == Opcode::AArch64_ADDXri || - opcode == Opcode::AArch64_ADDWri) { - // mov to/from sp; alias for: add , , #0 - operandCount = 3; - operands[2].type = ARM64_OP_IMM; - operands[2].imm = 0; - operands[2].access = CS_AC_READ; - operands[2].shift.type = ARM64_SFT_INVALID; - operands[2].vas = ARM64_VAS_INVALID; - operands[2].vector_index = -1; - return; - } - if (opcode == Opcode::AArch64_DUPi8 || opcode == Opcode::AArch64_DUPi16 || - opcode == Opcode::AArch64_DUPi32 || - opcode == Opcode::AArch64_DUPi64) { - // mov vd, Vn.T[index]; alias of dup vd, Vn.T[index] - return; - } - if (opcode == Opcode ::AArch64_CPY_ZPzI_B || - opcode == Opcode ::AArch64_CPY_ZPzI_D || - opcode == Opcode ::AArch64_CPY_ZPzI_H || - opcode == Opcode ::AArch64_CPY_ZPzI_S) { - // mov zd.T, pg/z, #imm{, shift}; alias of cpy zd.T, pg/z, #imm{, - // shift} - operandCount = 3; - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - - // get imm value - std::string tmpOpStr(operandStr.substr(operandStr.find("#") + 1)); - auto value = std::stoi(tmpOpStr, 0, 16); - operands[2].imm = tmpOpStr.length() == 4 ? static_cast(value) - : static_cast(value); - return; - } - if (opcode == Opcode::AArch64_DUPM_ZI || - opcode == Opcode::AArch64_DUP_ZI_B || - opcode == Opcode::AArch64_DUP_ZI_D || - opcode == Opcode::AArch64_DUP_ZI_H || - opcode == Opcode::AArch64_DUP_ZI_S) { - // mov Zd.T, #imm; alias for dupm Zd.T, #imm - // or - // mov Zd.T, #imm{, shift}; alias for dup Zd.T, #imm{, shift} - operandCount = 2; - operands[0].access = CS_AC_WRITE; - operands[1].type = ARM64_OP_IMM; - operands[1].access = CS_AC_READ; - - uint8_t start = operandStr[6] == '#' ? 7 : 8; - - if (opcode == Opcode::AArch64_DUPM_ZI) { - char specifier = operandStr[start - 4]; - switch (specifier) { - case 'b': - operands[0].vas = ARM64_VAS_1B; - break; - case 'h': - operands[0].vas = ARM64_VAS_1H; - break; - case 's': - operands[0].vas = ARM64_VAS_1S; - break; - case 'd': - operands[0].vas = ARM64_VAS_1D; - break; - - default: - break; - } - } - - bool hex = false; - if (operandStr[start + 1] == 'x') { - hex = true; - start += 2; - } - - uint8_t end = start + 1; - while (true) { - if (operandStr[end] < '0') { - break; - } - end++; - } - - std::string sub = operandStr.substr(start, end); - if (hex) { - operands[1].imm = std::stoul(sub, 0, 16); - } else { - operands[1].imm = stoi(sub); - } - - return; - } - if (opcode == Opcode::AArch64_DUP_ZR_S || - opcode == Opcode::AArch64_DUP_ZR_D || - opcode == Opcode::AArch64_DUP_ZR_B || - opcode == Opcode::AArch64_DUP_ZR_H) { - // mov Zd.T, ; alias for dup Zd.T, - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - - char specifier = operandStr[operandStr.find(".") + 1]; - switch (specifier) { - case 'b': - operands[0].vas = ARM64_VAS_1B; - break; - case 'h': - operands[0].vas = ARM64_VAS_1H; - break; - case 's': - operands[0].vas = ARM64_VAS_1S; - break; - case 'd': - operands[0].vas = ARM64_VAS_1D; - break; - - default: - break; - } - return; - } - if (opcode == Opcode::AArch64_DUP_ZZI_S || - opcode == Opcode::AArch64_DUP_ZZI_D || - opcode == Opcode::AArch64_DUP_ZZI_Q) { - // mov Zd.T, Vn; alias for dup Zd.T, Zn.T[0] - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - - uint8_t start = operandStr[2] == '.' ? 7 : 8; - uint8_t end = operandStr.length() - start; - - operands[1].reg = static_cast( - ARM64_REG_Z0 + stoi(operandStr.substr(start, end))); - operands[1].vector_index = 0; - return; - } - if (opcode == Opcode::AArch64_INSvi32lane || - opcode == Opcode::AArch64_INSvi64lane) { - // mov vd.T[index1], vn.T[index2]; alias for ins vd.T[index1], - // vn.T[index2] - return; - } - if (opcode == Opcode::AArch64_ORRv8i8) { - // mov vd, vn; alias for orr vd.t, vn.t, vn.t - operandCount = 3; - - operands[2] = operands[1]; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - return; - } - if (opcode >= Opcode::AArch64_EXTRACT_ZPMXI_H_B && - opcode <= Opcode::AArch64_EXTRACT_ZPMXI_V_S) { - return; - } - if (opcode == Opcode::AArch64_ORRWri || - opcode == Opcode::AArch64_ORRWrs || - opcode == Opcode::AArch64_ORRXri || - opcode == Opcode::AArch64_ORRXrs) { - // mov rd, rn; alias for: orr rd, zr, rn - operandCount = 3; - operands[2] = operands[1]; - - operands[1].type = ARM64_OP_REG; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - if (opcode == Opcode::AArch64_ORRWri || - opcode == Opcode::AArch64_ORRWrs) { - operands[1].reg = ARM64_REG_WZR; - } else { - operands[1].reg = ARM64_REG_XZR; - } - return; - } - if (opcode == Opcode::AArch64_ORR_PPzPP) { - // mov Pd.b, Pn.b; alias for: orr Pd.b, Pn/z, Pn.b, Pn.b - operandCount = 4; - operands[0].access = CS_AC_WRITE; - operands[0].vas = ARM64_VAS_1B; - operands[1].access = CS_AC_READ; - operands[1].vas = ARM64_VAS_1B; - operands[2] = operands[1]; - operands[3] = operands[1]; - return; - } - if (opcode == Opcode::AArch64_ORR_ZZZ) { - // mov Zd.d, Zn.d; alias for: orr Zd.d, Zn.d, Zn.d - operandCount = 3; - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2] = operands[1]; - return; - } - if (opcode == Opcode::AArch64_ORRv16i8) { - // mov Vd.16b, Vn.16b; alias for: orr Vd.16b, Vn.16b, Vn.16b - operandCount = 3; - operands[2] = operands[1]; - return; - } - if (opcode == Opcode::AArch64_SEL_ZPZZ_S || - opcode == Opcode::AArch64_SEL_ZPZZ_D) { - // mov Zd.T, Pg/M, Zn.T; alias for: sel Zd.T, Pg, Zn.T, Zd.T - if (mnemonic[0] == 'm') { - // SEL instructions id sometimes set as ARM64_INS_MOV even if - // aliasing hasn't occurred so double check mnemonic is MOV alias - operandCount = 4; - operands[3] = operands[0]; - operands[3].access = CS_AC_READ; - } - return; - } - if (opcode == Opcode::AArch64_UMOVvi8 || - opcode == Opcode::AArch64_UMOVvi16 || - opcode == Opcode::AArch64_UMOVvi32 || - opcode == Opcode::AArch64_UMOVvi64) { - // mov rd, Vn.T[index]; alias for umov rd, Vn.T[index] - return; - } - if (opcode == Opcode::AArch64_MOVZWi || - opcode == Opcode::AArch64_MOVZXi) { - // mov rd, #0; alias for: movz rd, #0{, shift #0} - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_LSL, 0}; - return; - } - if (opcode == Opcode::AArch64_MOVNWi || - opcode == Opcode::AArch64_MOVNXi) { - // mov rd, #amount; alias for: movn rd, #amount{, shift #0} - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_LSL, 0}; - operands[1].imm = ~(operands[1].imm); - return; - } - if (opcode == Opcode::AArch64_INSvi8gpr || - opcode == Opcode::AArch64_INSvi16gpr || - opcode == Opcode::AArch64_INSvi32gpr || - opcode == Opcode::AArch64_INSvi64gpr) { - // mov vd.ts[index], rn; alias for: ins vd.ts[index], rn - return; - } - if (opcode == Opcode::AArch64_UMOVvi32_idx0 || - opcode == Opcode::AArch64_UMOVvi64_idx0) { - // mov wd, vn.t[0]; alias for: umov wd, vn.t[0] - return; - } - return aliasNYI(); - case ARM64_INS_MUL: - // TODO add comment - if (opcode == Opcode::AArch64_MADDXrrr || - opcode == Opcode::AArch64_MADDWrrr) { - operandCount = 4; - operands[3].type = ARM64_OP_REG; - operands[3].access = CS_AC_READ; - if (opcode == Opcode::AArch64_MADDWrrr) { - operands[3].reg = ARM64_REG_WZR; - } else { - operands[3].reg = ARM64_REG_XZR; - } - return; - } - if (opcode == Opcode::AArch64_MUL_ZPmZ_B || - opcode == Opcode::AArch64_MUL_ZPmZ_D || - opcode == Opcode::AArch64_MUL_ZPmZ_H || - opcode == Opcode::AArch64_MUL_ZPmZ_S) { - return; - } - return aliasNYI(); - case ARM64_INS_MVN: - if (opcode == Opcode::AArch64_ORNWrs || - opcode == Opcode::AArch64_ORNXrs) { - // mvn rd, rn; alias for: orn rd, zr, rn - operandCount = 3; - operands[2] = operands[1]; - - operands[1].type = ARM64_OP_REG; - operands[1].access = CS_AC_READ; - operands[1].shift = {ARM64_SFT_INVALID, 0}; - if (opcode == Opcode::AArch64_ORNWrs) { - operands[1].reg = ARM64_REG_WZR; - } else { - operands[1].reg = ARM64_REG_XZR; - } - return; - } - if (opcode == Opcode::AArch64_NOTv16i8 || - opcode == Opcode::AArch64_NOTv8i8) { - // TODO needs tests - // mvn vd.t, vn.t; alias for : not vd.t, vn.t - // Blank entry was for a legitimate alias, however operands were - // identical so nothing to alter between the instructions. - return; - } - return aliasNYI(); - case ARM64_INS_NEG: - // TODO needs tests - if (opcode == Opcode::AArch64_SUBWrs || - opcode == Opcode::AArch64_SUBXrs) { - // neg rd, rm{, shift #amount}; alias for: - // sub rd, zr, rm{, shift #amount} - operandCount = 3; - operands[2] = operands[1]; - - operands[1].type = ARM64_OP_REG; - operands[1].access = CS_AC_READ; - - if (opcode == Opcode::AArch64_SUBWrs) { - operands[1].reg = ARM64_REG_WZR; - } else { - operands[1].reg = ARM64_REG_XZR; - } - return; - } - if (opcode == Opcode::AArch64_NEGv2i64) { - // No alias present, trying to alias self. - return; - } - return aliasNYI(); - case ARM64_INS_NEGS: - if (opcode == Opcode::AArch64_SUBSWrs || - opcode == Opcode::AArch64_SUBSXrs) { - // negs rd, rm{, shift #amount}; alias for: - // subs rd, zr, rm{, shift #amount} - operandCount = 3; - operands[2] = operands[1]; - - operands[1].type = ARM64_OP_REG; - operands[1].access = CS_AC_READ; - - if (opcode == Opcode::AArch64_SUBWrs) { - operands[1].reg = ARM64_REG_WZR; - } else { - operands[1].reg = ARM64_REG_XZR; - } - return; - } - return aliasNYI(); - case ARM64_INS_NGC: - return aliasNYI(); - case ARM64_INS_NGCS: - return aliasNYI(); - case ARM64_INS_NOT: - if (opcode == Opcode::AArch64_EOR_PPzPP) { - // not pd.b, pg/z, pn.b; alias for: eor pd.b, pg/z, pn.b, pg.b - operandCount = 4; - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[2].access = CS_AC_READ; - operands[3] = operands[1]; - return; - } - return aliasNYI(); - case ARM64_INS_REV64: - // rev64 vd.t, vn.t - if (opcode == Opcode::AArch64_REV64v16i8 || - opcode == Opcode::AArch64_REV64v2i32 || - opcode == Opcode::AArch64_REV64v4i16 || - opcode == Opcode::AArch64_REV64v4i32 || - opcode == Opcode::AArch64_REV64v8i16 || - opcode == Opcode::AArch64_REV64v8i8) { - operandCount = 2; - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - return; - } - return aliasNYI(); - case ARM64_INS_ROR: - // TODO needs test - if (opcode == Opcode::AArch64_RORVWr || - opcode == Opcode::AArch64_RORVXr) { - // ror wd, wn, wm; alias for : rorv wd, wn, wm - // ror xd, xn, xm; alias for : rorv xd, xn, xm - // Blank entry was for a legitimate alias, however operands were - // identical so nothing to alter between the instructions. - return; - } - return aliasNYI(); - case ARM64_INS_SBFIZ: - // TODO needs test - if (opcode == Opcode::AArch64_SBFMWri || - opcode == Opcode::AArch64_SBFMXri) { - operands[3].imm -= 1; - - uint8_t highestBit = 63; - if (opcode == Opcode::AArch64_SBFMWri) { - highestBit = 31; - } - - operands[2].imm = (-operands[2].imm) & highestBit; - return; - } - return aliasNYI(); - case ARM64_INS_SBFX: - // TODO needs test - if (opcode == Opcode::AArch64_SBFMWri || - opcode == Opcode::AArch64_SBFMXri) { - // sbfx rd, rn, #lsb, #width; alias for - // sbfm rd, rn, #lsb, #(lsb + width - 1) - operands[3].imm = operands[2].imm + operands[3].imm - 1; - return; - } - return aliasNYI(); - case ARM64_INS_SMNEGL: - return aliasNYI(); - case ARM64_INS_SMULL: - if (opcode == Opcode::AArch64_SMADDLrrr) { - operandCount = 4; - operands[3].type = ARM64_OP_REG; - operands[3].access = CS_AC_READ; - operands[3].reg = ARM64_REG_XZR; - return; - } - return aliasNYI(); - case ARM64_INS_SXTB: - // sxtb rd, rn; alias for: sbfm rd, rn, #0, #7 - if (opcode == Opcode::AArch64_SBFMWri || - opcode == Opcode::AArch64_SBFMXri) { - operandCount = 4; - - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - operands[2].imm = 0; - - operands[3].type = ARM64_OP_IMM; - operands[3].access = CS_AC_READ; - operands[3].imm = 7; - return; - } - return aliasNYI(); - case ARM64_INS_SXTH: - // sxth rd, rn; alias for: sbfm rd, rn, #0, #15 - if (opcode == Opcode::AArch64_SBFMWri || - opcode == Opcode::AArch64_SBFMXri) { - operandCount = 4; - - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - operands[2].imm = 0; - - operands[3].type = ARM64_OP_IMM; - operands[3].access = CS_AC_READ; - operands[3].imm = 15; - return; - } - return aliasNYI(); - case ARM64_INS_SXTW: - // sxtw rd, rn; alias for: sbfm rd, rn, #0, #31 - if (opcode == Opcode::AArch64_SBFMXri) { - operandCount = 4; - - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - operands[2].imm = 0; - - operands[3].type = ARM64_OP_IMM; - operands[3].access = CS_AC_READ; - operands[3].imm = 31; - return; - } - if (opcode == Opcode::AArch64_SXTW_ZPmZ_D) { - return; - } - return aliasNYI(); - case ARM64_INS_SYS: { - // TODO no test - // Extract IC/DC/AT/TLBI operation - if (std::string(mnemonic) == "dc") { - if (operandStr.substr(0, 3) == "zva") { - id = ARM64_INS_DC; - operandCount = 3; - operands[1] = operands[0]; - operands[1].access = CS_AC_READ; - operands[0].type = ARM64_OP_SYS; - operands[0].sys = ARM64_DC_ZVA; - operands[2].type = ARM64_OP_REG_MRS; - operands[2].access = CS_AC_READ; - operands[2].imm = ARM64_SYSREG_DCZID_EL0; - return; - } - } - return aliasNYI(); - } - case ARM64_INS_TLBI: - return aliasNYI(); - case ARM64_INS_TST: - // TODO needs test for register case - if (opcode == Opcode::AArch64_ANDSWrs || - opcode == Opcode::AArch64_ANDSXrs || - opcode == Opcode::AArch64_ANDSWri || - opcode == Opcode::AArch64_ANDSXri) { - // tst rn, rm; alias for: ands zr, rn, rm - // tst rn, #imm; alias for: ands zr, rn, #imm - operandCount = 3; - operands[2] = operands[1]; - operands[1] = operands[0]; - operands[1].access = CS_AC_READ; - - operands[0].type = ARM64_OP_REG; - operands[0].access = CS_AC_WRITE; - if (opcode == Opcode::AArch64_ANDSWrs || - opcode == Opcode::AArch64_ANDSWri) { - operands[0].reg = ARM64_REG_WZR; - } else { - operands[0].reg = ARM64_REG_XZR; - } - return; - } - return aliasNYI(); - case ARM64_INS_UBFIZ: - // TODO needs test and comment - if (opcode == Opcode::AArch64_UBFMWri || - opcode == Opcode::AArch64_UBFMXri) { - operands[3].imm -= 1; - - uint8_t highestBit = 63; - if (opcode == Opcode::AArch64_UBFMWri) { - highestBit = 31; - } - - operands[2].imm = (-operands[2].imm) & highestBit; - return; - } - return aliasNYI(); - case ARM64_INS_UBFX: - // TODO needs test - if (opcode == Opcode::AArch64_UBFMWri || - opcode == Opcode::AArch64_UBFMXri) { - // ubfx rd, rn, #lsb, #width; alias for - // ubfm rd, rn, #lsb, #(lsb + width - 1) - operands[3].imm = operands[2].imm + operands[3].imm - 1; - return; - } - return aliasNYI(); - case ARM64_INS_UMNEGL: - return aliasNYI(); - case ARM64_INS_UMULL: - // umull xd, wn, wm; alias for: umaddl xd, wn, wm, xzr - if (opcode == Opcode::AArch64_UMADDLrrr) { - operandCount = 4; - operands[3].type = ARM64_OP_REG; - operands[3].access = CS_AC_READ; - operands[3].reg = ARM64_REG_XZR; - return; - } - return aliasNYI(); - case ARM64_INS_UXTB: - // TODO needs test - // uxtb wd, wn; alias for: ubfm wd, wn, #0, #7 - if (opcode == Opcode::AArch64_UBFMWri) { - operandCount = 4; - operands[2].type = ARM64_OP_IMM; - operands[2].access = CS_AC_READ; - operands[2].imm = 0; - operands[3].type = ARM64_OP_IMM; - operands[3].access = CS_AC_READ; - operands[3].imm = 7; - return; - } - return aliasNYI(); - case ARM64_INS_UXTH: - return aliasNYI(); - } -} - -void InstructionMetadata::aliasNYI() { - metadataExceptionEncountered_ = true; - metadataException_ = InstructionException::AliasNotYetImplemented; -} - } // namespace aarch64 } // namespace arch -} // namespace simeng \ No newline at end of file +} // namespace simeng diff --git a/src/lib/arch/aarch64/InstructionMetadata.hh b/src/lib/arch/aarch64/InstructionMetadata.hh index 90eba4a5d0..d905d93e4d 100644 --- a/src/lib/arch/aarch64/InstructionMetadata.hh +++ b/src/lib/arch/aarch64/InstructionMetadata.hh @@ -53,7 +53,7 @@ struct InstructionMetadata { static const size_t MAX_GROUPS = sizeof(cs_detail::groups) / sizeof(uint8_t); /** The maximum number of operands as defined in Capstone */ static const size_t MAX_OPERANDS = - sizeof(cs_arm64::operands) / sizeof(cs_arm64_op); + sizeof(cs_aarch64::operands) / sizeof(cs_aarch64_op); /** The instruction's mnemonic ID. */ unsigned int id; @@ -65,7 +65,7 @@ struct InstructionMetadata { uint8_t encoding[4]; /** The instruction's mnemonic. */ - char mnemonic[CS_MNEMONIC_SIZE]; + std::string mnemonic; /** The remainder of the instruction's assembly representation. */ std::string operandStr; @@ -88,23 +88,17 @@ struct InstructionMetadata { uint8_t cc; /** Whether this instruction sets the condition flags. */ bool setsFlags; - /** Whether this instruction performs a base-address register writeback - * operation. */ - bool writeback; + + /** Whether this instruction is an alias. */ + bool isAlias; /** The explicit operands. */ - cs_arm64_op operands[MAX_OPERANDS]; + cs_aarch64_op operands[MAX_OPERANDS]; + /** The number of explicit operands. */ uint8_t operandCount; private: - /** Detect instruction aliases and update metadata to match the de-aliased - * instruction. */ - void revertAliasing(); - - /** Flag the instruction as invalid due to a detected unsupported alias. */ - void aliasNYI(); - /** The current exception state of this instruction. */ InstructionException metadataException_ = InstructionException::None; diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 6ff4fd99a9..357077e7b3 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -99,7 +99,7 @@ span Instruction::generateAddresses() { const uint16_t partition_num = VL_bits / 64; const uint64_t n = sourceValues_[partition_num + 2].get(); uint64_t m = 0; - if (metadata_.operands[2].mem.index) + if (metadata_.operands[2].mem.index != AARCH64_REG_INVALID) m = sourceValues_[partition_num + 3].get() << 3; setMemoryAddresses({(n + m), static_cast(VL_bits / 8)}); break; @@ -290,8 +290,8 @@ span Instruction::generateAddresses() { setMemoryAddresses({base + offset, static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1B_IMM_REAL: { // ld1b {zt.b}, pg/z, [xn{, #imm, - // mul vl}] + case Opcode::AArch64_LD1B_IMM: { // ld1b {zt.b}, pg/z, [xn{, #imm, + // mul vl}] const uint64_t base = sourceValues_[1].get(); const int64_t offset = static_cast(metadata_.operands[2].mem.disp); @@ -308,8 +308,8 @@ span Instruction::generateAddresses() { setMemoryAddresses({addr, static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1D_IMM_REAL: { // ld1d {zt.d}, pg/z, [xn{, #imm, - // mul vl}] + case Opcode::AArch64_LD1D_IMM: { // ld1d {zt.d}, pg/z, [xn{, #imm, + // mul vl}] const uint16_t partition_num = VL_bits / 64; const uint64_t base = sourceValues_[1].get(); @@ -336,8 +336,8 @@ span Instruction::generateAddresses() { setMemoryAddresses({addr, static_cast(VL_bits / 8)}); break; } - case Opcode::AArch64_LD1W_IMM_REAL: { // ld1w {zt.s}, pg/z, [xn{, #imm, - // mul vl}] + case Opcode::AArch64_LD1W_IMM: { // ld1w {zt.s}, pg/z, [xn{, #imm, + // mul vl}] const uint16_t partition_num = VL_bits / 32; const uint64_t base = sourceValues_[1].get(); @@ -429,7 +429,7 @@ span Instruction::generateAddresses() { } case Opcode::AArch64_LD2Twov4s_POST: { // ld2 {vt1.4s, vt2.4s}, [xn], // #imm - const uint64_t base = sourceValues_[2].get(); + const uint64_t base = sourceValues_[0].get(); setMemoryAddresses({{base, 16}, {base + 16, 16}}); break; } @@ -600,7 +600,7 @@ span Instruction::generateAddresses() { } case Opcode::AArch64_LDRXl: { // ldr xt, #imm setMemoryAddresses( - {{metadata_.operands[1].imm + instructionAddress_, 8}}); + {{metadata_.operands[1].mem.disp + instructionAddress_, 8}}); break; } case Opcode::AArch64_LDRXroW: { // ldr xt, [xn, wn{, extend {#amount}}] @@ -847,7 +847,7 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } - case Opcode::AArch64_SST1B_D_REAL: { // st1b {zd.d}, pg, [xn, zm.d] + case Opcode::AArch64_SST1B_D: { // st1b {zd.d}, pg, [xn, zm.d] const uint64_t* p = sourceValues_[1].getAsVector(); const uint16_t partition_num = VL_bits / 64; @@ -866,7 +866,7 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_SST1D_REAL: { // st1d {zt.d}, pg, [xn, zm.d] + case Opcode::AArch64_SST1D: { // st1d {zt.d}, pg, [xn, zm.d] const uint64_t* p = sourceValues_[1].getAsVector(); const uint16_t partition_num = VL_bits / 64; @@ -886,8 +886,8 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_SST1D_SCALED_SCALED_REAL: { // st1d {zt.d}, pg, [xn, - // zm.d, lsl #3] + case Opcode::AArch64_SST1D_SCALED: { // st1d {zt.d}, pg, [xn, + // zm.d, lsl #3] const uint64_t* p = sourceValues_[1].getAsVector(); const uint16_t partition_num = VL_bits / 64; diff --git a/src/lib/arch/aarch64/Instruction_decode.cc b/src/lib/arch/aarch64/Instruction_decode.cc index 165c51b9ac..6d2007cb55 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -1,3 +1,5 @@ +#include + #include "InstructionMetadata.hh" #define NOT(bits, length) (~bits & (1 << length - 1)) @@ -9,6 +11,65 @@ namespace simeng { namespace arch { namespace aarch64 { +/************************** + * HELPER DATA STRUCTURES + **************************/ + +static const std::unordered_set logicalOps = { + "and", "bic", "bif", "bit", "bsl", "bcax", "bmop", + "eor", "eon", "mvn", "not", "nand", "nbsl", "nor", + "rax", "xar", "orr", "orq", "orv", "tst", "orn"}; + +static const std::unordered_set cmpOps = { + "ccmn", "cmn", "cmp", "cmpp", "cmpeq", "cmpge", "cmpgt", + "cmphi", "cmphs", "cmple", "cmplo", "cmpls", "cmplt", "cmpne", + "cmptst", "ccmp", "cmeq", "cmge", "cmgt", "cmtst", "cmhi", + "cmhs", "cmla", "cmle", "cmlt", "fac", "facge", "facgt", + "facle", "faclt", "fccmp", "fccmpe", "fcmp", "fcmpe", "fcmuo", + "fcmeq", "fcmge", "fcmgt", "fcmle", "fcmlt", "fcmne"}; + +static const std::unordered_set cvtOps = { + "bfcvt", "bfcvtn", "bfcvtnt", "bf1cvt", "bf1cvtl", "bf1cvtlt", + "bf2cvt", "bf2cvtl", "bf2cvtlt", "fcvt", "fcvtas", "fcvtau", + "fcvtl", "fcvtms", "fcvtmu", "fcvtn", "fcvtns", "fcvtnu", + "fcvtps", "fcvtpu", "fcvtxn", "fcvtzs", "fcvtzu", "fcvtlt", + "fcvtnb", "fcvtnt", "fcvtx", "fcvtxnt", "fcvtzs", "fcvtzu", + "f1cvt", "f1cvtl", "f1cvtlt", "f2cvt", "f2cvtl", "f2cvtlt", + "fjcvtzs", "scvtf", "ucvtf"}; + +static const std::unordered_set divsqrtOps = { + "sdiv", "sdivr", "udiv", "udivr", "fdiv", "fdivr", + "frsqrt", "frsqrte", "frsqrts", "fsqrt", "ursqrte"}; + +static const std::unordered_set mulOps = { + "bfmmla", "bfmul", "bfml", "bfmla", "bfmlalb", "bfmlalt", + "bfmlal", "bfmls", "bfmlslb", "bfmlslt", "bfmlsl", "cmla", + "dot", "bfdot", "bfvdot", "fdot", "fvdot", "fvdotb", + "fvdott", "sdot", "sudot", "suvdot", "udot", "usdot", + "usvdot", "uvdot", "cdot", "fmla", "fmlal", "fmlal2", + "fmlalb", "fmlalt", "fmlallbb", "fmlallbt", "fmlalltb", "fmlalltt", + "fmlall", "fmls", "fmlsl", "fmlsl2", "fmlslb", "fmlslt", + "fmul", "fmulx", "fmad", "fmadd", "fmmla", "fmsb", + "fmsub", "ftmad", "fcmla", "fnm", "fnmad", "fnmla", + "fnmls", "fnmsb", "fnmadd", "fnmsub", "fnmul", "madd", + "maddpt", "mul", "mla", "mlapt", "mls", "mneg", + "msub", "msubpt", "mad", "madpt", "msb", "mop", + "bfmopa", "bfmops", "bmopa", "bmops", "fmopa", "fmops", + "smopa", "smops", "sumopa", "sumops", "umopa", "umops", + "usmopa", "usmops", "pmul", "pmull", "pmull2", "pmullb", + "pmullt", "sml", "smlalb", "smlalt", "smlslb", "smlslt", + "smlal", "smlal2", "smlsl", "smlsl2", "smlall", "smlsll", + "smmla", "smul", "smulh", "smull", "smull2", "smullb", + "smullt", "sqdm", "sqdmlal", "sqdmlal2", "sqdmlsl", "sqdmlsl2", + "sqdmulh", "sqdmull", "sqdmull2", "sqdmlalb", "sqdmlalbt", "sqdmlalt", + "sqdmlslb", "sqdmlslbt", "sqdmlslt", "sqdmullb", "sqdmullt", "sqrd", + "sqrdmlah", "sqrdmlsh", "sqrdmulh", "sqrdcmlah", "sumlall", "smaddl", + "smnegl", "smsubl", "umul", "umulh", "umull", "umull2", + "umullb", "umullt", "uml", "umlal", "umlal2", "umlsl", + "umlsl2", "umlslt", "umlalb", "umlalt", "umlslb", "umlall", + "umlsll", "usmlall", "usmmla", "ummla", "umaddl", "umnegl", + "umsubl"}; + /******************** * HELPER FUNCTIONS *******************/ @@ -23,9 +84,6 @@ constexpr uint32_t bits(uint32_t value, uint8_t start, uint8_t width) { return ((value >> start) & ((1 << width) - 1)); } -// Generate a general purpose register identifier with tag `tag` -constexpr Register genReg(uint16_t tag) { return {RegisterType::GENERAL, tag}; } - // Generate a NZCV register identifier constexpr Register nzcvReg() { return {RegisterType::NZCV, 0}; } @@ -36,103 +94,116 @@ constexpr int32_t signExtend(uint32_t value, int currentLength) { return static_cast(value) | (negative ? mask : 0); } -/** Parses the Capstone `arm64_reg` value to generate an architectural register - * representation. +/** Parses the Capstone `aarch64_reg` value to generate an architectural + * register representation. * * WARNING: this conversion is FRAGILE, and relies on the structure of the - * `arm64_reg` enum. Updates to the Capstone library version may cause this to - * break. */ -Register csRegToRegister(arm64_reg reg) { - // Check from top of the range downwards + * `aarch64_reg` enum. Updates to the Capstone library version may cause this to + * break. + * */ +Register csRegToRegister(aarch64_reg reg) { + // Do not need check for AARCH64_REG_Vn as in Capstone, they are aliased as Qn + // (full vector) or Dn (half vector). + // As D and Q registers are also of type RegisterType::VECTOR, the outcome + // will be the same + + // Assert that reg is not a SME tile as these should be passed to + // `getZARowVectors()` + assert(reg != AARCH64_REG_ZA); + assert(!(AARCH64_REG_ZAB0 <= reg && reg <= AARCH64_REG_ZAS3)); + + // AARCH64_REG_ZT0 is a fixed with Table register, reading from the table + // register file. + if (reg == AARCH64_REG_ZT0) { + return {RegisterType::TABLE, 0}; + } + + // AARCH64_REG_Z0 -> +31 are scalable vector registers (Z) registers, reading + // from the vector file + if (AARCH64_REG_Z0 <= reg && reg <= AARCH64_REG_Z31) { + return {RegisterType::VECTOR, static_cast(reg - AARCH64_REG_Z0)}; + } - // ARM64_REG_V0 -> {end} are vector registers, reading from the vector file - if (reg >= ARM64_REG_V0) { - return {RegisterType::VECTOR, static_cast(reg - ARM64_REG_V0)}; + // AARCH64_REG_X0 -> +28 are 64-bit (X) registers, reading from the general + // file. Excludes #29 (FP) and #30 (LR) + if (AARCH64_REG_X0 <= reg && reg <= AARCH64_REG_X28) { + return {RegisterType::GENERAL, static_cast(reg - AARCH64_REG_X0)}; } - // ARM64_REG_ZAB0 -> +31 are tiles of the matrix register (ZA), reading from - // the matrix file. - if (reg >= ARM64_REG_ZAB0) { - // Placeholder value returned as each tile (what the enum represents) - // consists of multiple vectors (rows) - return {RegisterType::MATRIX, 0}; + // AARCH64_REG_W0 -> +30 are 32-bit (W) registers, reading from the general + // file. Excludes #31 (WZR/WSP). + if (AARCH64_REG_W0 <= reg && reg <= AARCH64_REG_W30) { + return {RegisterType::GENERAL, static_cast(reg - AARCH64_REG_W0)}; } - // ARM64_REG_Z0 -> +31 are scalable vector registers (Z) registers, reading - // from the vector file - if (reg >= ARM64_REG_Z0) { - return {RegisterType::VECTOR, static_cast(reg - ARM64_REG_Z0)}; + // AARCH64_REG_Q0 -> +31 are 128-bit registers representing scalar access + // specifiers on the vector registers + if (AARCH64_REG_Q0 <= reg && reg <= AARCH64_REG_Q31) { + return {RegisterType::VECTOR, static_cast(reg - AARCH64_REG_Q0)}; } - // ARM64_REG_X0 -> +28 are 64-bit (X) registers, reading from the general - // file. Excludes #29 (FP) and #30 (LR) - if (reg >= ARM64_REG_X0) { - return {RegisterType::GENERAL, static_cast(reg - ARM64_REG_X0)}; + // AARCH64_REG_D0 -> +31 are 64-bit registers representing scalar access + // specifiers on the vector registers + if (AARCH64_REG_D0 <= reg && reg <= AARCH64_REG_D31) { + return {RegisterType::VECTOR, static_cast(reg - AARCH64_REG_D0)}; } - // ARM64_REG_W0 -> +30 are 32-bit (W) registers, reading from the general - // file. Excludes #31 (WZR/WSP). - if (reg >= ARM64_REG_W0) { - return {RegisterType::GENERAL, static_cast(reg - ARM64_REG_W0)}; + // AARCH64_REG_S0 -> +31 are 32-bit registers representing scalar access + // specifiers on the vector registers + if (AARCH64_REG_S0 <= reg && reg <= AARCH64_REG_S31) { + return {RegisterType::VECTOR, static_cast(reg - AARCH64_REG_S0)}; } - // ARM64_REG_Q0 and above are repeated ranges representing scalar access - // specifiers on the vector registers with arrangements Q and S, each - // covering 32 registers - if (reg >= ARM64_REG_Q0) { - return {RegisterType::VECTOR, - static_cast((reg - ARM64_REG_Q0) % 32)}; + // AARCH64_REG_H0 -> +31 are 16-bit registers representing scalar access + // specifiers on the vector registers + if (AARCH64_REG_H0 <= reg && reg <= AARCH64_REG_H31) { + return {RegisterType::VECTOR, static_cast(reg - AARCH64_REG_H0)}; } - // ARM64_REG_P0 -> +15 are 256-bit (P) registers. Excludes #16 (FFR). - if (reg >= ARM64_REG_P0) { - return {RegisterType::PREDICATE, static_cast(reg - ARM64_REG_P0)}; + // AARCH64_REG_B0 -> +31 are 8-bit registers representing scalar access + // specifiers on the vector registers + if (AARCH64_REG_B0 <= reg && reg <= AARCH64_REG_B31) { + return {RegisterType::VECTOR, static_cast(reg - AARCH64_REG_B0)}; } - // ARM64_REG_Q0 and above are repeated ranges representing scalar access - // specifiers on the vector registers with arrangements B, D and H, each - // covering 32 registers - if (reg >= ARM64_REG_B0) { - return {RegisterType::VECTOR, - static_cast((reg - ARM64_REG_B0) % 32)}; + // AARCH64_REG_P0 -> +15 are 256-bit (P) "predicate-as-mask" registers. + // Excludes #16 (FFR). + // AARCH64_REG_PN0 -> +15 are 256-bit (PN) "predicate-as-counter" registers. + // Occupy same registers as (P) predicates but use a different encoding. + if (AARCH64_REG_P0 <= reg && reg <= AARCH64_REG_PN15) { + return {RegisterType::PREDICATE, + static_cast(static_cast(reg - AARCH64_REG_P0) % + 16u)}; } - // ARM64_REG_WZR and _XZR are zero registers, and don't read - if (reg == ARM64_REG_WZR || reg == ARM64_REG_XZR) { + // AARCH64_REG_WZR and _XZR are zero registers, and don't read + if (reg == AARCH64_REG_WZR || reg == AARCH64_REG_XZR) { return RegisterType::ZERO_REGISTER; } - // ARM64_REG_SP and _WSP are stack pointer registers, stored in r31 of the + // AARCH64_REG_SP and _WSP are stack pointer registers, stored in r31 of the // general file - if (reg == ARM64_REG_SP || reg == ARM64_REG_WSP) { + if (reg == AARCH64_REG_SP || reg == AARCH64_REG_WSP) { return {RegisterType::GENERAL, 31}; } - // ARM64_REG_NZCV is the condition flags register - if (reg == ARM64_REG_NZCV) { + // AARCH64_REG_NZCV is the condition flags register + if (reg == AARCH64_REG_NZCV) { return {RegisterType::NZCV, 0}; } - // ARM64_REG_X29 is the frame pointer, stored in r29 of the general file - if (reg == ARM64_REG_X29) { + // AARCH64_REG_X29 is the frame pointer, stored in r29 of the general file + if (reg == AARCH64_REG_X29) { return {RegisterType::GENERAL, 29}; } - // ARM64_REG_X30 is the link register, stored in r30 of the general file - if (reg == ARM64_REG_X30) { + // AARCH64_REG_X30 is the link register, stored in r30 of the general file + if (reg == AARCH64_REG_X30) { return {RegisterType::GENERAL, 30}; } - if (reg == ARM64_REG_FFR) { + if (reg == AARCH64_REG_FFR) { return {RegisterType::PREDICATE, 16}; } - // The matrix register (ZA) can also be referenced as a whole in some - // instructions. - if (reg == ARM64_REG_ZA) { - // Placeholder value returned as each tile (what the enum represents) - // consists of multiple vectors (rows) - return {RegisterType::MATRIX, 0}; - } - assert(false && "Decoding failed due to unknown register identifier"); return {std::numeric_limits::max(), std::numeric_limits::max()}; @@ -140,29 +211,30 @@ Register csRegToRegister(arm64_reg reg) { /** Returns a full set of rows from the ZA matrix register that make up the * supplied SME tile register. */ -std::vector getZARowVectors(arm64_reg reg, const uint64_t SVL_bits) { +std::vector getZARowVectors(aarch64_reg reg, + const uint64_t SVL_bits) { std::vector outRegs; // Get SVL in bytes (will equal total number of implemented ZA rows) uint64_t SVL = SVL_bits / 8; uint8_t base = 0; uint8_t tileTypeCount = 0; - if (reg == ARM64_REG_ZA || reg == ARM64_REG_ZAB0) { + if (reg == AARCH64_REG_ZA || reg == AARCH64_REG_ZAB0) { // Treat ZA as byte tile : ZAB0 represents whole matrix, only 1 tile // Add all rows for this SVL // Don't need to set base as will always be 0 tileTypeCount = 1; - } else if (reg >= ARM64_REG_ZAH0 && reg <= ARM64_REG_ZAH1) { - base = reg - ARM64_REG_ZAH0; + } else if (reg >= AARCH64_REG_ZAH0 && reg <= AARCH64_REG_ZAH1) { + base = reg - AARCH64_REG_ZAH0; tileTypeCount = 2; - } else if (reg >= ARM64_REG_ZAS0 && reg <= ARM64_REG_ZAS3) { - base = reg - ARM64_REG_ZAS0; + } else if (reg >= AARCH64_REG_ZAS0 && reg <= AARCH64_REG_ZAS3) { + base = reg - AARCH64_REG_ZAS0; tileTypeCount = 4; - } else if (reg >= ARM64_REG_ZAD0 && reg <= ARM64_REG_ZAD7) { - base = reg - ARM64_REG_ZAD0; + } else if (reg >= AARCH64_REG_ZAD0 && reg <= AARCH64_REG_ZAD7) { + base = reg - AARCH64_REG_ZAD0; tileTypeCount = 8; - } else if (reg >= ARM64_REG_ZAQ0 && reg <= ARM64_REG_ZAQ15) { - base = reg - ARM64_REG_ZAQ0; + } else if (reg >= AARCH64_REG_ZAQ0 && reg <= AARCH64_REG_ZAQ15) { + base = reg - AARCH64_REG_ZAQ0; tileTypeCount = 16; } @@ -182,22 +254,28 @@ std::vector getZARowVectors(arm64_reg reg, const uint64_t SVL_bits) { * DECODING LOGIC *****************/ void Instruction::decode() { - if (metadata_.id == ARM64_INS_INVALID) { + if (metadata_.id == AARCH64_INS_INVALID) { exception_ = InstructionException::EncodingUnallocated; exceptionEncountered_ = true; return; } - // Extract implicit writes + // Extract implicit writes, including pre/post index writeback for (size_t i = 0; i < metadata_.implicitDestinationCount; i++) { destinationRegisters_[destinationRegisterCount_] = csRegToRegister( - static_cast(metadata_.implicitDestinations[i])); + static_cast(metadata_.implicitDestinations[i])); destinationRegisterCount_++; } + // Extract implicit reads for (size_t i = 0; i < metadata_.implicitSourceCount; i++) { + // TODO: Implement FPCR usage properly + // Ignore implicit reading of FPCR + if (static_cast(metadata_.implicitSources[i]) == + AARCH64_REG_FPCR) + continue; sourceRegisters_[sourceOperandsPending_] = - csRegToRegister(static_cast(metadata_.implicitSources[i])); + csRegToRegister(static_cast(metadata_.implicitSources[i])); sourceRegisterCount_++; sourceOperandsPending_++; } @@ -208,186 +286,145 @@ void Instruction::decode() { for (size_t i = 0; i < metadata_.operandCount; i++) { const auto& op = metadata_.operands[i]; - if (op.type == ARM64_OP_REG) { // Register operand + if (op.type == AARCH64_OP_REG) { // Register operand if ((op.access & cs_ac_type::CS_AC_WRITE)) { - if (op.reg != ARM64_REG_WZR && op.reg != ARM64_REG_XZR) { + if (op.reg != AARCH64_REG_WZR && op.reg != AARCH64_REG_XZR) { // Determine the data type the instruction operates on based on the // register operand used - // Belongs to the predicate group if the destination register is a - // predicate - if (op.reg >= ARM64_REG_V0) { + // SME and Predicate based operations use individual op.type + if (op.is_vreg) { setInstructionType(InsnType::isVectorData); - } else if (op.reg >= ARM64_REG_ZAB0 || op.reg == ARM64_REG_ZA) { - setInstructionType(InsnType::isSMEData); - } else if (op.reg >= ARM64_REG_Z0) { + } else if ((AARCH64_REG_Z0 <= op.reg && op.reg <= AARCH64_REG_Z31) || + op.reg == AARCH64_REG_ZT0) { + // ZT0 is an SME register, but we declare it as an SVE instruction + // due to its 1D format. setInstructionType(InsnType::isSVEData); - } else if (op.reg <= ARM64_REG_S31 && op.reg >= ARM64_REG_Q0) { - setInstructionType(InsnType::isScalarData); - } else if (op.reg <= ARM64_REG_P15 && op.reg >= ARM64_REG_P0) { - setInstructionType(InsnType::isPredicate); - } else if (op.reg <= ARM64_REG_H31 && op.reg >= ARM64_REG_B0) { + } else if ((op.reg <= AARCH64_REG_S31 && op.reg >= AARCH64_REG_Q0) || + (op.reg <= AARCH64_REG_H31 && op.reg >= AARCH64_REG_B0)) { setInstructionType(InsnType::isScalarData); } - if ((op.reg >= ARM64_REG_ZAB0 && op.reg < ARM64_REG_V0) || - (op.reg == ARM64_REG_ZA)) { - // Add all Matrix register rows as destination operands - std::vector regs = getZARowVectors( - op.reg, architecture_.getStreamingVectorLength()); - // Update operand structure sizes - sourceRegisters_.addSMEOperand(regs.size()); - destinationRegisters_.addSMEOperand(regs.size()); - sourceValues_.addSMEOperand(regs.size()); - results_.addSMEOperand(regs.size()); - for (size_t i = 0; i < regs.size(); i++) { - destinationRegisters_[destinationRegisterCount_] = regs[i]; - destinationRegisterCount_++; - // If WRITE, also need to add to source registers to maintain - // unaltered row values - sourceRegisters_[sourceRegisterCount_] = regs[i]; - sourceRegisterCount_++; - sourceOperandsPending_++; - } - } else { - // Add register writes to destinations, but skip zero-register - // destinations - destinationRegisters_[destinationRegisterCount_] = - csRegToRegister(op.reg); - destinationRegisterCount_++; - } + // Add register writes to destinations, but skip zero-register + // destinations + destinationRegisters_[destinationRegisterCount_] = + csRegToRegister(op.reg); + destinationRegisterCount_++; } } if (op.access & cs_ac_type::CS_AC_READ) { - if ((op.reg >= ARM64_REG_ZAB0 && op.reg < ARM64_REG_V0) || - (op.reg == ARM64_REG_ZA)) { - // Add all Matrix register rows as source operands - std::vector regs = - getZARowVectors(op.reg, architecture_.getStreamingVectorLength()); - // Update source operand structure sizes - sourceRegisters_.addSMEOperand(regs.size()); - sourceValues_.addSMEOperand(regs.size()); - for (size_t i = 0; i < regs.size(); i++) { - sourceRegisters_[sourceRegisterCount_] = regs[i]; - sourceRegisterCount_++; - sourceOperandsPending_++; - } - } else { - // Add register reads to destinations - sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.reg); - sourceRegisterCount_++; - sourceOperandsPending_++; - } - // TODO checking of the shift type is a temporary fix to help reduce the - // chance of incorrectly reverted aliases from being mis-classified as - // isShift when op.shift contains garbage data. This should be reviewed - // on the next capstone update which should remove the need to revert - // aliasing - if (op.shift.type > arm64_shifter::ARM64_SFT_INVALID && - op.shift.type <= arm64_shifter::ARM64_SFT_ROR && + // Add register reads to destinations + sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.reg); + sourceRegisterCount_++; + sourceOperandsPending_++; + + // Identify shift operands + if (op.shift.type != aarch64_shifter::AARCH64_SFT_INVALID && op.shift.value > 0) { - setInstructionType(InsnType::isShift); // Identify shift operands + setInstructionType(InsnType::isShift); } } - } else if (op.type == ARM64_OP_MEM) { // Memory operand - accessesMemory = true; - sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.mem.base); - sourceRegisterCount_++; - sourceOperandsPending_++; - - if (metadata_.writeback) { - // Writeback instructions modify the base address - destinationRegisters_[destinationRegisterCount_] = - csRegToRegister(op.mem.base); - destinationRegisterCount_++; - } - if (op.mem.index) { - // Register offset; add to sources - sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.mem.index); + } else if (op.type == AARCH64_OP_MEM) { // Memory operand + // Check base register exists + if (op.mem.base != AARCH64_REG_INVALID) { + accessesMemory = true; + sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.mem.base); sourceRegisterCount_++; sourceOperandsPending_++; } - } else if (op.type == ARM64_OP_SME_INDEX) { // SME instruction with index - std::vector regs; - if ((op.sme_index.reg >= ARM64_REG_ZAB0 && - op.sme_index.reg < ARM64_REG_V0) || - (op.sme_index.reg == ARM64_REG_ZA)) { - // Set instruction group - setInstructionType(InsnType::isSMEData); - regs = getZARowVectors(op.sme_index.reg, - architecture_.getStreamingVectorLength()); - // Update operands structure sizes - destinationRegisters_.addSMEOperand(regs.size()); - results_.addSMEOperand(regs.size()); - sourceRegisters_.addSMEOperand(regs.size()); - sourceValues_.addSMEOperand(regs.size()); - for (size_t i = 0; i < regs.size(); i++) { - // If READ access, we only need to add SME rows to source registers. - // If WRITE access, then we need to add SME rows to destination - // registers AND source registers. The latter is required to maintain - // any un-updated rows given that an SME_INDEX op will specify only - // one row (or column) to write to. - sourceRegisters_[sourceRegisterCount_] = regs[i]; - sourceRegisterCount_++; + if (op.mem.index != AARCH64_REG_INVALID) { + // Register offset; add to sources + sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.mem.index); + // Early check for WZR/XZR registers used as scalar index. Allows SME + // instructions to avoid checking all source operands later on. + if (sourceRegisters_[sourceRegisterCount_] == + RegisterType::ZERO_REGISTER) { + sourceValues_[sourceRegisterCount_] = RegisterValue(0, 8); + } else { sourceOperandsPending_++; - if (op.access & cs_ac_type::CS_AC_WRITE) { - destinationRegisters_[destinationRegisterCount_] = regs[i]; - destinationRegisterCount_++; - } } - } else { - // SME_INDEX can also be for predicate - // Set instruction group - setInstructionType(InsnType::isPredicate); + sourceRegisterCount_++; + } + } else if (op.type == AARCH64_OP_SME) { + setInstructionType(InsnType::isSMEData); + std::vector regs = getZARowVectors( + op.sme.tile, architecture_.getStreamingVectorLength()); + // Update operands structure sizes + destinationRegisters_.addSMEOperand(regs.size()); + results_.addSMEOperand(regs.size()); + sourceRegisters_.addSMEOperand(regs.size()); + sourceValues_.addSMEOperand(regs.size()); + for (size_t i = 0; i < regs.size(); i++) { + // If READ access, we only need to add SME rows to source registers. + // If WRITE access, then we need to add SME rows to destination + // registers AND source registers. The latter is required to maintain + // any un-updated rows if an SME op will specifies + // one row (or column) to write to. + sourceRegisters_[sourceRegisterCount_] = regs[i]; + sourceRegisterCount_++; + sourceOperandsPending_++; if (op.access & cs_ac_type::CS_AC_WRITE) { - destinationRegisters_[destinationRegisterCount_] = - csRegToRegister(op.sme_index.reg); + destinationRegisters_[destinationRegisterCount_] = regs[i]; destinationRegisterCount_++; - } else if (op.access & cs_ac_type::CS_AC_READ) { - sourceRegisters_[sourceRegisterCount_] = - csRegToRegister(op.sme_index.reg); - sourceRegisterCount_++; - sourceOperandsPending_++; } } - // Register that is base of index will always be a source operand - sourceRegisters_[sourceRegisterCount_] = - csRegToRegister(op.sme_index.base); - sourceRegisterCount_++; - sourceOperandsPending_++; - } else if (op.type == ARM64_OP_REG_MRS) { - int32_t sysRegTag = architecture_.getSystemRegisterTag(op.imm); + if (op.sme.type == AARCH64_SME_OP_TILE_VEC) { + // SME tile has slice determined by register and immidiate. + // Add base register to source operands + sourceRegisters_[sourceRegisterCount_] = + csRegToRegister(op.sme.slice_reg); + sourceRegisterCount_++; + sourceOperandsPending_++; + } + } else if (op.type == AARCH64_OP_PRED) { + if (i == 0) setInstructionType(InsnType::isPredicate); + if (op.access == CS_AC_READ) { + sourceRegisters_[sourceRegisterCount_] = csRegToRegister(op.pred.reg); + sourceRegisterCount_++; + sourceOperandsPending_++; + } + if (op.access == CS_AC_WRITE) { + destinationRegisters_[destinationRegisterCount_] = + csRegToRegister(op.pred.reg); + destinationRegisterCount_++; + } + if (op.pred.vec_select != AARCH64_REG_INVALID) { + sourceRegisters_[sourceRegisterCount_] = + csRegToRegister(op.pred.vec_select); + sourceRegisterCount_++; + sourceOperandsPending_++; + } + } else if (op.type == AARCH64_OP_SYSREG) { + int32_t sysRegTag = + architecture_.getSystemRegisterTag(op.sysop.reg.sysreg); + // Check SYSREG is supported if (sysRegTag == -1) { exceptionEncountered_ = true; exception_ = InstructionException::UnmappedSysReg; return; - } else { + } + if (op.sysop.sub_type == AARCH64_OP_REG_MRS) { sourceRegisters_[sourceRegisterCount_] = { RegisterType::SYSTEM, static_cast(sysRegTag)}; sourceRegisterCount_++; sourceOperandsPending_++; - } - } else if (op.type == ARM64_OP_REG_MSR) { - int32_t sysRegTag = architecture_.getSystemRegisterTag(op.imm); - if (sysRegTag == -1) { - exceptionEncountered_ = true; - exception_ = InstructionException::UnmappedSysReg; - return; - } else { + } else if (op.sysop.sub_type == AARCH64_OP_REG_MSR) { destinationRegisters_[destinationRegisterCount_] = { RegisterType::SYSTEM, static_cast(sysRegTag)}; destinationRegisterCount_++; } - } else if (op.type == ARM64_OP_SVCR) { - // Updating of SVCR is done via an exception and not via the sysreg file. - // No operands are required for this operation. - // Any access to SVCR other than SMSTART and SMSTOP (i.e. this OP_TYPE) - // will result in an `unmapped system register` exception. + } else if (metadata_.operands[0].type == AARCH64_OP_SYSALIAS && + metadata_.operands[0].sysop.sub_type == AARCH64_OP_SVCR) { + // This case is for instruction alias SMSTART and SMSTOP. Updating of SVCR + // value is done via an exception so no registers required. } } // Identify branches for (size_t i = 0; i < metadata_.groupCount; i++) { - if (metadata_.groups[i] == ARM64_GRP_JUMP) { + if (metadata_.groups[i] == AARCH64_GRP_JUMP || + metadata_.groups[i] == AARCH64_GRP_CALL || + metadata_.groups[i] == AARCH64_GRP_RET || + metadata_.groups[i] == AARCH64_GRP_BRANCH_RELATIVE) { setInstructionType(InsnType::isBranch); } } @@ -447,10 +484,9 @@ void Instruction::decode() { knownOffset_ = metadata_.operands[2].imm; break; } - case Opcode::AArch64_RET: { // ret {xr} + case Opcode::AArch64_RET: // ret {xt} branchType_ = BranchType::Return; break; - } default: break; } @@ -463,7 +499,8 @@ void Instruction::decode() { // Check first operand access to determine if it's a load or store if (metadata_.operands[0].access & CS_AC_WRITE) { - if (metadata_.id == ARM64_INS_STXR || metadata_.id == ARM64_INS_STLXR) { + if (metadata_.id == AARCH64_INS_STXR || + metadata_.id == AARCH64_INS_STLXR) { // Exceptions to this is load condition are exclusive store with a // success flag as first operand if (microOpcode_ != MicroOpcode::STR_DATA) { @@ -485,33 +522,34 @@ void Instruction::decode() { } // LDADD* are considered to be both a load and a store - if (metadata_.id >= ARM64_INS_LDADD && metadata_.id <= ARM64_INS_LDADDLH) { + if (Opcode::AArch64_LDADDAB <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_LDADDX) { setInstructionType(InsnType::isLoad); setInstructionType(InsnType::isStoreData); } // CASAL* are considered to be both a load and a store - if (metadata_.opcode == Opcode::AArch64_CASALW || - metadata_.opcode == Opcode::AArch64_CASALX) { + if (Opcode::AArch64_CASALB <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_CASALX) { setInstructionType(InsnType::isLoad); setInstructionType(InsnType::isStoreData); } if (isInstruction(InsnType::isStoreData)) { // Identify store instruction group - if (ARM64_REG_Z0 <= metadata_.operands[0].reg && - metadata_.operands[0].reg <= ARM64_REG_Z31) { + if (AARCH64_REG_Z0 <= metadata_.operands[0].reg && + metadata_.operands[0].reg <= AARCH64_REG_Z31) { setInstructionType(InsnType::isSVEData); - } else if ((metadata_.operands[0].reg <= ARM64_REG_S31 && - metadata_.operands[0].reg >= ARM64_REG_Q0) || - (metadata_.operands[0].reg <= ARM64_REG_H31 && - metadata_.operands[0].reg >= ARM64_REG_B0)) { + } else if ((metadata_.operands[0].reg <= AARCH64_REG_S31 && + metadata_.operands[0].reg >= AARCH64_REG_Q0) || + (metadata_.operands[0].reg <= AARCH64_REG_H31 && + metadata_.operands[0].reg >= AARCH64_REG_B0)) { setInstructionType(InsnType::isScalarData); - } else if (metadata_.operands[0].reg >= ARM64_REG_V0) { + } else if (metadata_.operands[0].is_vreg) { setInstructionType(InsnType::isVectorData); - } else if ((metadata_.operands[0].reg >= ARM64_REG_ZAB0 && - metadata_.operands[0].reg < ARM64_REG_V0) || - metadata_.operands[0].reg == ARM64_REG_ZA) { + } else if ((metadata_.operands[0].reg >= AARCH64_REG_ZAB0 && + metadata_.operands[0].reg <= AARCH64_REG_ZT0) || + metadata_.operands[0].reg == AARCH64_REG_ZA) { setInstructionType(InsnType::isSMEData); } } @@ -521,28 +559,18 @@ void Instruction::decode() { } if (metadata_.opcode == Opcode::AArch64_LDRXl || metadata_.opcode == Opcode::AArch64_LDRSWl) { - // Literal loads aren't flagged as having a memory operand, so these must be - // marked as loads manually + // Literal loads aren't flagged as having a memory operand, so these must + // be marked as loads manually setInstructionType(InsnType::isLoad); } - if ((264 <= metadata_.opcode && metadata_.opcode <= 267) || // AND - (1063 <= metadata_.opcode && metadata_.opcode <= 1084) || // AND (pt.2) - (284 <= metadata_.opcode && metadata_.opcode <= 287) || // BIC - (1167 <= metadata_.opcode && metadata_.opcode <= 1183) || // BIC (pt.2) - (321 <= metadata_.opcode && metadata_.opcode <= 324) || // EOR/EON - (1707 <= metadata_.opcode && - metadata_.opcode <= 1736) || // EOR/EON (pt.2) - (771 <= metadata_.opcode && metadata_.opcode <= 774) || // ORR/ORN - (3748 <= metadata_.opcode && - metadata_.opcode <= 3771)) { // ORR/ORN (pt.2) + // Identify Logical (bitwise) instructions + if (logicalOps.find(metadata_.mnemonic) != logicalOps.end()) { setInstructionType(InsnType::isLogical); } - if ((1252 <= metadata_.opcode && metadata_.opcode <= 1259) || - (1314 <= metadata_.opcode && metadata_.opcode <= 1501) || - (1778 <= metadata_.opcode && metadata_.opcode <= 1799) || - (1842 <= metadata_.opcode && metadata_.opcode <= 1969)) { + // Identify comparison insturctions (excluding atomic LD-CMP-STR) + if (cmpOps.find(metadata_.mnemonic) != cmpOps.end()) { setInstructionType(InsnType::isCompare); // Capture those floating point compare instructions with no destination // register @@ -555,14 +583,8 @@ void Instruction::decode() { } } - if ((347 <= metadata_.opcode && metadata_.opcode <= 366) || - (1142 <= metadata_.opcode && metadata_.opcode <= 1146) || - (1976 <= metadata_.opcode && metadata_.opcode <= 2186) || - (metadata_.opcode == 2207) || - (782 <= metadata_.opcode && metadata_.opcode <= 788) || - (4063 <= metadata_.opcode && metadata_.opcode <= 4097) || - (898 <= metadata_.opcode && metadata_.opcode <= 904) || - (5608 <= metadata_.opcode && metadata_.opcode <= 5642)) { + // Identify convert instructions + if (cvtOps.find(metadata_.mnemonic) != cvtOps.end()) { setInstructionType(InsnType::isConvert); // Capture those floating point convert instructions whose destination // register is general purpose @@ -574,83 +596,12 @@ void Instruction::decode() { } // Identify divide or square root operations - if ((367 <= metadata_.opcode && metadata_.opcode <= 375) || - (789 <= metadata_.opcode && metadata_.opcode <= 790) || - (905 <= metadata_.opcode && metadata_.opcode <= 906) || - (2187 <= metadata_.opcode && metadata_.opcode <= 2200) || - (4098 <= metadata_.opcode && metadata_.opcode <= 4103) || - (5644 <= metadata_.opcode && metadata_.opcode <= 5649) || - (481 <= metadata_.opcode && metadata_.opcode <= 483) || - (metadata_.opcode == 940) || - (2640 <= metadata_.opcode && metadata_.opcode <= 2661) || - (2665 <= metadata_.opcode && metadata_.opcode <= 2675) || - (6066 <= metadata_.opcode && metadata_.opcode <= 6068)) { + if (divsqrtOps.find(metadata_.mnemonic) != divsqrtOps.end()) { setInstructionType(InsnType::isDivideOrSqrt); } // Identify multiply operations - if ((433 <= metadata_.opcode && - metadata_.opcode <= 447) || // all MUL variants - (759 <= metadata_.opcode && metadata_.opcode <= 762) || - (816 <= metadata_.opcode && metadata_.opcode <= 819) || - (915 <= metadata_.opcode && metadata_.opcode <= 918) || - (2436 <= metadata_.opcode && metadata_.opcode <= 2482) || - (2512 <= metadata_.opcode && metadata_.opcode <= 2514) || - (2702 <= metadata_.opcode && metadata_.opcode <= 2704) || - (3692 <= metadata_.opcode && metadata_.opcode <= 3716) || - (3793 <= metadata_.opcode && metadata_.opcode <= 3805) || - (4352 <= metadata_.opcode && metadata_.opcode <= 4380) || - (4503 <= metadata_.opcode && metadata_.opcode <= 4543) || - (4625 <= metadata_.opcode && metadata_.opcode <= 4643) || - (5804 <= metadata_.opcode && metadata_.opcode <= 5832) || - (2211 <= metadata_.opcode && - metadata_.opcode <= 2216) || // all MADD/MAD variants - (2494 <= metadata_.opcode && metadata_.opcode <= 2499) || - (2699 <= metadata_.opcode && metadata_.opcode <= 2701) || - (3610 <= metadata_.opcode && metadata_.opcode <= 3615) || - (4227 == metadata_.opcode) || (5682 == metadata_.opcode) || - (2433 <= metadata_.opcode && - metadata_.opcode <= 2435) || // all MSUB variants - (2509 <= metadata_.opcode && metadata_.opcode <= 2511) || - (3690 <= metadata_.opcode && metadata_.opcode <= 3691) || - (4351 == metadata_.opcode) || (5803 == metadata_.opcode) || - (424 <= metadata_.opcode && - metadata_.opcode <= 426) || // all MLA variants - (451 <= metadata_.opcode && metadata_.opcode <= 453) || - (1151 <= metadata_.opcode && metadata_.opcode <= 1160) || - (1378 <= metadata_.opcode && metadata_.opcode <= 1383) || - (1914 <= metadata_.opcode && metadata_.opcode <= 1926) || - (2341 <= metadata_.opcode && metadata_.opcode <= 2371) || - (2403 <= metadata_.opcode && metadata_.opcode <= 2404) || - (2500 <= metadata_.opcode && metadata_.opcode <= 2502) || - (3618 <= metadata_.opcode && metadata_.opcode <= 3634) || - (4295 <= metadata_.opcode && metadata_.opcode <= 4314) || - (4335 <= metadata_.opcode && metadata_.opcode <= 4336) || - (4453 <= metadata_.opcode && metadata_.opcode <= 4477) || - (4581 <= metadata_.opcode && metadata_.opcode <= 4605) || - (5749 <= metadata_.opcode && metadata_.opcode <= 5768) || - (5789 <= metadata_.opcode && metadata_.opcode <= 5790) || - (6115 <= metadata_.opcode && metadata_.opcode <= 6116) || - (427 <= metadata_.opcode && - metadata_.opcode <= 429) || // all MLS variants - (454 <= metadata_.opcode && metadata_.opcode <= 456) || - (2372 <= metadata_.opcode && metadata_.opcode <= 2402) || - (2503 <= metadata_.opcode && metadata_.opcode <= 2505) || - (3635 <= metadata_.opcode && metadata_.opcode <= 3651) || - (4315 <= metadata_.opcode && metadata_.opcode <= 4334) || - (4478 <= metadata_.opcode && metadata_.opcode <= 4502) || - (4606 <= metadata_.opcode && metadata_.opcode <= 4624) || - (5769 <= metadata_.opcode && metadata_.opcode <= 5788) || - (2430 <= metadata_.opcode && - metadata_.opcode <= 2432) || // all MSB variants - (2506 <= metadata_.opcode && metadata_.opcode <= 2508) || - (3682 <= metadata_.opcode && metadata_.opcode <= 3685) || - (2405 <= metadata_.opcode && - metadata_.opcode <= 2408) || // all SME FMOPS & FMOPA variants - (4337 <= metadata_.opcode && metadata_.opcode <= 4340) || - (5391 <= metadata_.opcode && metadata_.opcode <= 5394) || - (5791 <= metadata_.opcode && metadata_.opcode <= 5794) || - (6117 <= metadata_.opcode && metadata_.opcode <= 6120)) { + if (mulOps.find(metadata_.mnemonic) != mulOps.end()) { setInstructionType(InsnType::isMultiply); } @@ -660,19 +611,24 @@ void Instruction::decode() { setInstructionType(InsnType::isPredicate); } // Uncaught float data assignment for FMOV move to general instructions - if (((430 <= metadata_.opcode && metadata_.opcode <= 432) || - (2409 <= metadata_.opcode && metadata_.opcode <= 2429)) && + if (((Opcode::AArch64_FMOVD0 <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_FMOVS0) || + (Opcode::AArch64_FMOVDXHighr <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_FMOVXHr)) && !(isInstruction(InsnType::isScalarData) || isInstruction(InsnType::isVectorData))) { setInstructionType(InsnType::isScalarData); } // Uncaught vector data assignment for SMOV and UMOV instructions - if ((4341 <= metadata_.opcode && metadata_.opcode <= 4350) || - (5795 <= metadata_.opcode && metadata_.opcode <= 5802)) { + if ((Opcode::AArch64_SMOVvi16to32 <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_SMOVvi8to64_idx0) || + (Opcode::AArch64_UMOVvi16 <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_UMOVvi8_idx0)) { setInstructionType(InsnType::isVectorData); } // Uncaught float data assignment for FCVT convert to general instructions - if ((1976 <= metadata_.opcode && metadata_.opcode <= 2186) && + if ((Opcode::AArch64_FCVTASUWDr <= metadata_.opcode && + metadata_.opcode <= Opcode::AArch64_FCVT_ZPmZ_StoH) && !(isInstruction(InsnType::isScalarData) || isInstruction(InsnType::isVectorData))) { setInstructionType(InsnType::isScalarData); @@ -688,8 +644,8 @@ void Instruction::decode() { } } } else { - // For SME instructions, resize the following structures to have the exact - // amount of space required + // For SME instructions, resize the following structures to have the + // exact amount of space required sourceRegisters_.resize(sourceRegisterCount_); destinationRegisters_.resize(destinationRegisterCount_); sourceValues_.resize(sourceRegisterCount_); diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 6da1864eaf..20b62904b9 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -1239,7 +1239,8 @@ void Instruction::execute() { const uint64_t* pg = sourceValues_[1].getAsVector(); const uint64_t sliceNum = (sourceValues_[2 + rowCount].get() + - static_cast(metadata_.operands[2].sme_index.disp)) % + static_cast( + metadata_.operands[2].sme.slice_offset.imm)) % rowCount; const uint8_t* zanRow = sourceValues_[2 + sliceNum].getAsVector(); @@ -2568,7 +2569,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint16_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint64_t* data = memoryData_[0].getAsVector(); uint64_t out[32] = {0}; @@ -2604,7 +2605,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint64_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { @@ -2632,7 +2633,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint32_t* data = memoryData_[0].getAsVector(); uint32_t out[64] = {0}; @@ -2668,7 +2669,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint32_t* data = memoryData_[0].getAsVector(); for (int i = 0; i < partition_num; i++) { @@ -2703,8 +2704,8 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_LD1B_IMM_REAL: { // ld1b {zt.b}, pg/z, [xn{, #imm, - // mul vl}] + case Opcode::AArch64_LD1B_IMM: { // ld1b {zt.b}, pg/z, [xn{, #imm, + // mul vl}] // LOAD const uint64_t* p = sourceValues_[0].getAsVector(); @@ -2741,8 +2742,8 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_LD1D_IMM_REAL: { // ld1d {zt.d}, pg/z, [xn{, #imm, - // mul vl}] + case Opcode::AArch64_LD1D_IMM: { // ld1d {zt.d}, pg/z, [xn{, #imm, + // mul vl}] // LOAD const uint64_t* p = sourceValues_[0].getAsVector(); @@ -2785,13 +2786,13 @@ void Instruction::execute() { break; } case Opcode::AArch64_LD1Onev16b_POST: { // ld1 {vt.16b}, [xn], <#imm|xm> - results_[0] = memoryData_[0].zeroExtend(memoryData_[0].size(), 256); - // if #imm post-index, value can only be 16 - const uint64_t postIndex = (metadata_.operands[2].type == ARM64_OP_REG) - ? sourceValues_[1].get() - : 16; - results_[1] = sourceValues_[0].get() + postIndex; + const uint64_t postIndex = + (metadata_.operands[2].type == AARCH64_OP_REG) + ? sourceValues_[1].get() + : 16; + results_[0] = sourceValues_[0].get() + postIndex; + results_[1] = memoryData_[0].zeroExtend(memoryData_[0].size(), 256); break; } case Opcode::AArch64_LD1RD_IMM: { // ld1rd {zt.d}, pg/z, [xn, #imm] @@ -2934,9 +2935,9 @@ void Instruction::execute() { uint8_t val = memoryData_[0].get(); uint8_t out[16] = {val, val, val, val, val, val, val, val, val, val, val, val, val, val, val, val}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv1d: { // ld1r {vt.1d}, [xn] @@ -2950,9 +2951,9 @@ void Instruction::execute() { // LOAD uint64_t val = memoryData_[0].get(); uint64_t out[2] = {val, 0}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv2d: { // ld1r {vt.2d}, [xn] @@ -2966,9 +2967,9 @@ void Instruction::execute() { // LOAD uint64_t val = memoryData_[0].get(); uint64_t out[2] = {val, val}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv2s: { // ld1r {vt.2s}, [xn] @@ -2982,9 +2983,9 @@ void Instruction::execute() { // LOAD uint32_t val = memoryData_[0].get(); uint32_t out[4] = {val, val, 0, 0}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv4h: { // ld1r {vt.4h}, [xn] @@ -2998,9 +2999,9 @@ void Instruction::execute() { // LOAD uint16_t val = memoryData_[0].get(); uint16_t out[8] = {val, val, val, val, 0, 0, 0, 0}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv4s: { // ld1r {vt.4s}, [xn] @@ -3014,9 +3015,9 @@ void Instruction::execute() { // LOAD uint32_t val = memoryData_[0].get(); uint32_t out[4] = {val, val, val, val}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv8b: { // ld1r {vt.8b}, [xn] @@ -3032,9 +3033,9 @@ void Instruction::execute() { uint8_t val = memoryData_[0].get(); uint8_t out[16] = {val, val, val, val, val, val, val, val, 0, 0, 0, 0, 0, 0, 0, 0}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Rv8h: { // ld1r {vt.8h}, [xn] @@ -3048,9 +3049,9 @@ void Instruction::execute() { // LOAD uint16_t val = memoryData_[0].get(); uint16_t out[8] = {val, val, val, val, val, val, val, val}; - results_[0] = {out, 256}; - results_[1] = - sourceValues_[0].get() + metadata_.operands[2].imm; + results_[0] = + sourceValues_[0].get() + metadata_.operands[1].mem.disp; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD1Fourv16b: // ld1 {vt1.16b, vt2.16b, vt3.16b, @@ -3077,15 +3078,16 @@ void Instruction::execute() { case Opcode::AArch64_LD1Fourv4s_POST: { // ld1 {vt1.4s, vt2.4s, vt3.4s, // vt4.4s}, [xn], <#imm|xm> // LOAD - results_[0] = memoryData_[0].zeroExtend(memoryData_[0].size(), 256); - results_[1] = memoryData_[1].zeroExtend(memoryData_[1].size(), 256); - results_[2] = memoryData_[2].zeroExtend(memoryData_[2].size(), 256); - results_[3] = memoryData_[3].zeroExtend(memoryData_[3].size(), 256); // if #imm post-index, value can only be 64 - const uint64_t postIndex = (metadata_.operands[5].type == ARM64_OP_REG) - ? sourceValues_[1].get() - : 64; - results_[4] = sourceValues_[0].get() + postIndex; + const uint64_t postIndex = + (metadata_.operands[5].type == AARCH64_OP_REG) + ? sourceValues_[1].get() + : 64; + results_[0] = sourceValues_[0].get() + postIndex; + results_[1] = memoryData_[0].zeroExtend(memoryData_[0].size(), 256); + results_[2] = memoryData_[1].zeroExtend(memoryData_[1].size(), 256); + results_[3] = memoryData_[2].zeroExtend(memoryData_[2].size(), 256); + results_[4] = memoryData_[3].zeroExtend(memoryData_[3].size(), 256); break; } case Opcode::AArch64_LD1Twov16b: // ld1 {vt1.16b, vt2.16b}, [xn] @@ -3107,14 +3109,14 @@ void Instruction::execute() { case Opcode::AArch64_LD1Twov4s_POST: { // ld1 {vt1.4s, vt2.4s}, [xn], // <#imm|xm> // LOAD - results_[0] = memoryData_[0].zeroExtend(memoryData_[0].size(), 256); - results_[1] = memoryData_[1].zeroExtend(memoryData_[1].size(), 256); - // if #imm post-index, value can only be 32 - const uint64_t postIndex = (metadata_.operands[3].type == ARM64_OP_REG) - ? sourceValues_[1].get() - : 32; - results_[2] = sourceValues_[0].get() + postIndex; + const uint64_t postIndex = + (metadata_.operands[3].type == AARCH64_OP_REG) + ? sourceValues_[1].get() + : 32; + results_[0] = sourceValues_[0].get() + postIndex; + results_[1] = memoryData_[0].zeroExtend(memoryData_[0].size(), 256); + results_[2] = memoryData_[1].zeroExtend(memoryData_[1].size(), 256); break; } case Opcode::AArch64_LD1W: { // ld1w {zt.s}, pg/z, [xn, xm, lsl #2] @@ -3136,8 +3138,8 @@ void Instruction::execute() { results_[0] = {out, 256}; break; } - case Opcode::AArch64_LD1W_IMM_REAL: { // ld1w {zt.s}, pg/z, [xn{, #imm, - // mul vl}] + case Opcode::AArch64_LD1W_IMM: { // ld1w {zt.s}, pg/z, [xn{, #imm, + // mul vl}] // LOAD const uint64_t* p = sourceValues_[0].getAsVector(); @@ -3186,9 +3188,13 @@ void Instruction::execute() { for (int i = 0; i < 2; i++) { out[i] = (i == index) ? memoryData_[0].get() : vt[i]; } - results_[0] = {out, 256}; - results_[1] = - sourceValues_[1].get() + metadata_.operands[2].imm; + // If post index is #imm, it can only be 8 + const uint64_t postIndex = + (metadata_.operands[2].type == AARCH64_OP_REG) + ? sourceValues_[1].get() + : 8; + results_[0] = sourceValues_[1].get() + postIndex; + results_[1] = {out, 256}; break; } case Opcode::AArch64_LD2D: // ld2d {zt1.d, zt2.d}, pg/z, [, xm, @@ -3230,19 +3236,19 @@ void Instruction::execute() { break; } case Opcode::AArch64_LD2Twov4s_POST: { // ld2 {vt1.4s, vt2.4s}, [xn], - // #imm + // // LOAD const float* region1 = memoryData_[0].getAsVector(); const float* region2 = memoryData_[1].getAsVector(); float t1[4] = {region1[0], region1[2], region2[0], region2[2]}; float t2[4] = {region1[1], region1[3], region2[1], region2[3]}; - results_[0] = {t1, 256}; - results_[1] = {t2, 256}; - uint64_t offset = 32; - if (metadata_.operandCount == 4) { - offset = sourceValues_[3].get(); - } - results_[2] = sourceValues_[2].get() + offset; + // #imm can only be 32 + const uint64_t offset = (metadata_.operands[3].type == AARCH64_OP_REG) + ? sourceValues_[1].get() + : 32; + results_[0] = sourceValues_[0].get() + offset; + results_[1] = {t1, 256}; + results_[2] = {t2, 256}; break; } case Opcode::AArch64_LD3D_IMM: { // ld3d {zt1.d, zt2.d, zt3.d}, pg/z, @@ -3364,9 +3370,9 @@ void Instruction::execute() { isInstruction(InsnType::isSVEData)) ? 256 : 8; - results_[0] = memoryData_[0].zeroExtend(dataSize_, regSize); - results_[1] = memoryData_[1].zeroExtend(dataSize_, regSize); - results_[2] = + results_[1] = memoryData_[0].zeroExtend(dataSize_, regSize); + results_[2] = memoryData_[1].zeroExtend(dataSize_, regSize); + results_[0] = sourceValues_[0].get() + metadata_.operands[3].imm; break; } @@ -3380,9 +3386,9 @@ void Instruction::execute() { isInstruction(InsnType::isSVEData)) ? 256 : 8; - results_[0] = memoryData_[0].zeroExtend(dataSize_, regSize); - results_[1] = memoryData_[1].zeroExtend(dataSize_, regSize); - results_[2] = + results_[1] = memoryData_[0].zeroExtend(dataSize_, regSize); + results_[2] = memoryData_[1].zeroExtend(dataSize_, regSize); + results_[0] = sourceValues_[0].get() + metadata_.operands[2].mem.disp; break; } @@ -3394,15 +3400,15 @@ void Instruction::execute() { } case Opcode::AArch64_LDRBBpost: { // ldrb wt, [xn], #imm // LOAD - results_[0] = memoryData_[0].zeroExtend(1, 8); - results_[1] = + results_[1] = memoryData_[0].zeroExtend(1, 8); + results_[0] = sourceValues_[0].get() + metadata_.operands[2].imm; break; } case Opcode::AArch64_LDRBBpre: { // ldrb wt, [xn, #imm]! // LOAD - results_[0] = memoryData_[0].zeroExtend(1, 8); - results_[1] = + results_[1] = memoryData_[0].zeroExtend(1, 8); + results_[0] = sourceValues_[0].get() + metadata_.operands[1].mem.disp; break; } @@ -3450,8 +3456,8 @@ void Instruction::execute() { isInstruction(InsnType::isSVEData)) ? 256 : 8; - results_[0] = memoryData_[0].zeroExtend(dataSize_, regSize); - results_[1] = + results_[1] = memoryData_[0].zeroExtend(dataSize_, regSize); + results_[0] = sourceValues_[0].get() + metadata_.operands[2].imm; break; } @@ -3467,8 +3473,8 @@ void Instruction::execute() { isInstruction(InsnType::isSVEData)) ? 256 : 8; - results_[0] = memoryData_[0].zeroExtend(dataSize_, regSize); - results_[1] = + results_[1] = memoryData_[0].zeroExtend(dataSize_, regSize); + results_[0] = sourceValues_[0].get() + metadata_.operands[1].mem.disp; break; } @@ -3484,15 +3490,15 @@ void Instruction::execute() { } case Opcode::AArch64_LDRHHpost: { // ldrh wt, [xn], #imm // LOAD - results_[0] = memoryData_[0].zeroExtend(2, 8); - results_[1] = + results_[1] = memoryData_[0].zeroExtend(2, 8); + results_[0] = sourceValues_[0].get() + metadata_.operands[2].imm; break; } case Opcode::AArch64_LDRHHpre: { // ldrh wt, [xn, #imm]! // LOAD - results_[0] = memoryData_[0].zeroExtend(2, 8); - results_[1] = + results_[1] = memoryData_[0].zeroExtend(2, 8); + results_[0] = sourceValues_[0].get() + metadata_.operands[1].mem.disp; break; } @@ -3586,8 +3592,8 @@ void Instruction::execute() { } case Opcode::AArch64_LDRSWpost: { // ldrsw xt, [xn], #simm // LOAD - results_[0] = static_cast(memoryData_[0].get()); - results_[1] = + results_[1] = static_cast(memoryData_[0].get()); + results_[0] = sourceValues_[0].get() + metadata_.operands[2].imm; break; } @@ -3847,8 +3853,7 @@ void Instruction::execute() { case Opcode::AArch64_MSR: { // msr (systemreg|Sop0_op1_Cn_Cm_op2), xt // Handle case where SVCR is being updated as this invokes additional // functionality - if (metadata_.operands[0].reg == - static_cast(ARM64_SYSREG_SVCR)) { + if (metadata_.operands[0].sysop.reg.sysreg == AARCH64_SYSREG_SVCR) { return SMZAupdated(); } else { results_[0] = sourceValues_[0]; @@ -3866,16 +3871,16 @@ void Instruction::execute() { case Opcode::AArch64_MSRpstatesvcrImm1: { // msr svcr, #imm // This instruction is always used by SMSTART and SMSTOP aliases. const uint64_t svcrBits = - static_cast(metadata_.operands[0].svcr); + static_cast(metadata_.operands[0].sysop.alias.svcr); // Changing value of SM or ZA bits in SVCR zeros out vector, predicate, // and ZA registers. Raise an exception to do this. switch (svcrBits) { - case ARM64_SVCR_SVCRSM: + case AARCH64_SVCR_SVCRSM: return streamingModeUpdated(); - case ARM64_SVCR_SVCRZA: + case AARCH64_SVCR_SVCRZA: return zaRegisterStatusUpdated(); - case ARM64_SVCR_SVCRSMZA: + case AARCH64_SVCR_SVCRSMZA: return SMZAupdated(); default: // Invalid instruction @@ -4373,7 +4378,7 @@ void Instruction::execute() { results_[0] = vecSshrShift_imm(sourceValues_, metadata_); break; } - case Opcode::AArch64_SST1B_D_REAL: { // st1b {zd.d}, pg, [xn, zm.d] + case Opcode::AArch64_SST1B_D: { // st1b {zd.d}, pg, [xn, zm.d] // STORE const uint64_t* d = sourceValues_[0].getAsVector(); const uint64_t* p = sourceValues_[1].getAsVector(); @@ -4389,7 +4394,7 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_SST1D_REAL: { // st1d {zt.d}, pg, [xn, zm.d] + case Opcode::AArch64_SST1D: { // st1d {zt.d}, pg, [xn, zm.d] // STORE const uint64_t* d = sourceValues_[0].getAsVector(); const uint64_t* p = sourceValues_[1].getAsVector(); @@ -4421,9 +4426,8 @@ void Instruction::execute() { } break; } - case Opcode::AArch64_SST1D_SCALED_SCALED_REAL: { // st1d {zt.d}, pg, [xn, - // zm.d, lsl # - // 3] + case Opcode::AArch64_SST1D_SCALED: { // st1d {zt.d}, pg, [xn, + // zm.d, lsl #3] // STORE const uint64_t* d = sourceValues_[0].getAsVector(); const uint64_t* p = sourceValues_[1].getAsVector(); @@ -4451,7 +4455,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint64_t* tileSlice = sourceValues_[sliceNum].getAsVector(); @@ -4471,7 +4475,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; std::array mdata; uint16_t md_size = 0; @@ -4506,7 +4510,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; const uint32_t* tileSlice = sourceValues_[sliceNum].getAsVector(); @@ -4526,7 +4530,7 @@ void Instruction::execute() { sourceValues_[partition_num + 1].getAsVector(); const uint32_t sliceNum = - (ws + metadata_.operands[0].sme_index.disp) % partition_num; + (ws + metadata_.operands[0].sme.slice_offset.imm) % partition_num; std::array mdata; uint16_t md_size = 0; @@ -4634,9 +4638,10 @@ void Instruction::execute() { 16 * sizeof(uint8_t)); } // if #imm post-index, value can only be 64 - const uint64_t postIndex = (metadata_.operands[5].type == ARM64_OP_REG) - ? sourceValues_[5].get() - : 64; + const uint64_t postIndex = + (metadata_.operands[5].type == AARCH64_OP_REG) + ? sourceValues_[5].get() + : 64; results_[0] = sourceValues_[4].get() + postIndex; break; } @@ -4659,9 +4664,10 @@ void Instruction::execute() { 2 * sizeof(uint64_t)); } // if #imm post-index, value can only be 64 - const uint64_t postIndex = (metadata_.operands[5].type == ARM64_OP_REG) - ? sourceValues_[5].get() - : 64; + const uint64_t postIndex = + (metadata_.operands[5].type == AARCH64_OP_REG) + ? sourceValues_[5].get() + : 64; results_[0] = sourceValues_[4].get() + postIndex; break; } @@ -4674,9 +4680,10 @@ void Instruction::execute() { 2 * sizeof(uint32_t)); } // if #imm post-index, value can only be 32 - const uint64_t postIndex = (metadata_.operands[5].type == ARM64_OP_REG) - ? sourceValues_[5].get() - : 32; + const uint64_t postIndex = + (metadata_.operands[5].type == AARCH64_OP_REG) + ? sourceValues_[5].get() + : 32; results_[0] = sourceValues_[4].get() + postIndex; break; } @@ -4699,9 +4706,10 @@ void Instruction::execute() { 4 * sizeof(uint32_t)); } // if #imm post-index, value can only be 64 - const uint64_t postIndex = (metadata_.operands[5].type == ARM64_OP_REG) - ? sourceValues_[5].get() - : 64; + const uint64_t postIndex = + (metadata_.operands[5].type == AARCH64_OP_REG) + ? sourceValues_[5].get() + : 64; results_[0] = sourceValues_[4].get() + postIndex; break; } @@ -4722,9 +4730,10 @@ void Instruction::execute() { memoryData_[1] = RegisterValue((char*)t2, 16 * sizeof(uint8_t)); // if #imm post-index, value can only be 32 - const uint64_t postIndex = (metadata_.operands[3].type == ARM64_OP_REG) - ? sourceValues_[3].get() - : 32; + const uint64_t postIndex = + (metadata_.operands[3].type == AARCH64_OP_REG) + ? sourceValues_[3].get() + : 32; results_[0] = sourceValues_[2].get() + postIndex; break; } @@ -4745,9 +4754,10 @@ void Instruction::execute() { memoryData_[1] = RegisterValue((char*)t2, 2 * sizeof(uint64_t)); // if #imm post-index, value can only be 32 - const uint64_t postIndex = (metadata_.operands[3].type == ARM64_OP_REG) - ? sourceValues_[3].get() - : 32; + const uint64_t postIndex = + (metadata_.operands[3].type == AARCH64_OP_REG) + ? sourceValues_[3].get() + : 32; results_[0] = sourceValues_[2].get() + postIndex; break; } @@ -4768,9 +4778,10 @@ void Instruction::execute() { memoryData_[1] = RegisterValue((char*)t2, 4 * sizeof(uint32_t)); // if #imm post-index, value can only be 32 - const uint64_t postIndex = (metadata_.operands[3].type == ARM64_OP_REG) - ? sourceValues_[3].get() - : 32; + const uint64_t postIndex = + (metadata_.operands[3].type == AARCH64_OP_REG) + ? sourceValues_[3].get() + : 32; results_[0] = sourceValues_[2].get() + postIndex; break; } @@ -4804,16 +4815,16 @@ void Instruction::execute() { memoryData_[0] = t[metadata_.operands[0].vector_index]; break; } - case Opcode::AArch64_ST1i16_POST: { // st1 {vt.h}[index], [xn], xm - // st1 {vt.h}[index], [xn], #2 + case Opcode::AArch64_ST1i16_POST: { // st1 {vt.h}[index], [xn], // STORE const uint16_t* t = sourceValues_[0].getAsVector(); memoryData_[0] = t[metadata_.operands[0].vector_index]; - uint64_t offset = 2; - if (metadata_.operandCount == 3) { - offset = sourceValues_[2].get(); - } - results_[0] = sourceValues_[1].get() + offset; + // if #imm post-index, value can only be 2 + const uint64_t postIndex = + (metadata_.operands[2].type == AARCH64_OP_REG) + ? sourceValues_[2].get() + : 2; + results_[0] = sourceValues_[1].get() + postIndex; break; } case Opcode::AArch64_ST1i32: { // st1 {vt.s}[index], [xn] @@ -4822,16 +4833,16 @@ void Instruction::execute() { memoryData_[0] = t[metadata_.operands[0].vector_index]; break; } - case Opcode::AArch64_ST1i32_POST: { // st1 {vt.s}[index], [xn], xm - // st1 {vt.s}[index], [xn], #4 + case Opcode::AArch64_ST1i32_POST: { // st1 {vt.s}[index], [xn], // STORE const uint32_t* t = sourceValues_[0].getAsVector(); memoryData_[0] = t[metadata_.operands[0].vector_index]; - uint64_t offset = 4; - if (metadata_.operandCount == 3) { - offset = sourceValues_[2].get(); - } - results_[0] = sourceValues_[1].get() + offset; + // if #imm post-index, value can only be 4 + const uint64_t postIndex = + (metadata_.operands[2].type == AARCH64_OP_REG) + ? sourceValues_[2].get() + : 4; + results_[0] = sourceValues_[1].get() + postIndex; break; } case Opcode::AArch64_ST1i64: { // st1 {vt.d}[index], [xn] @@ -4840,16 +4851,16 @@ void Instruction::execute() { memoryData_[0] = t[metadata_.operands[0].vector_index]; break; } - case Opcode::AArch64_ST1i64_POST: { // st1 {vt.d}[index], [xn], xm - // st1 {vt.d}[index], [xn], #8 + case Opcode::AArch64_ST1i64_POST: { // st1 {vt.d}[index], [xn], // STORE const uint64_t* t = sourceValues_[0].getAsVector(); memoryData_[0] = t[metadata_.operands[0].vector_index]; - uint64_t offset = 8; - if (metadata_.operandCount == 3) { - offset = sourceValues_[2].get(); - } - results_[0] = sourceValues_[1].get() + offset; + // if #imm post-index, value can only be 8 + const uint64_t postIndex = + (metadata_.operands[2].type == AARCH64_OP_REG) + ? sourceValues_[2].get() + : 8; + results_[0] = sourceValues_[1].get() + postIndex; break; } case Opcode::AArch64_ST1i8: { // st1 {vt.b}[index], [xn] @@ -4858,17 +4869,16 @@ void Instruction::execute() { memoryData_[0] = t[metadata_.operands[0].vector_index]; break; } - case Opcode::AArch64_ST1i8_POST: { // st1 {vt.b}[index], [xn], xm - // st1 {vt.b}[index], [xn], #1 + case Opcode::AArch64_ST1i8_POST: { // st1 {vt.b}[index], [xn], // STORE const uint8_t* t = sourceValues_[0].getAsVector(); memoryData_[0] = t[metadata_.operands[0].vector_index]; - uint64_t offset = 1; - if (metadata_.operandCount == 3) { - offset = sourceValues_[2].get(); - } - results_[0] = - RegisterValue(sourceValues_[1].get() + offset, 8); + // if #imm post-index, value can only be 1 + const uint64_t postIndex = + (metadata_.operands[2].type == AARCH64_OP_REG) + ? sourceValues_[2].get() + : 1; + results_[0] = sourceValues_[1].get() + postIndex; break; } case Opcode::AArch64_ST2D_IMM: { // st2d {zt1.d, zt2.d}, pg, [{, @@ -4908,7 +4918,7 @@ void Instruction::execute() { break; } case Opcode::AArch64_ST2Twov4s_POST: { // st2 {vt1.4s, vt2.4s}, [xn], - // #imm + // // STORE const float* t1 = sourceValues_[0].getAsVector(); const float* t2 = sourceValues_[1].getAsVector(); @@ -4916,12 +4926,12 @@ void Instruction::execute() { std::vector m2 = {t1[2], t2[2], t1[3], t2[3]}; memoryData_[0] = RegisterValue((char*)m1.data(), 4 * sizeof(float)); memoryData_[1] = RegisterValue((char*)m2.data(), 4 * sizeof(float)); - - uint64_t offset = 32; - if (metadata_.operandCount == 4) { - offset = sourceValues_[3].get(); - } - results_[0] = sourceValues_[2].get() + offset; + // if #imm post-index, value can only be 32 + const uint64_t postIndex = + (metadata_.operands[3].type == AARCH64_OP_REG) + ? sourceValues_[3].get() + : 32; + results_[0] = sourceValues_[2].get() + postIndex; break; } case Opcode::AArch64_STLRB: { // stlrb wt, [xn] diff --git a/src/lib/arch/aarch64/MicroDecoder.cc b/src/lib/arch/aarch64/MicroDecoder.cc index edb4a9a1c2..ea181c8d66 100644 --- a/src/lib/arch/aarch64/MicroDecoder.cc +++ b/src/lib/arch/aarch64/MicroDecoder.cc @@ -18,52 +18,51 @@ MicroDecoder::~MicroDecoder() { microMetadataCache_.clear(); } -bool MicroDecoder::detectOverlap(arm64_reg registerA, arm64_reg registerB) { +bool MicroDecoder::detectOverlap(aarch64_reg registerA, aarch64_reg registerB) { // Early checks on equivalent register ISA names if (registerA == registerB) return true; - if ((registerA == ARM64_REG_WZR || registerA == ARM64_REG_XZR) && - (registerB == ARM64_REG_WZR || registerB == ARM64_REG_XZR)) + if ((registerA == AARCH64_REG_WZR || registerA == AARCH64_REG_XZR) && + (registerB == AARCH64_REG_WZR || registerB == AARCH64_REG_XZR)) return true; - if ((registerA == ARM64_REG_WSP || registerA == ARM64_REG_SP) && - (registerB == ARM64_REG_WSP || registerB == ARM64_REG_SP)) + if ((registerA == AARCH64_REG_WSP || registerA == AARCH64_REG_SP) && + (registerB == AARCH64_REG_WSP || registerB == AARCH64_REG_SP)) return true; // Arrays to hold register identifiers - std::array registers = {registerA, registerB}; + std::array registers = {registerA, registerB}; std::array isGP = {false, false}; std::array indexes = {0, 0}; // Get index of each register and whether they are general purpose for (int i = 0; i < 2; i++) { - if (registers[i] == ARM64_REG_FP) { + if (registers[i] == AARCH64_REG_FP) { isGP[i] = true; indexes[i] = 29; - } else if (registers[i] == ARM64_REG_LR) { + } else if (registers[i] == AARCH64_REG_LR) { isGP[i] = true; indexes[i] = 30; } else { - arm64_reg base = (arm64_reg)0; - if (registers[i] >= ARM64_REG_V0) { - base = ARM64_REG_V0; - } else if (registers[i] >= ARM64_REG_Z0) { - base = ARM64_REG_Z0; - } else if (registers[i] >= ARM64_REG_X0) { - base = ARM64_REG_X0; + aarch64_reg base = (aarch64_reg)0; + // No need to check V registers as they are encoded as Q or D registers + if (registers[i] >= AARCH64_REG_Z0) { + base = AARCH64_REG_Z0; + } else if (registers[i] >= AARCH64_REG_X0) { + base = AARCH64_REG_X0; isGP[i] = true; - } else if (registers[i] >= ARM64_REG_W0) { - base = ARM64_REG_W0; + } else if (registers[i] >= AARCH64_REG_W0) { + base = AARCH64_REG_W0; isGP[i] = true; - } else if (registers[i] >= ARM64_REG_S0) { - base = ARM64_REG_S0; - } else if (registers[i] >= ARM64_REG_Q0) { - base = ARM64_REG_Q0; - } else if (registers[i] >= ARM64_REG_P0) { - base = ARM64_REG_P0; - } else if (registers[i] >= ARM64_REG_H0) { - base = ARM64_REG_H0; - } else if (registers[i] >= ARM64_REG_D0) { - base = ARM64_REG_D0; - } else if (registers[i] >= ARM64_REG_B0) { - base = ARM64_REG_B0; + } else if (registers[i] >= AARCH64_REG_S0) { + base = AARCH64_REG_S0; + } else if (registers[i] >= AARCH64_REG_Q0) { + base = AARCH64_REG_Q0; + } else if (registers[i] >= AARCH64_REG_P0) { + base = AARCH64_REG_P0; + } else if (registers[i] >= AARCH64_REG_H0) { + base = AARCH64_REG_H0; + } else if (registers[i] >= AARCH64_REG_D0) { + base = AARCH64_REG_D0; + } else if (registers[i] >= AARCH64_REG_B0) { + base = AARCH64_REG_B0; } indexes[i] = registers[i] - base; } @@ -105,23 +104,25 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); // ldr uop 2 - cacheVector.push_back(createLdrUop( - architecture, metadata.operands[2].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 2 * dataSize}, - capstoneHandle, true, 2, dataSize)); + cacheVector.push_back( + createLdrUop(architecture, metadata.operands[2].reg, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, + 2 * dataSize}, + capstoneHandle, true, 2, dataSize)); // ldr uop 3 - cacheVector.push_back(createLdrUop( - architecture, metadata.operands[3].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 3 * dataSize}, - capstoneHandle, true, 2, dataSize)); + cacheVector.push_back( + createLdrUop(architecture, metadata.operands[3].reg, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, + 3 * dataSize}, + capstoneHandle, true, 2, dataSize)); iter = microDecodeCache_.try_emplace(word, cacheVector).first; break; @@ -134,25 +135,27 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); // ldr uop 2 - cacheVector.push_back(createLdrUop( - architecture, metadata.operands[2].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 2 * dataSize}, - capstoneHandle, true, 2, dataSize)); + cacheVector.push_back( + createLdrUop(architecture, metadata.operands[2].reg, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, + 2 * dataSize}, + capstoneHandle, true, 2, dataSize)); // ldr uop 3 - cacheVector.push_back(createLdrUop( - architecture, metadata.operands[3].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 3 * dataSize}, - capstoneHandle, true, 2, dataSize)); + cacheVector.push_back( + createLdrUop(architecture, metadata.operands[3].reg, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, + 3 * dataSize}, + capstoneHandle, true, 2, dataSize)); // offset generation uop - if (metadata.operands[5].type == ARM64_OP_REG) { + if (metadata.operands[5].type == AARCH64_OP_REG) { cacheVector.push_back(createRegOffsetUop( architecture, metadata.operands[4].mem.base, metadata.operands[5].reg, capstoneHandle, true)); @@ -173,25 +176,27 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); // ldr uop 2 - cacheVector.push_back(createLdrUop( - architecture, metadata.operands[2].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 2 * dataSize}, - capstoneHandle, true, 2, dataSize)); + cacheVector.push_back( + createLdrUop(architecture, metadata.operands[2].reg, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, + 2 * dataSize}, + capstoneHandle, true, 2, dataSize)); // ldr uop 3 - cacheVector.push_back(createLdrUop( - architecture, metadata.operands[3].reg, - {metadata.operands[4].mem.base, ARM64_REG_INVALID, 3 * dataSize}, - capstoneHandle, true, 2, dataSize)); + cacheVector.push_back( + createLdrUop(architecture, metadata.operands[3].reg, + {metadata.operands[4].mem.base, AARCH64_REG_INVALID, + 3 * dataSize}, + capstoneHandle, true, 2, dataSize)); // offset generation uop - if (metadata.operands[5].type == ARM64_OP_REG) { + if (metadata.operands[5].type == AARCH64_OP_REG) { cacheVector.push_back(createRegOffsetUop( architecture, metadata.operands[4].mem.base, metadata.operands[5].reg, capstoneHandle, true)); @@ -216,12 +221,12 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); iter = microDecodeCache_.try_emplace(word, cacheVector).first; @@ -235,15 +240,15 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); // offset generation uop - if (metadata.operands[3].type == ARM64_OP_REG) { + if (metadata.operands[3].type == AARCH64_OP_REG) { cacheVector.push_back(createRegOffsetUop( architecture, metadata.operands[2].mem.base, metadata.operands[3].reg, capstoneHandle, true)); @@ -264,15 +269,15 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); // offset generation uop - if (metadata.operands[3].type == ARM64_OP_REG) { + if (metadata.operands[3].type == AARCH64_OP_REG) { cacheVector.push_back(createRegOffsetUop( architecture, metadata.operands[2].mem.base, metadata.operands[3].reg, capstoneHandle, true)); @@ -305,13 +310,13 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[orderA].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, metadata.operands[2].mem.disp + (orderA * dataSize)}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[orderB].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, metadata.operands[2].mem.disp + (orderB * dataSize)}, capstoneHandle, true, 2, dataSize)); @@ -329,12 +334,12 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, false, 2, dataSize)); // offset generation uop cacheVector.push_back(createImmOffsetUop( @@ -358,12 +363,12 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop 0 cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // ldr uop 1 cacheVector.push_back(createLdrUop( architecture, metadata.operands[1].reg, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, true, 2, dataSize)); iter = microDecodeCache_.try_emplace(word, cacheVector).first; @@ -382,7 +387,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[1].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[1].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // offset generation uop cacheVector.push_back(createImmOffsetUop( @@ -409,7 +414,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // ldr uop cacheVector.push_back(createLdrUop( architecture, metadata.operands[0].reg, - {metadata.operands[1].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[1].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, true, 1, dataSize)); iter = microDecodeCache_.try_emplace(word, cacheVector).first; @@ -428,7 +433,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store0 address uop cacheVector.push_back( createStrUop(architecture, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, metadata.operands[2].mem.disp}, capstoneHandle, false, 1, dataSize)); // store0 data uop @@ -438,7 +443,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store1 address uop cacheVector.push_back( createStrUop(architecture, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, metadata.operands[2].mem.disp + dataSize}, capstoneHandle, false, 2, dataSize)); // store1 data uop @@ -461,7 +466,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store0 address uop cacheVector.push_back(createStrUop( architecture, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // store0 data uop cacheVector.push_back(createSDUop(architecture, @@ -470,7 +475,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store1 address uop cacheVector.push_back(createStrUop( architecture, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, false, 2, dataSize)); // store1 data uop cacheVector.push_back(createSDUop(architecture, @@ -501,7 +506,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store0 address uop cacheVector.push_back(createStrUop( architecture, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // store0 data uop cacheVector.push_back(createSDUop(architecture, @@ -510,7 +515,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store1 address uop cacheVector.push_back(createStrUop( architecture, - {metadata.operands[2].mem.base, ARM64_REG_INVALID, dataSize}, + {metadata.operands[2].mem.base, AARCH64_REG_INVALID, dataSize}, capstoneHandle, false, 2, dataSize)); // store1 data uop cacheVector.push_back(createSDUop( @@ -534,7 +539,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store address uop cacheVector.push_back(createStrUop( architecture, - {metadata.operands[1].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[1].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // store data uop cacheVector.push_back(createSDUop(architecture, @@ -567,7 +572,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store address uop cacheVector.push_back(createStrUop( architecture, - {metadata.operands[1].mem.base, ARM64_REG_INVALID, 0}, + {metadata.operands[1].mem.base, AARCH64_REG_INVALID, 0}, capstoneHandle, false, 1, dataSize)); // store data uop cacheVector.push_back(createSDUop( @@ -591,7 +596,7 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, // store address uop cacheVector.push_back( createStrUop(architecture, - {metadata.operands[1].mem.base, ARM64_REG_INVALID, + {metadata.operands[1].mem.base, AARCH64_REG_INVALID, metadata.operands[1].mem.disp}, capstoneHandle, false, 1, dataSize)); // store data uop @@ -622,66 +627,123 @@ uint8_t MicroDecoder::decode(const Architecture& architecture, uint32_t word, } cs_detail MicroDecoder::createDefaultDetail(std::vector opTypes) { - cs_arm64 info = default_info; + cs_aarch64 info = default_info; cs_detail detail = default_detail; info.op_count = opTypes.size(); for (size_t op = 0; op < opTypes.size(); op++) { info.operands[op] = default_op; switch (opTypes[op].type) { - case arm64_op_type::ARM64_OP_REG: { - info.operands[op].type = ARM64_OP_REG; - info.operands[op].reg = ARM64_REG_INVALID; + case aarch64_op_type::AARCH64_OP_REG: { + info.operands[op].type = AARCH64_OP_REG; + info.operands[op].reg = AARCH64_REG_INVALID; if (opTypes[op].isDestination) { info.operands[op].access = CS_AC_WRITE; } break; } - case arm64_op_type::ARM64_OP_IMM: { - info.operands[op].type = ARM64_OP_IMM; + case aarch64_op_type::AARCH64_OP_IMM: { + info.operands[op].type = AARCH64_OP_IMM; info.operands[op].imm = 0; break; } - case arm64_op_type::ARM64_OP_MEM: { - info.operands[op].type = ARM64_OP_MEM; - info.operands[op].mem = {ARM64_REG_INVALID, ARM64_REG_INVALID, 0}; + case aarch64_op_type::AARCH64_OP_MEM: { + info.operands[op].type = AARCH64_OP_MEM; + info.operands[op].mem = {AARCH64_REG_INVALID, AARCH64_REG_INVALID, 0}; break; } - case arm64_op_type::ARM64_OP_INVALID: - case arm64_op_type::ARM64_OP_FP: - case arm64_op_type::ARM64_OP_CIMM: - case arm64_op_type::ARM64_OP_REG_MRS: - case arm64_op_type::ARM64_OP_REG_MSR: - case arm64_op_type::ARM64_OP_PSTATE: - case arm64_op_type::ARM64_OP_SYS: - case arm64_op_type::ARM64_OP_SVCR: - case arm64_op_type::ARM64_OP_PREFETCH: - case arm64_op_type::ARM64_OP_BARRIER: - case arm64_op_type::ARM64_OP_SME_INDEX: + case aarch64_op_type::AARCH64_OP_INVALID: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_MEM_REG: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_MEM_IMM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_FP: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_CIMM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_REG_MRS: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_REG_MSR: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_IMPLICIT_IMM_0: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SVCR: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_AT: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_DB: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_DC: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_ISB: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_TSB: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_PRFM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SVEPRFM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_RPRFM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_PSTATEIMM0_15: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_PSTATEIMM0_1: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_PSB: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_BTI: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SVEPREDPAT: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SVEVECLENSPECIFIER: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SME: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_IMM_RANGE: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_TLBI: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_IC: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_DBNXS: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_EXACTFPIMM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SYSREG: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SYSIMM: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_SYSALIAS: + [[fallthrough]]; + case aarch64_op_type::AARCH64_OP_PRED: break; } } - detail.arm64 = info; + detail.aarch64 = info; return detail; } Instruction MicroDecoder::createImmOffsetUop(const Architecture& architecture, - arm64_reg base, int64_t offset, + aarch64_reg base, int64_t offset, csh capstoneHandle, bool lastMicroOp, int microOpIndex) { - cs_detail off_imm_detail = - createDefaultDetail({{ARM64_OP_REG, 1}, {ARM64_OP_REG}, {ARM64_OP_IMM}}); - off_imm_detail.arm64.operands[0].reg = base; - off_imm_detail.arm64.operands[1].reg = base; - off_imm_detail.arm64.operands[2].imm = offset; - - cs_insn off_imm_cs = {arm64_insn::ARM64_INS_ADD, + cs_detail off_imm_detail = createDefaultDetail( + {{AARCH64_OP_REG, 1}, {AARCH64_OP_REG}, {AARCH64_OP_IMM}}); + off_imm_detail.aarch64.operands[0].reg = base; + off_imm_detail.aarch64.operands[1].reg = base; + off_imm_detail.aarch64.operands[2].imm = offset; + + cs_insn off_imm_cs = {aarch64_insn::AARCH64_INS_ADD, + aarch64_insn::AARCH64_INS_INVALID, 0x0, 4, "", "micro_offset_imm", "", + false, + false, &off_imm_detail, MicroOpcode::OFFSET_IMM}; @@ -694,23 +756,24 @@ Instruction MicroDecoder::createImmOffsetUop(const Architecture& architecture, return off_imm; } -Instruction MicroDecoder::createRegOffsetUop(const Architecture& architecture, - arm64_reg base, arm64_reg offset, - csh capstoneHandle, - bool lastMicroOp, - int microOpIndex) { - cs_detail off_reg_detail = - createDefaultDetail({{ARM64_OP_REG, 1}, {ARM64_OP_REG}, {ARM64_OP_REG}}); - off_reg_detail.arm64.operands[0].reg = base; - off_reg_detail.arm64.operands[1].reg = base; - off_reg_detail.arm64.operands[2].reg = offset; - - cs_insn off_reg_cs = {arm64_insn::ARM64_INS_ADD, +Instruction MicroDecoder::createRegOffsetUop( + const Architecture& architecture, aarch64_reg base, aarch64_reg offset, + csh capstoneHandle, bool lastMicroOp, int microOpIndex) { + cs_detail off_reg_detail = createDefaultDetail( + {{AARCH64_OP_REG, 1}, {AARCH64_OP_REG}, {AARCH64_OP_REG}}); + off_reg_detail.aarch64.operands[0].reg = base; + off_reg_detail.aarch64.operands[1].reg = base; + off_reg_detail.aarch64.operands[2].reg = offset; + + cs_insn off_reg_cs = {aarch64_insn::AARCH64_INS_ADD, + aarch64_insn::AARCH64_INS_INVALID, 0x0, 4, "", "micro_offset_reg", "", + false, + false, &off_reg_detail, MicroOpcode::OFFSET_REG}; @@ -724,16 +787,24 @@ Instruction MicroDecoder::createRegOffsetUop(const Architecture& architecture, } Instruction MicroDecoder::createLdrUop(const Architecture& architecture, - arm64_reg dest, arm64_op_mem mem, + aarch64_reg dest, aarch64_op_mem mem, csh capstoneHandle, bool lastMicroOp, int microOpIndex, uint8_t dataSize) { cs_detail ldr_detail = - createDefaultDetail({{ARM64_OP_REG, 1}, {ARM64_OP_MEM}}); - ldr_detail.arm64.operands[0].reg = dest; - ldr_detail.arm64.operands[1].mem = mem; - cs_insn ldr_cs = { - arm64_insn::ARM64_INS_LDR, 0x0, 4, "", "micro_ldr", "", &ldr_detail, - MicroOpcode::LDR_ADDR}; + createDefaultDetail({{AARCH64_OP_REG, 1}, {AARCH64_OP_MEM}}); + ldr_detail.aarch64.operands[0].reg = dest; + ldr_detail.aarch64.operands[1].mem = mem; + cs_insn ldr_cs = {aarch64_insn::AARCH64_INS_LDR, + aarch64_insn::AARCH64_INS_INVALID, + 0x0, + 4, + "", + "micro_ldr", + "", + false, + false, + &ldr_detail, + MicroOpcode::LDR_ADDR}; InstructionMetadata ldr_metadata(ldr_cs); microMetadataCache_.emplace_front(ldr_metadata); Instruction ldr(architecture, microMetadataCache_.front(), @@ -744,13 +815,21 @@ Instruction MicroDecoder::createLdrUop(const Architecture& architecture, } Instruction MicroDecoder::createSDUop(const Architecture& architecture, - arm64_reg src, csh capstoneHandle, + aarch64_reg src, csh capstoneHandle, bool lastMicroOp, int microOpIndex) { - cs_detail sd_detail = createDefaultDetail({{ARM64_OP_REG}}); - sd_detail.arm64.operands[0].reg = src; - cs_insn sd_cs = { - arm64_insn::ARM64_INS_STR, 0x0, 4, "", "micro_sd", "", &sd_detail, - MicroOpcode::STR_DATA}; + cs_detail sd_detail = createDefaultDetail({{AARCH64_OP_REG}}); + sd_detail.aarch64.operands[0].reg = src; + cs_insn sd_cs = {aarch64_insn::AARCH64_INS_STR, + aarch64_insn::AARCH64_INS_INVALID, + 0x0, + 4, + "", + "micro_sd", + "", + false, + false, + &sd_detail, + MicroOpcode::STR_DATA}; InstructionMetadata sd_metadata(sd_cs); microMetadataCache_.emplace_front(sd_metadata); Instruction sd( @@ -761,14 +840,22 @@ Instruction MicroDecoder::createSDUop(const Architecture& architecture, } Instruction MicroDecoder::createStrUop(const Architecture& architecture, - arm64_op_mem mem, csh capstoneHandle, + aarch64_op_mem mem, csh capstoneHandle, bool lastMicroOp, int microOpIndex, uint8_t dataSize) { - cs_detail str_detail = createDefaultDetail({{ARM64_OP_MEM}}); - str_detail.arm64.operands[0].mem = mem; - cs_insn str_cs = { - arm64_insn::ARM64_INS_STR, 0x0, 4, "", "micro_str", "", &str_detail, - MicroOpcode::STR_DATA}; + cs_detail str_detail = createDefaultDetail({{AARCH64_OP_MEM}}); + str_detail.aarch64.operands[0].mem = mem; + cs_insn str_cs = {aarch64_insn::AARCH64_INS_STR, + aarch64_insn::AARCH64_INS_INVALID, + 0x0, + 4, + "", + "micro_str", + "", + false, + false, + &str_detail, + MicroOpcode::STR_ADDR}; InstructionMetadata str_metadata(str_cs); microMetadataCache_.emplace_front(str_metadata); Instruction str(architecture, microMetadataCache_.front(), diff --git a/src/lib/arch/riscv/InstructionMetadata.cc b/src/lib/arch/riscv/InstructionMetadata.cc index 85d27abcfa..0d31ec00e0 100644 --- a/src/lib/arch/riscv/InstructionMetadata.cc +++ b/src/lib/arch/riscv/InstructionMetadata.cc @@ -457,23 +457,6 @@ void InstructionMetadata::duplicateFirstOp() { operandCount = 3; } -void InstructionMetadata::createMemOpPosOne() { - // Given register sequence {Op_a, imm, reg} return {Op_a, mem, _} - assert(operands[1].type == RISCV_OP_IMM && - "Incorrect operand type when creating memory operand"); - assert(operands[2].type == RISCV_OP_REG && - "Incorrect operand type when creating memory operand"); - - cs_riscv_op temp; - temp.type = RISCV_OP_MEM; - temp.mem.base = operands[2].reg; - temp.mem.disp = operands[1].imm; - - operands[1] = temp; - - operandCount = 2; -} - void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { if (insnLengthBytes_ != 2) { return; @@ -533,9 +516,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_LD; - // Create operand formatted like LD instruction - createMemOpPosOne(); - break; } case Opcode::RISCV_C_ADDI4SPN: @@ -600,17 +580,12 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_SD; - // Create operand formatted like SD instruction - createMemOpPosOne(); - break; } case Opcode::RISCV_C_SWSP: { // sw rs2, offset[7:2](x2) opcode = Opcode::RISCV_SW; - createMemOpPosOne(); - break; } case Opcode::RISCV_C_ADD: @@ -642,9 +617,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_LD; - // Create operand formatted like LD instruction - createMemOpPosOne(); - break; } case Opcode::RISCV_C_ADDI: { @@ -678,8 +650,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { // sd rs2 ′ , offset[7:3](rs1 ′) opcode = Opcode::RISCV_SD; - // Create operand formatted like SD instruction - createMemOpPosOne(); break; } @@ -728,8 +698,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_LW; - createMemOpPosOne(); - break; } case Opcode::RISCV_C_FLDSP: @@ -737,16 +705,12 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { // fld rd, offset[8:3](x2) opcode = Opcode::RISCV_FLD; - createMemOpPosOne(); - break; case Opcode::RISCV_C_SW: { // sw rs2 ′, offset[6:2](rs1 ′) opcode = Opcode::RISCV_SW; - createMemOpPosOne(); - break; } case Opcode::RISCV_C_J: @@ -793,8 +757,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_LW; - createMemOpPosOne(); - break; case Opcode::RISCV_C_SRLI: // srli rd ′ , rd ′ , shamt[5:0] @@ -881,8 +843,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_FSD; - createMemOpPosOne(); - break; case Opcode::RISCV_C_FLD: // TODO rv64dc ONLY, make check for this once RV32 implemented @@ -890,8 +850,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_FLD; - createMemOpPosOne(); - break; case Opcode::RISCV_C_FSDSP: // TODO rv64dc ONLY, make check for this once RV32 implemented @@ -899,8 +857,6 @@ void InstructionMetadata::convertCompressedInstruction(const cs_insn& insn) { opcode = Opcode::RISCV_FSD; - createMemOpPosOne(); - break; case Opcode::RISCV_C_SUBW: // TODO rv64 ONLY, make check for this once RV32 implemented diff --git a/src/lib/arch/riscv/Instruction_address.cc b/src/lib/arch/riscv/Instruction_address.cc index 3a9fce30ff..0d6bbb9843 100644 --- a/src/lib/arch/riscv/Instruction_address.cc +++ b/src/lib/arch/riscv/Instruction_address.cc @@ -17,7 +17,7 @@ span Instruction::generateAddresses() { isInstruction(InsnType::isAtomic)) { // Atomics // Metadata operands[2] corresponds to instruction sourceRegValues[1] - assert(metadata_.operands[2].type == RISCV_OP_REG && + assert(metadata_.operands[2].type == RISCV_OP_MEM && "metadata_ operand not of correct type during RISC-V address " "generation"); address = sourceValues_[1].get(); @@ -25,14 +25,14 @@ span Instruction::generateAddresses() { isInstruction(InsnType::isAtomic)) { // Load reserved // Metadata operands[1] corresponds to instruction sourceRegValues[0] - assert(metadata_.operands[1].type == RISCV_OP_REG && + assert(metadata_.operands[1].type == RISCV_OP_MEM && "metadata_ operand not of correct type during RISC-V address " "generation"); address = sourceValues_[0].get(); } else if (isInstruction(InsnType::isStore) && isInstruction(InsnType::isAtomic)) { // Store conditional - assert(metadata_.operands[2].type == RISCV_OP_REG && + assert(metadata_.operands[2].type == RISCV_OP_MEM && "metadata_ operand not of correct type during RISC-V address " "generation"); address = sourceValues_[1].get(); diff --git a/src/lib/config/ModelConfig.cc b/src/lib/config/ModelConfig.cc index 1b12e629d7..6d54b50d06 100644 --- a/src/lib/config/ModelConfig.cc +++ b/src/lib/config/ModelConfig.cc @@ -367,16 +367,16 @@ void ModelConfig::setExpectations(bool isDefault) { std::vector{false, true}); if (isa_ == ISA::AArch64) { - expectations_["Core"].addChild(ExpectationNode::createExpectation( + expectations_["Core"].addChild(ExpectationNode::createExpectation( 128, "Vector-Length", true)); expectations_["Core"]["Vector-Length"].setValueSet( - std::vector{128, 256, 384, 512, 640, 768, 896, 1024, 1152, + std::vector{128, 256, 384, 512, 640, 768, 896, 1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920, 2048}); - expectations_["Core"].addChild(ExpectationNode::createExpectation( + expectations_["Core"].addChild(ExpectationNode::createExpectation( 128, "Streaming-Vector-Length", true)); expectations_["Core"]["Streaming-Vector-Length"].setValueSet( - std::vector{128, 256, 512, 1024, 2048}); + std::vector{128, 256, 512, 1024, 2048}); } // Fetch @@ -441,9 +441,16 @@ void ModelConfig::setExpectations(bool isDefault) { 1, UINT16_MAX); expectations_["Register-Set"].addChild( - ExpectationNode::createExpectation(1, "Matrix-Count", true)); - expectations_["Register-Set"]["Matrix-Count"].setValueBounds( + ExpectationNode::createExpectation(1, "SME-Matrix-Count", + true)); + expectations_["Register-Set"]["SME-Matrix-Count"].setValueBounds( 1, UINT16_MAX); + + expectations_["Register-Set"].addChild( + ExpectationNode::createExpectation( + 1, "SME-Lookup-Table-Count", true)); + expectations_["Register-Set"]["SME-Lookup-Table-Count"] + .setValueBounds(1, UINT16_MAX); } else if (isa_ == ISA::RV64) { // TODO: Reduce to 32 once renaming issue has been sorted. Also replace in // ConfigTest. @@ -660,7 +667,7 @@ void ModelConfig::setExpectations(bool isDefault) { // Get the upper bound of what the opcode value can be based on the ISA uint16_t maxOpcode = 0; if (isa_ == ISA::AArch64) { - maxOpcode = arch::aarch64::Opcode::AArch64_INSTRUCTION_LIST_END; + maxOpcode = arch::aarch64::Opcode::INSTRUCTION_LIST_END; } else if (isa_ == ISA::RV64) { maxOpcode = arch::riscv::Opcode::RISCV_INSTRUCTION_LIST_END; } diff --git a/test/integration/ConfigTest.cc b/test/integration/ConfigTest.cc index 4e6ac2ad68..48975eeacd 100644 --- a/test/integration/ConfigTest.cc +++ b/test/integration/ConfigTest.cc @@ -17,14 +17,14 @@ TEST(ConfigTest, Default) { simeng::config::SimulationMode::Emulation); EXPECT_EQ(simeng::config::SimInfo::getSimModeStr(), "Emulation"); std::vector sysRegisterEnums = { - arm64_sysreg::ARM64_SYSREG_DCZID_EL0, - arm64_sysreg::ARM64_SYSREG_FPCR, - arm64_sysreg::ARM64_SYSREG_FPSR, - arm64_sysreg::ARM64_SYSREG_TPIDR_EL0, - arm64_sysreg::ARM64_SYSREG_MIDR_EL1, - arm64_sysreg::ARM64_SYSREG_CNTVCT_EL0, - arm64_sysreg::ARM64_SYSREG_PMCCNTR_EL0, - arm64_sysreg::ARM64_SYSREG_SVCR}; + aarch64_sysreg::AARCH64_SYSREG_DCZID_EL0, + aarch64_sysreg::AARCH64_SYSREG_FPCR, + aarch64_sysreg::AARCH64_SYSREG_FPSR, + aarch64_sysreg::AARCH64_SYSREG_TPIDR_EL0, + aarch64_sysreg::AARCH64_SYSREG_MIDR_EL1, + aarch64_sysreg::AARCH64_SYSREG_CNTVCT_EL0, + aarch64_sysreg::AARCH64_SYSREG_PMCCNTR_EL0, + aarch64_sysreg::AARCH64_SYSREG_SVCR}; EXPECT_EQ(simeng::config::SimInfo::getSysRegVec(), sysRegisterEnums); std::vector archRegStruct = { {8, 32}, @@ -32,7 +32,8 @@ TEST(ConfigTest, Default) { {32, 17}, {1, 1}, {8, static_cast(sysRegisterEnums.size())}, - {256, 16}}; + {256, 16}, + {64, 1}}; EXPECT_EQ(simeng::config::SimInfo::getArchRegStruct(), archRegStruct); // Test that default config generated matches for AArch64 ISA @@ -47,26 +48,27 @@ TEST(ConfigTest, Default) { "5\n'Process-Image':\n 'Heap-Size': 100000\n 'Stack-Size': " "100000\n'Register-Set':\n 'GeneralPurpose-Count': 38\n " "'FloatingPoint/SVE-Count': 38\n 'Predicate-Count': 17\n " - "'Conditional-Count': 1\n 'Matrix-Count': 1\n'Pipeline-Widths':\n " - "Commit: 1\n FrontEnd: 1\n 'LSQ-Completion': 1\n'Queue-Sizes':\n ROB: " - "32\n Load: 16\n Store: 16\n'Port-Allocator':\n Type: " - "Balanced\n'Branch-Predictor':\n Type: Perceptron\n " - "'BTB-Tag-Bits': 8\n 'Global-History-Length': 8\n 'RAS-entries': " - "8\n'L1-Data-Memory':\n 'Interface-Type': " + "'Conditional-Count': 1\n 'SME-Matrix-Count': 1\n " + "'SME-Lookup-Table-Count': " + "1\n'Pipeline-Widths':\n Commit: 1\n FrontEnd: 1\n 'LSQ-Completion': " + "1\n'Queue-Sizes':\n ROB: 32\n Load: 16\n Store: " + "16\n'Port-Allocator':\n Type: Balanced\n'Branch-Predictor':\n Type: " + "Perceptron\n 'BTB-Tag-Bits': 8\n 'Global-History-Length': 8\n " + "'RAS-entries': 8\n'L1-Data-Memory':\n 'Interface-Type': " "Flat\n'L1-Instruction-Memory':\n 'Interface-Type': " "Flat\n'LSQ-L1-Interface':\n 'Access-Latency': 4\n Exclusive: 0\n " "'Load-Bandwidth': 32\n 'Store-Bandwidth': 32\n " "'Permitted-Requests-Per-Cycle': 1\n 'Permitted-Loads-Per-Cycle': 1\n " "'Permitted-Stores-Per-Cycle': 1\nPorts:\n 0:\n Portname: 0\n " "'Instruction-Group-Support':\n - ALL\n " - "'Instruction-Opcode-Support':\n - 6343\n " + "'Instruction-Opcode-Support':\n - 8232\n " "'Instruction-Group-Support-Nums':\n - " "86\n'Reservation-Stations':\n 0:\n Size: 32\n 'Dispatch-Rate': " "4\n Ports:\n - 0\n 'Port-Nums':\n - " "0\n'Execution-Units':\n 0:\n Pipelined: 1\n 'Blocking-Groups':\n " " - NONE\n 'Blocking-Group-Nums':\n - 87\nLatencies:\n 0:\n " " 'Instruction-Groups':\n - NONE\n 'Instruction-Opcodes':\n " - " - 6343\n 'Execution-Latency': 1\n 'Execution-Throughput': 1\n " + " - 8232\n 'Execution-Latency': 1\n 'Execution-Throughput': 1\n " " 'Instruction-Group-Nums':\n - 87\n'CPU-Info':\n " "'Generate-Special-Dir': 1\n 'Special-File-Dir-Path': " SIMENG_BUILD_DIR "/specialFiles/\n 'Core-Count': 1\n 'Socket-Count': 1\n SMT: 1\n " @@ -375,14 +377,14 @@ TEST(ConfigTest, configFromFile) { simeng::config::SimulationMode::Outoforder); EXPECT_EQ(simeng::config::SimInfo::getSimModeStr(), "Out-of-Order"); std::vector sysRegisterEnums = { - arm64_sysreg::ARM64_SYSREG_DCZID_EL0, - arm64_sysreg::ARM64_SYSREG_FPCR, - arm64_sysreg::ARM64_SYSREG_FPSR, - arm64_sysreg::ARM64_SYSREG_TPIDR_EL0, - arm64_sysreg::ARM64_SYSREG_MIDR_EL1, - arm64_sysreg::ARM64_SYSREG_CNTVCT_EL0, - arm64_sysreg::ARM64_SYSREG_PMCCNTR_EL0, - arm64_sysreg::ARM64_SYSREG_SVCR}; + aarch64_sysreg::AARCH64_SYSREG_DCZID_EL0, + aarch64_sysreg::AARCH64_SYSREG_FPCR, + aarch64_sysreg::AARCH64_SYSREG_FPSR, + aarch64_sysreg::AARCH64_SYSREG_TPIDR_EL0, + aarch64_sysreg::AARCH64_SYSREG_MIDR_EL1, + aarch64_sysreg::AARCH64_SYSREG_CNTVCT_EL0, + aarch64_sysreg::AARCH64_SYSREG_PMCCNTR_EL0, + aarch64_sysreg::AARCH64_SYSREG_SVCR}; EXPECT_EQ(simeng::config::SimInfo::getSysRegVec(), sysRegisterEnums); std::vector archRegStruct = { {8, 32}, @@ -390,7 +392,8 @@ TEST(ConfigTest, configFromFile) { {32, 17}, {1, 1}, {8, static_cast(sysRegisterEnums.size())}, - {256, 16}}; + {256, 16}, + {64, 1}}; EXPECT_EQ(simeng::config::SimInfo::getArchRegStruct(), archRegStruct); std::vector physRegStruct = { {8, 96}, @@ -398,10 +401,11 @@ TEST(ConfigTest, configFromFile) { {32, 48}, {1, 128}, {8, static_cast(sysRegisterEnums.size())}, - {256, 16}}; + {256, 16}, + {64, 1}}; EXPECT_EQ(simeng::config::SimInfo::getPhysRegStruct(), physRegStruct); std::vector physRegQuants = { - 96, 128, 48, 128, static_cast(sysRegisterEnums.size()), 16}; + 96, 128, 48, 128, static_cast(sysRegisterEnums.size()), 16, 1}; EXPECT_EQ(simeng::config::SimInfo::getPhysRegQuantities(), physRegQuants); } // getPhysRegStruct() diff --git a/test/regression/RegressionTest.cc b/test/regression/RegressionTest.cc index 216a2c9297..4d2de4e440 100644 --- a/test/regression/RegressionTest.cc +++ b/test/regression/RegressionTest.cc @@ -239,8 +239,13 @@ void RegressionTest::assemble(const char* source, const char* triple, ASSERT_NE(asmBackend, nullptr) << "Failed to create LLVM asm backend"; // Create MC code emitter +#if SIMENG_LLVM_VERSION < 15 std::unique_ptr codeEmitter( target->createMCCodeEmitter(*instrInfo, *regInfo, context)); +#else + std::unique_ptr codeEmitter( + target->createMCCodeEmitter(*instrInfo, context)); +#endif ASSERT_NE(codeEmitter, nullptr) << "Failed to create LLVM code emitter"; // Create MC object writer @@ -275,8 +280,14 @@ void RegressionTest::assemble(const char* source, const char* triple, // Create ELF object from output llvm::StringRef objectData = objectStream.str(); +#if SIMENG_LLVM_VERSION < 15 auto elfOrErr = llvm::object::ELFFile< llvm::object::ELFType>::create(objectData); +#else + auto elfOrErr = + llvm::object::ELFFile>::create(objectData); +#endif ASSERT_FALSE(elfOrErr.takeError()) << "Failed to load ELF object"; auto& elf = *elfOrErr; diff --git a/test/regression/RegressionTest.hh b/test/regression/RegressionTest.hh index a110ff80d1..661584cd43 100644 --- a/test/regression/RegressionTest.hh +++ b/test/regression/RegressionTest.hh @@ -44,6 +44,7 @@ #if SIMENG_LLVM_VERSION < 14 #include "llvm/Support/TargetRegistry.h" #else +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #endif diff --git a/test/regression/aarch64/AArch64RegressionTest.hh b/test/regression/aarch64/AArch64RegressionTest.hh index b0774c15c6..32d975b09d 100644 --- a/test/regression/aarch64/AArch64RegressionTest.hh +++ b/test/regression/aarch64/AArch64RegressionTest.hh @@ -16,7 +16,8 @@ FloatingPoint/SVE-Count: 90, Predicate-Count: 17, Conditional-Count: 128, - Matrix-Count: 2, + SME-Matrix-Count: 2, + SME-Lookup-Table-Count: 8, }, L1-Data-Memory: { @@ -162,7 +163,7 @@ inline std::vector> genCoreTypeSVLPairs( * For example: * * // Compare za1h.s[0] to some expected 32-bit floating point values. - * CHECK_MAT_ROW(ARM64_REG_ZAS1, 0, float, {123.456f, 0.f, 42.f, -1.f}); + * CHECK_MAT_ROW(AARCH64_REG_ZAS1, 0, float, {123.456f, 0.f, 42.f, -1.f}); */ #define CHECK_MAT_ROW(tag, index, type, ...) \ { \ @@ -181,7 +182,7 @@ inline std::vector> genCoreTypeSVLPairs( * For example: * * // Compare za1v.s[0] to some expected 32-bit floating point values. - * CHECK_MAT_COL(ARM64_REG_ZAS1, 0, float, {123.456f, 0.f, 42.f, -1.f}); + * CHECK_MAT_COL(AARCH64_REG_ZAS1, 0, float, {123.456f, 0.f, 42.f, -1.f}); */ #define CHECK_MAT_COL(tag, index, type, ...) \ { \ @@ -240,8 +241,10 @@ class AArch64RegressionTest : public RegressionTest { std::string getSubtargetFeaturesString() { #if SIMENG_LLVM_VERSION < 14 return "+sve,+lse"; -#else +#elif SIMENG_LLVM_VERSION < 18 return "+sve,+lse,+sve2,+sme,+sme-f64"; +#else + return "+sve,+lse,+sve2,+sme,+sme-f64f64,+sme-i16i64,+sme2"; #endif } @@ -289,22 +292,22 @@ class AArch64RegressionTest : public RegressionTest { // Get matrix row register tag uint8_t base = 0; uint8_t tileTypeCount = 0; - if (tag == ARM64_REG_ZA || tag == ARM64_REG_ZAB0) { + if (tag == AARCH64_REG_ZA || tag == AARCH64_REG_ZAB0) { // Treat ZA as byte tile : ZAB0 represents whole matrix, only 1 tile // Add all rows for this SVL // Don't need to set base as will always be 0 tileTypeCount = 1; - } else if (tag >= ARM64_REG_ZAH0 && tag <= ARM64_REG_ZAH1) { - base = tag - ARM64_REG_ZAH0; + } else if (tag >= AARCH64_REG_ZAH0 && tag <= AARCH64_REG_ZAH1) { + base = tag - AARCH64_REG_ZAH0; tileTypeCount = 2; - } else if (tag >= ARM64_REG_ZAS0 && tag <= ARM64_REG_ZAS3) { - base = tag - ARM64_REG_ZAS0; + } else if (tag >= AARCH64_REG_ZAS0 && tag <= AARCH64_REG_ZAS3) { + base = tag - AARCH64_REG_ZAS0; tileTypeCount = 4; - } else if (tag >= ARM64_REG_ZAD0 && tag <= ARM64_REG_ZAD7) { - base = tag - ARM64_REG_ZAD0; + } else if (tag >= AARCH64_REG_ZAD0 && tag <= AARCH64_REG_ZAD7) { + base = tag - AARCH64_REG_ZAD0; tileTypeCount = 8; - } else if (tag >= ARM64_REG_ZAQ0 && tag <= ARM64_REG_ZAQ15) { - base = tag - ARM64_REG_ZAQ0; + } else if (tag >= AARCH64_REG_ZAQ0 && tag <= AARCH64_REG_ZAQ15) { + base = tag - AARCH64_REG_ZAQ0; tileTypeCount = 16; } uint16_t reg_tag = base + (index * tileTypeCount); @@ -328,22 +331,22 @@ class AArch64RegressionTest : public RegressionTest { // Get matrix row register tag uint8_t base = 0; uint8_t tileTypeCount = 0; - if (tag == ARM64_REG_ZA || tag == ARM64_REG_ZAB0) { + if (tag == AARCH64_REG_ZA || tag == AARCH64_REG_ZAB0) { // Treat ZA as byte tile : ZAB0 represents whole matrix, only 1 tile // Add all rows for this SVL // Don't need to set base as will always be 0 tileTypeCount = 1; - } else if (tag >= ARM64_REG_ZAH0 && tag <= ARM64_REG_ZAH1) { - base = tag - ARM64_REG_ZAH0; + } else if (tag >= AARCH64_REG_ZAH0 && tag <= AARCH64_REG_ZAH1) { + base = tag - AARCH64_REG_ZAH0; tileTypeCount = 2; - } else if (tag >= ARM64_REG_ZAS0 && tag <= ARM64_REG_ZAS3) { - base = tag - ARM64_REG_ZAS0; + } else if (tag >= AARCH64_REG_ZAS0 && tag <= AARCH64_REG_ZAS3) { + base = tag - AARCH64_REG_ZAS0; tileTypeCount = 4; - } else if (tag >= ARM64_REG_ZAD0 && tag <= ARM64_REG_ZAD7) { - base = tag - ARM64_REG_ZAD0; + } else if (tag >= AARCH64_REG_ZAD0 && tag <= AARCH64_REG_ZAD7) { + base = tag - AARCH64_REG_ZAD0; tileTypeCount = 8; - } else if (tag >= ARM64_REG_ZAQ0 && tag <= ARM64_REG_ZAQ15) { - base = tag - ARM64_REG_ZAQ0; + } else if (tag >= AARCH64_REG_ZAQ0 && tag <= AARCH64_REG_ZAQ15) { + base = tag - AARCH64_REG_ZAQ0; tileTypeCount = 16; } diff --git a/test/regression/aarch64/Exception.cc b/test/regression/aarch64/Exception.cc index 1c90371ddc..b987ae4429 100644 --- a/test/regression/aarch64/Exception.cc +++ b/test/regression/aarch64/Exception.cc @@ -293,7 +293,8 @@ TEST_P(Exception, svcr) { smstart )"); for (uint64_t i = 0; i < (SVL / 8); i++) { - CHECK_MAT_ROW(ARM64_REG_ZA, i, uint32_t, fillNeon({0}, SVL / 8)); + CHECK_MAT_ROW(AARCH64_REG_ZA, i, uint32_t, + fillNeon({0}, SVL / 8)); } // Check that changes to SVCR using msr svcr, xn work correctly @@ -366,7 +367,8 @@ TEST_P(Exception, svcr) { msr svcr, x4 )"); for (uint64_t i = 0; i < (SVL / 8); i++) { - CHECK_MAT_ROW(ARM64_REG_ZA, i, uint32_t, fillNeon({0}, SVL / 8)); + CHECK_MAT_ROW(AARCH64_REG_ZA, i, uint32_t, + fillNeon({0}, SVL / 8)); } } #endif diff --git a/test/regression/aarch64/instructions/comparison.cc b/test/regression/aarch64/instructions/comparison.cc index 9c56501ae4..c91c48ee00 100644 --- a/test/regression/aarch64/instructions/comparison.cc +++ b/test/regression/aarch64/instructions/comparison.cc @@ -109,7 +109,7 @@ TEST_P(InstComparison, cmnw) { )"); EXPECT_EQ(getNZCV(), 0b0110); - EXPECT_GROUP(R"(cmn w0, #0x1)", INT_SIMPLE_ARTH_NOSHIFT); + EXPECT_GROUP(R"(cmn w0, #0x1)", INT_SIMPLE_CMP); } // Test that NZCV flags are set correctly by the 64-bit cmn instruction @@ -136,7 +136,7 @@ TEST_P(InstComparison, cmnx) { )"); EXPECT_EQ(getNZCV(), 0b0110); - EXPECT_GROUP(R"(cmn X0, #0x1)", INT_SIMPLE_ARTH_NOSHIFT); + EXPECT_GROUP(R"(cmn X0, #0x1)", INT_SIMPLE_CMP); } // Test that NZCV flags are set correctly by the 32-bit ccmn instruction @@ -265,7 +265,7 @@ TEST_P(InstComparison, cmpw) { )"); EXPECT_EQ(getNZCV(), 0b0011); - EXPECT_GROUP(R"(cmp w1, #1)", INT_SIMPLE_ARTH_NOSHIFT); + EXPECT_GROUP(R"(cmp w1, #1)", INT_SIMPLE_CMP); } // Test that NZCV flags are set correctly by 64-bit cmp @@ -347,7 +347,7 @@ TEST_P(InstComparison, cmpx) { )"); EXPECT_EQ(getNZCV(), 0b0010); - EXPECT_GROUP(R"(cmp x0, x2, uxtx 4)", INT_SIMPLE_ARTH); + EXPECT_GROUP(R"(cmp x0, x2, uxtx 4)", INT_SIMPLE_CMP); } // Test that NZCV flags are set correctly by 64-bit tst diff --git a/test/regression/aarch64/instructions/sme.cc b/test/regression/aarch64/instructions/sme.cc index e344cc14ee..55c7b945f3 100644 --- a/test/regression/aarch64/instructions/sme.cc +++ b/test/regression/aarch64/instructions/sme.cc @@ -71,9 +71,9 @@ TEST_P(InstSme, fmopa) { fmopa za2.s, p0/m, p2/m, z3.s, z4.s )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, float, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, float, fillNeon({10.0f}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, float, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, float, fillNeon({24.0f}, (SVL / 16))); } @@ -99,9 +99,9 @@ TEST_P(InstSme, fmopa) { fmopa za2.d, p0/m, p2/m, z3.d, z4.d )"); for (uint64_t i = 0; i < (SVL / 64); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAD0, i, double, + CHECK_MAT_ROW(AARCH64_REG_ZAD0, i, double, fillNeon({10.0}, (SVL / 8))); - CHECK_MAT_ROW(ARM64_REG_ZAD2, i, double, + CHECK_MAT_ROW(AARCH64_REG_ZAD2, i, double, fillNeon({24.0}, (SVL / 16))); } } @@ -138,12 +138,12 @@ TEST_P(InstSme, ld1d) { ld1d {za1h.d[w12, 1]}, p1/z, [x0, x2, lsl #3] )"); CHECK_MAT_ROW( - ARM64_REG_ZAD0, 0, uint64_t, + AARCH64_REG_ZAD0, 0, uint64_t, fillNeon({0x98765432ABCDEF01, 0xDEADBEEF12345678}, SVL / 8)); CHECK_MAT_ROW( - ARM64_REG_ZAD0, 1, uint64_t, + AARCH64_REG_ZAD0, 1, uint64_t, fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAD1, 1, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAD1, 1, uint64_t, fillNeonCombined( {0xDEADBEEF12345678, 0x98765432ABCDEF01}, {0}, SVL / 8)); @@ -178,12 +178,12 @@ TEST_P(InstSme, ld1d) { ld1d {za1v.d[w12, 1]}, p1/z, [x0, x2, lsl #3] )"); CHECK_MAT_COL( - ARM64_REG_ZAD0, 0, uint64_t, + AARCH64_REG_ZAD0, 0, uint64_t, fillNeon({0x98765432ABCDEF01, 0xDEADBEEF12345678}, SVL / 8)); CHECK_MAT_COL( - ARM64_REG_ZAD0, 1, uint64_t, + AARCH64_REG_ZAD0, 1, uint64_t, fillNeon({0xDEADBEEF12345678, 0x98765432ABCDEF01}, SVL / 8)); - CHECK_MAT_COL(ARM64_REG_ZAD1, 1, uint64_t, + CHECK_MAT_COL(AARCH64_REG_ZAD1, 1, uint64_t, fillNeonCombined( {0xDEADBEEF12345678, 0x98765432ABCDEF01}, {0}, SVL / 8)); } @@ -220,12 +220,12 @@ TEST_P(InstSme, ld1w) { ld1w {za1h.s[w12, 0]}, p1/z, [x0, x2, lsl #2] )"); CHECK_MAT_ROW( - ARM64_REG_ZAS0, 1, uint64_t, + AARCH64_REG_ZAS0, 1, uint64_t, fillNeon({0x9876543212345678, 0xDEADBEEFABCDEF01}, SVL / 8)); CHECK_MAT_ROW( - ARM64_REG_ZAS0, 3, uint64_t, + AARCH64_REG_ZAS0, 3, uint64_t, fillNeon({0x12345678DEADBEEF, 0xABCDEF0198765432}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAS1, 1, uint64_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS1, 1, uint64_t, fillNeonCombined( {0x12345678DEADBEEF, 0xABCDEF0198765432}, {0}, SVL / 8)); @@ -260,14 +260,14 @@ TEST_P(InstSme, ld1w) { whilelo p1.s, xzr, x1 ld1w {za1v.s[w12, 0]}, p1/z, [x0, x2, lsl #2] )"); - CHECK_MAT_COL(ARM64_REG_ZAS0, 1, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, 1, uint32_t, fillNeon( {0x12345678, 0x98765432, 0xABCDEF01, 0xDEADBEEF}, SVL / 8)); - CHECK_MAT_COL(ARM64_REG_ZAS0, 3, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS0, 3, uint32_t, fillNeon( {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); CHECK_MAT_COL( - ARM64_REG_ZAS1, 1, uint32_t, + AARCH64_REG_ZAS1, 1, uint32_t, fillNeonCombined( {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, {0}, SVL / 8)); } @@ -526,7 +526,8 @@ TEST_P(InstSme, zero) { zero {za} )"); for (uint64_t i = 0; i < (SVL / 8); i++) { - CHECK_MAT_ROW(ARM64_REG_ZA, i, uint64_t, fillNeon({0}, SVL / 8)); + CHECK_MAT_ROW(AARCH64_REG_ZA, i, uint64_t, + fillNeon({0}, SVL / 8)); } initialHeapData_.resize(SVL / 4); @@ -562,12 +563,12 @@ TEST_P(InstSme, zero) { zero {za0.s, za2.s} )"); for (uint64_t i = 0; i < (SVL / 32); i++) { - CHECK_MAT_ROW(ARM64_REG_ZAS0, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS0, i, uint32_t, fillNeon({0}, SVL / 8)); - CHECK_MAT_ROW(ARM64_REG_ZAS2, i, uint32_t, + CHECK_MAT_ROW(AARCH64_REG_ZAS2, i, uint32_t, fillNeon({0}, SVL / 8)); } - CHECK_MAT_COL(ARM64_REG_ZAS1, 3, uint32_t, + CHECK_MAT_COL(AARCH64_REG_ZAS1, 3, uint32_t, fillNeon( {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}, SVL / 8)); } diff --git a/test/regression/aarch64/instructions/sve.cc b/test/regression/aarch64/instructions/sve.cc index a7cee561e3..6a52d46b95 100644 --- a/test/regression/aarch64/instructions/sve.cc +++ b/test/regression/aarch64/instructions/sve.cc @@ -8010,7 +8010,7 @@ TEST_P(InstSve, zip) { } #if SIMENG_LLVM_VERSION >= 14 -// If LLVm version supports SVE2 : +// If LLVM version supports SVE2 : TEST_P(InstSve, psel) { RUN_AARCH64(R"( mov w13, #0 diff --git a/test/unit/aarch64/ArchInfoTest.cc b/test/unit/aarch64/ArchInfoTest.cc index 13978639e5..39e25a0bd1 100644 --- a/test/unit/aarch64/ArchInfoTest.cc +++ b/test/unit/aarch64/ArchInfoTest.cc @@ -16,14 +16,14 @@ class AArch64ArchInfoTest : public ::testing::Test { protected: const std::vector sysRegisterEnums = { - arm64_sysreg::ARM64_SYSREG_DCZID_EL0, - arm64_sysreg::ARM64_SYSREG_FPCR, - arm64_sysreg::ARM64_SYSREG_FPSR, - arm64_sysreg::ARM64_SYSREG_TPIDR_EL0, - arm64_sysreg::ARM64_SYSREG_MIDR_EL1, - arm64_sysreg::ARM64_SYSREG_CNTVCT_EL0, - arm64_sysreg::ARM64_SYSREG_PMCCNTR_EL0, - arm64_sysreg::ARM64_SYSREG_SVCR}; + aarch64_sysreg::AARCH64_SYSREG_DCZID_EL0, + aarch64_sysreg::AARCH64_SYSREG_FPCR, + aarch64_sysreg::AARCH64_SYSREG_FPSR, + aarch64_sysreg::AARCH64_SYSREG_TPIDR_EL0, + aarch64_sysreg::AARCH64_SYSREG_MIDR_EL1, + aarch64_sysreg::AARCH64_SYSREG_CNTVCT_EL0, + aarch64_sysreg::AARCH64_SYSREG_PMCCNTR_EL0, + aarch64_sysreg::AARCH64_SYSREG_SVCR}; const std::vector archRegStruct = { {8, 32}, @@ -31,7 +31,8 @@ class AArch64ArchInfoTest : public ::testing::Test { {32, 17}, {1, 1}, {8, static_cast(sysRegisterEnums.size())}, - {256, 64}}; + {256, 64}, + {64, 1}}; const std::vector physRegStruct = { {8, 96}, @@ -39,10 +40,11 @@ class AArch64ArchInfoTest : public ::testing::Test { {32, 48}, {1, 128}, {8, static_cast(sysRegisterEnums.size())}, - {256, 128}}; + {256, 128}, + {64, 8}}; const std::vector physRegQuants = { - 96, 128, 48, 128, static_cast(sysRegisterEnums.size()), 128}; + 96, 128, 48, 128, static_cast(sysRegisterEnums.size()), 128, 8}; }; // Test for the getSysRegEnums() function diff --git a/test/unit/aarch64/ArchitectureTest.cc b/test/unit/aarch64/ArchitectureTest.cc index 7ad5fcacf4..dbc1fa65ac 100644 --- a/test/unit/aarch64/ArchitectureTest.cc +++ b/test/unit/aarch64/ArchitectureTest.cc @@ -125,7 +125,7 @@ TEST_F(AArch64ArchitectureTest, getSystemRegisterTag) { EXPECT_EQ(output, -1); // Test for correct behaviour - output = arch->getSystemRegisterTag(ARM64_SYSREG_DCZID_EL0); + output = arch->getSystemRegisterTag(AARCH64_SYSREG_DCZID_EL0); EXPECT_EQ(output, 0); } @@ -162,7 +162,7 @@ TEST_F(AArch64ArchitectureTest, getInitialState) { std::vector regs = { {RegisterType::GENERAL, 31}, {RegisterType::SYSTEM, - (uint16_t)arch->getSystemRegisterTag(ARM64_SYSREG_DCZID_EL0)}}; + (uint16_t)arch->getSystemRegisterTag(AARCH64_SYSREG_DCZID_EL0)}}; std::vector regVals = {{kernel.getInitialStackPointer(), 8}, {20, 8}}; @@ -202,13 +202,13 @@ TEST_F(AArch64ArchitectureTest, updateSystemTimerRegisters) { EXPECT_EQ( regFile .get({RegisterType::SYSTEM, (uint16_t)arch->getSystemRegisterTag( - ARM64_SYSREG_PMCCNTR_EL0)}) + AARCH64_SYSREG_PMCCNTR_EL0)}) .get(), i); EXPECT_EQ( regFile .get({RegisterType::SYSTEM, (uint16_t)arch->getSystemRegisterTag( - ARM64_SYSREG_CNTVCT_EL0)}) + AARCH64_SYSREG_CNTVCT_EL0)}) .get(), vctCount); } diff --git a/test/unit/aarch64/AuxiliaryFunctionsTest.cc b/test/unit/aarch64/AuxiliaryFunctionsTest.cc index dd18b16a31..f319b55dbb 100644 --- a/test/unit/aarch64/AuxiliaryFunctionsTest.cc +++ b/test/unit/aarch64/AuxiliaryFunctionsTest.cc @@ -240,19 +240,19 @@ TEST(AArch64AuxiliaryFunctionTest, ConditionHolds) { /** `extendValue` Tests */ TEST(AArch64AuxiliaryFunctionTest, ExtendValue) { // Test special case - EXPECT_EQ(extendValue(123, ARM64_EXT_INVALID, 0), 123); + EXPECT_EQ(extendValue(123, AARCH64_EXT_INVALID, 0), 123); // Results validated on XCI and A64FX hardware - EXPECT_EQ(extendValue(270, ARM64_EXT_UXTB, 3), 112); - EXPECT_EQ(extendValue(65560, ARM64_EXT_UXTH, 3), 192); - EXPECT_EQ(extendValue(0xFFFFFFFF, ARM64_EXT_UXTW, 3), 34359738360); - EXPECT_EQ(extendValue(0x0F0F0F0F0F0F0F01, ARM64_EXT_UXTX, 4), + EXPECT_EQ(extendValue(270, AARCH64_EXT_UXTB, 3), 112); + EXPECT_EQ(extendValue(65560, AARCH64_EXT_UXTH, 3), 192); + EXPECT_EQ(extendValue(0xFFFFFFFF, AARCH64_EXT_UXTW, 3), 34359738360); + EXPECT_EQ(extendValue(0x0F0F0F0F0F0F0F01, AARCH64_EXT_UXTX, 4), 0xF0F0F0F0F0F0F010); - EXPECT_EQ(extendValue(133, ARM64_EXT_SXTB, 3), -984); - EXPECT_EQ(extendValue(32768, ARM64_EXT_SXTH, 3), -262144); - EXPECT_EQ(extendValue(2147483648, ARM64_EXT_SXTW, 3), -17179869184); - EXPECT_EQ(extendValue(0x8000000000000000, ARM64_EXT_SXTX, 3), 0); + EXPECT_EQ(extendValue(133, AARCH64_EXT_SXTB, 3), -984); + EXPECT_EQ(extendValue(32768, AARCH64_EXT_SXTH, 3), -262144); + EXPECT_EQ(extendValue(2147483648, AARCH64_EXT_SXTW, 3), -17179869184); + EXPECT_EQ(extendValue(0x8000000000000000, AARCH64_EXT_SXTX, 3), 0); } /** `getNZCVfromPred` Tests */ @@ -344,361 +344,351 @@ TEST(AArch64AuxiliaryFunctionTest, Mulhi) { EXPECT_EQ(mulhi(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFF), 0xFFFFFFFE); } -/** `sveGetPattern` Tests */ -TEST(AArch64AuxiliaryFunctionTest, sveGetPattern) { +/** `getElemsFromPattern` Tests */ +TEST(AArch64AuxiliaryFunctionTest, getElemsFromPattern) { uint16_t vl = 128; - EXPECT_EQ(sveGetPattern("", 64, vl), 2); - EXPECT_EQ(sveGetPattern("", 16, vl), 8); - EXPECT_EQ(sveGetPattern("all", 64, vl), 2); - EXPECT_EQ(sveGetPattern("all", 16, vl), 8); - EXPECT_EQ(sveGetPattern("notValid", 64, vl), 2); - EXPECT_EQ(sveGetPattern("notValid", 16, vl), 8); - - EXPECT_EQ(sveGetPattern("vl1", 64, vl), 1); - EXPECT_EQ(sveGetPattern("vl2", 64, vl), 2); - EXPECT_EQ(sveGetPattern("vl3", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl4", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl5", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl6", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl7", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl8", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl16", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl32", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl64", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl128", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl256", 64, vl), 0); - - EXPECT_EQ(sveGetPattern("mul4", 8, vl), 16); - EXPECT_EQ(sveGetPattern("mul3", 8, vl), 15); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 64, vl), 2); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 16, vl), 8); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL1, 64, vl), 1); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL2, 64, vl), 2); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL3, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL4, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL5, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL6, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL7, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL8, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL16, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL32, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL64, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL128, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL256, 64, vl), 0); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL4, 8, vl), 16); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL3, 8, vl), 15); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_POW2, 8, vl), 16); vl = 256; - EXPECT_EQ(sveGetPattern("", 64, vl), 4); - EXPECT_EQ(sveGetPattern("", 16, vl), 16); - EXPECT_EQ(sveGetPattern("all", 64, vl), 4); - EXPECT_EQ(sveGetPattern("all", 16, vl), 16); - EXPECT_EQ(sveGetPattern("notValid", 64, vl), 4); - EXPECT_EQ(sveGetPattern("notValid", 16, vl), 16); - - EXPECT_EQ(sveGetPattern("vl1", 64, vl), 1); - EXPECT_EQ(sveGetPattern("vl2", 64, vl), 2); - EXPECT_EQ(sveGetPattern("vl3", 64, vl), 3); - EXPECT_EQ(sveGetPattern("vl4", 64, vl), 4); - EXPECT_EQ(sveGetPattern("vl5", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl6", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl7", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl8", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl16", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl32", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl64", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl128", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl256", 64, vl), 0); - - EXPECT_EQ(sveGetPattern("mul4", 8, vl), 32); - EXPECT_EQ(sveGetPattern("mul3", 8, vl), 30); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 64, vl), 4); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 16, vl), 16); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL1, 64, vl), 1); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL2, 64, vl), 2); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL3, 64, vl), 3); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL4, 64, vl), 4); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL5, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL6, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL7, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL8, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL16, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL32, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL64, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL128, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL256, 64, vl), 0); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL4, 8, vl), 32); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL3, 8, vl), 30); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_POW2, 8, vl), 32); vl = 512; - EXPECT_EQ(sveGetPattern("", 64, vl), 8); - EXPECT_EQ(sveGetPattern("", 16, vl), 32); - EXPECT_EQ(sveGetPattern("all", 64, vl), 8); - EXPECT_EQ(sveGetPattern("all", 16, vl), 32); - EXPECT_EQ(sveGetPattern("notValid", 64, vl), 8); - EXPECT_EQ(sveGetPattern("notValid", 16, vl), 32); - - EXPECT_EQ(sveGetPattern("vl1", 64, vl), 1); - EXPECT_EQ(sveGetPattern("vl2", 64, vl), 2); - EXPECT_EQ(sveGetPattern("vl3", 64, vl), 3); - EXPECT_EQ(sveGetPattern("vl4", 64, vl), 4); - EXPECT_EQ(sveGetPattern("vl5", 64, vl), 5); - EXPECT_EQ(sveGetPattern("vl6", 64, vl), 6); - EXPECT_EQ(sveGetPattern("vl7", 64, vl), 7); - EXPECT_EQ(sveGetPattern("vl8", 64, vl), 8); - EXPECT_EQ(sveGetPattern("vl16", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl32", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl64", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl128", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl256", 64, vl), 0); - - EXPECT_EQ(sveGetPattern("mul4", 8, vl), 64); - EXPECT_EQ(sveGetPattern("mul3", 8, vl), 63); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 64, vl), 8); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 16, vl), 32); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL1, 64, vl), 1); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL2, 64, vl), 2); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL3, 64, vl), 3); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL4, 64, vl), 4); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL5, 64, vl), 5); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL6, 64, vl), 6); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL7, 64, vl), 7); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL8, 64, vl), 8); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL16, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL32, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL64, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL128, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL256, 64, vl), 0); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL4, 8, vl), 64); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL3, 8, vl), 63); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_POW2, 8, vl), 64); vl = 1024; - EXPECT_EQ(sveGetPattern("", 64, vl), 16); - EXPECT_EQ(sveGetPattern("", 16, vl), 64); - EXPECT_EQ(sveGetPattern("all", 64, vl), 16); - EXPECT_EQ(sveGetPattern("all", 16, vl), 64); - EXPECT_EQ(sveGetPattern("notValid", 64, vl), 16); - EXPECT_EQ(sveGetPattern("notValid", 16, vl), 64); - - EXPECT_EQ(sveGetPattern("vl1", 64, vl), 1); - EXPECT_EQ(sveGetPattern("vl2", 64, vl), 2); - EXPECT_EQ(sveGetPattern("vl3", 64, vl), 3); - EXPECT_EQ(sveGetPattern("vl4", 64, vl), 4); - EXPECT_EQ(sveGetPattern("vl5", 64, vl), 5); - EXPECT_EQ(sveGetPattern("vl6", 64, vl), 6); - EXPECT_EQ(sveGetPattern("vl7", 64, vl), 7); - EXPECT_EQ(sveGetPattern("vl8", 64, vl), 8); - EXPECT_EQ(sveGetPattern("vl16", 64, vl), 16); - EXPECT_EQ(sveGetPattern("vl32", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl64", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl128", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl256", 64, vl), 0); - - EXPECT_EQ(sveGetPattern("mul4", 8, vl), 128); - EXPECT_EQ(sveGetPattern("mul3", 8, vl), 126); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 64, vl), 16); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 16, vl), 64); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL1, 64, vl), 1); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL2, 64, vl), 2); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL3, 64, vl), 3); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL4, 64, vl), 4); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL5, 64, vl), 5); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL6, 64, vl), 6); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL7, 64, vl), 7); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL8, 64, vl), 8); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL16, 64, vl), 16); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL32, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL64, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL128, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL256, 64, vl), 0); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL4, 8, vl), 128); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL3, 8, vl), 126); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_POW2, 8, vl), 128); vl = 2048; - EXPECT_EQ(sveGetPattern("", 64, vl), 32); - EXPECT_EQ(sveGetPattern("", 16, vl), 128); - EXPECT_EQ(sveGetPattern("all", 64, vl), 32); - EXPECT_EQ(sveGetPattern("all", 16, vl), 128); - EXPECT_EQ(sveGetPattern("notValid", 64, vl), 32); - EXPECT_EQ(sveGetPattern("notValid", 16, vl), 128); - - EXPECT_EQ(sveGetPattern("vl1", 64, vl), 1); - EXPECT_EQ(sveGetPattern("vl2", 64, vl), 2); - EXPECT_EQ(sveGetPattern("vl3", 64, vl), 3); - EXPECT_EQ(sveGetPattern("vl4", 64, vl), 4); - EXPECT_EQ(sveGetPattern("vl5", 64, vl), 5); - EXPECT_EQ(sveGetPattern("vl6", 64, vl), 6); - EXPECT_EQ(sveGetPattern("vl7", 64, vl), 7); - EXPECT_EQ(sveGetPattern("vl8", 64, vl), 8); - EXPECT_EQ(sveGetPattern("vl16", 64, vl), 16); - EXPECT_EQ(sveGetPattern("vl32", 64, vl), 32); - EXPECT_EQ(sveGetPattern("vl64", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl128", 64, vl), 0); - EXPECT_EQ(sveGetPattern("vl256", 64, vl), 0); - - EXPECT_EQ(sveGetPattern("mul4", 8, vl), 256); - EXPECT_EQ(sveGetPattern("mul3", 8, vl), 255); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 64, vl), 32); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_ALL, 16, vl), 128); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL1, 64, vl), 1); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL2, 64, vl), 2); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL3, 64, vl), 3); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL4, 64, vl), 4); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL5, 64, vl), 5); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL6, 64, vl), 6); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL7, 64, vl), 7); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL8, 64, vl), 8); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL16, 64, vl), 16); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL32, 64, vl), 32); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL64, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL128, 64, vl), 0); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_VL256, 64, vl), 0); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL4, 8, vl), 256); + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_MUL3, 8, vl), 255); + + EXPECT_EQ(getElemsFromPattern(AARCH64_SVEPREDPAT_POW2, 8, vl), 256); } /** `ShiftValue` Tests */ TEST(AArch64AuxiliaryFunctionTest, ShiftValueTest_LSL) { // 8-bit const uint8_t a = 0x0F; - EXPECT_EQ(shiftValue(a, ARM64_SFT_LSL, 4), 0xF0); + EXPECT_EQ(shiftValue(a, AARCH64_SFT_LSL, 4), 0xF0); const uint8_t b = 0xF0; - EXPECT_EQ(shiftValue(b, ARM64_SFT_LSL, 7), 0x00); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_LSL, 7), 0x00); - EXPECT_EQ(shiftValue(b, ARM64_SFT_LSL, 0), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_LSL, 0), b); // 16-bit const uint16_t c = 0x00FF; - EXPECT_EQ(shiftValue(c, ARM64_SFT_LSL, 8), 0xFF00); + EXPECT_EQ(shiftValue(c, AARCH64_SFT_LSL, 8), 0xFF00); const uint16_t d = 0xFF00; - EXPECT_EQ(shiftValue(d, ARM64_SFT_LSL, 15), 0x0000); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_LSL, 15), 0x0000); - EXPECT_EQ(shiftValue(d, ARM64_SFT_LSL, 0), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_LSL, 0), d); // 32-bit const uint32_t e = 0x0000FFFF; - EXPECT_EQ(shiftValue(e, ARM64_SFT_LSL, 16), 0xFFFF0000); + EXPECT_EQ(shiftValue(e, AARCH64_SFT_LSL, 16), 0xFFFF0000); const uint32_t f = 0xFFFF0000; - EXPECT_EQ(shiftValue(f, ARM64_SFT_LSL, 31), 0x00000000); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_LSL, 31), 0x00000000); - EXPECT_EQ(shiftValue(f, ARM64_SFT_LSL, 0), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_LSL, 0), f); // 64-bit const uint64_t g = 0x00000000FFFFFFFF; - EXPECT_EQ(shiftValue(g, ARM64_SFT_LSL, 32), 0xFFFFFFFF00000000); + EXPECT_EQ(shiftValue(g, AARCH64_SFT_LSL, 32), 0xFFFFFFFF00000000); const uint64_t h = 0xFFFFFFFF00000000; - EXPECT_EQ(shiftValue(h, ARM64_SFT_LSL, 63), 0x0000000000000000); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_LSL, 63), 0x0000000000000000); - EXPECT_EQ(shiftValue(h, ARM64_SFT_LSL, 0), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_LSL, 0), h); } TEST(AArch64AuxiliaryFunctionTest, ShiftValueTest_LSR) { // 8-bit const uint8_t a = 0x0F; - EXPECT_EQ(shiftValue(a, ARM64_SFT_LSR, 4), 0x00); + EXPECT_EQ(shiftValue(a, AARCH64_SFT_LSR, 4), 0x00); const uint8_t b = 0xF0; - EXPECT_EQ(shiftValue(b, ARM64_SFT_LSR, 7), 0x01); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_LSR, 7), 0x01); - EXPECT_EQ(shiftValue(b, ARM64_SFT_LSR, 0), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_LSR, 0), b); // 16-bit const uint16_t c = 0x00FF; - EXPECT_EQ(shiftValue(c, ARM64_SFT_LSR, 8), 0x0); + EXPECT_EQ(shiftValue(c, AARCH64_SFT_LSR, 8), 0x0); const uint16_t d = 0xFF00; - EXPECT_EQ(shiftValue(d, ARM64_SFT_LSR, 15), 0x0001); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_LSR, 15), 0x0001); - EXPECT_EQ(shiftValue(d, ARM64_SFT_LSR, 0), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_LSR, 0), d); // 32-bit const uint32_t e = 0x0000FFFF; - EXPECT_EQ(shiftValue(e, ARM64_SFT_LSR, 16), 0x00000000); + EXPECT_EQ(shiftValue(e, AARCH64_SFT_LSR, 16), 0x00000000); const uint32_t f = 0xFFFF0000; - EXPECT_EQ(shiftValue(f, ARM64_SFT_LSR, 31), 0x00000001); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_LSR, 31), 0x00000001); - EXPECT_EQ(shiftValue(f, ARM64_SFT_LSR, 0), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_LSR, 0), f); // 64-bit const uint64_t g = 0x00000000FFFFFFFF; - EXPECT_EQ(shiftValue(g, ARM64_SFT_LSR, 32), 0x0000000000000000); + EXPECT_EQ(shiftValue(g, AARCH64_SFT_LSR, 32), 0x0000000000000000); const uint64_t h = 0xFFFFFFFF00000000; - EXPECT_EQ(shiftValue(h, ARM64_SFT_LSR, 63), 0x0000000000000001); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_LSR, 63), 0x0000000000000001); - EXPECT_EQ(shiftValue(h, ARM64_SFT_LSR, 0), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_LSR, 0), h); } TEST(AArch64AuxiliaryFunctionTest, ShiftValueTest_ASR) { // 8-bit const uint8_t a = 0x0F; - EXPECT_EQ(shiftValue(a, ARM64_SFT_ASR, 4), 0x00); + EXPECT_EQ(shiftValue(a, AARCH64_SFT_ASR, 4), 0x00); const uint8_t b = 0xF0; - EXPECT_EQ(shiftValue(b, ARM64_SFT_ASR, 7), 0xFF); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_ASR, 7), 0xFF); - EXPECT_EQ(shiftValue(b, ARM64_SFT_ASR, 0), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_ASR, 0), b); // 16-bit const uint16_t c = 0x00FF; - EXPECT_EQ(shiftValue(c, ARM64_SFT_ASR, 8), 0x0000); + EXPECT_EQ(shiftValue(c, AARCH64_SFT_ASR, 8), 0x0000); const uint16_t d = 0xFF00; - EXPECT_EQ(shiftValue(d, ARM64_SFT_ASR, 15), 0xFFFF); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_ASR, 15), 0xFFFF); - EXPECT_EQ(shiftValue(d, ARM64_SFT_ASR, 0), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_ASR, 0), d); // 32-bit const uint32_t e = 0x0000FFFF; - EXPECT_EQ(shiftValue(e, ARM64_SFT_ASR, 16), 0x00000000); + EXPECT_EQ(shiftValue(e, AARCH64_SFT_ASR, 16), 0x00000000); const uint32_t f = 0xFFFF0000; - EXPECT_EQ(shiftValue(f, ARM64_SFT_ASR, 31), 0xFFFFFFFF); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_ASR, 31), 0xFFFFFFFF); - EXPECT_EQ(shiftValue(f, ARM64_SFT_ASR, 0), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_ASR, 0), f); // 64-bit const uint64_t g = 0x00000000FFFFFFFF; - EXPECT_EQ(shiftValue(g, ARM64_SFT_ASR, 32), 0x0000000000000000); + EXPECT_EQ(shiftValue(g, AARCH64_SFT_ASR, 32), 0x0000000000000000); const uint64_t h = 0xFFFFFFFF00000000; - EXPECT_EQ(shiftValue(h, ARM64_SFT_ASR, 63), 0xFFFFFFFFFFFFFFFF); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_ASR, 63), 0xFFFFFFFFFFFFFFFF); - EXPECT_EQ(shiftValue(h, ARM64_SFT_ASR, 0), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_ASR, 0), h); } TEST(AArch64AuxiliaryFunctionTest, ShiftValueTest_ROR) { // 8-bit const uint8_t a = 0x0F; - EXPECT_EQ(shiftValue(a, ARM64_SFT_ROR, 4), 0xF0); + EXPECT_EQ(shiftValue(a, AARCH64_SFT_ROR, 4), 0xF0); const uint8_t b = 0xF0; - EXPECT_EQ(shiftValue(b, ARM64_SFT_ROR, 7), 0xE1); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_ROR, 7), 0xE1); - EXPECT_EQ(shiftValue(b, ARM64_SFT_ROR, 0), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_ROR, 0), b); // 16-bit const uint16_t c = 0x00FF; - EXPECT_EQ(shiftValue(c, ARM64_SFT_ROR, 8), 0xFF00); + EXPECT_EQ(shiftValue(c, AARCH64_SFT_ROR, 8), 0xFF00); const uint16_t d = 0xFF00; - EXPECT_EQ(shiftValue(d, ARM64_SFT_ROR, 15), 0xFE01); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_ROR, 15), 0xFE01); - EXPECT_EQ(shiftValue(d, ARM64_SFT_ROR, 0), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_ROR, 0), d); // 32-bit const uint32_t e = 0x0000FFFF; - EXPECT_EQ(shiftValue(e, ARM64_SFT_ROR, 16), 0xFFFF0000); + EXPECT_EQ(shiftValue(e, AARCH64_SFT_ROR, 16), 0xFFFF0000); const uint32_t f = 0xFFFF0000; - EXPECT_EQ(shiftValue(f, ARM64_SFT_ROR, 31), 0xFFFE0001); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_ROR, 31), 0xFFFE0001); - EXPECT_EQ(shiftValue(f, ARM64_SFT_ROR, 0), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_ROR, 0), f); // 64-bit const uint64_t g = 0x00000000FFFFFFFF; - EXPECT_EQ(shiftValue(g, ARM64_SFT_ROR, 32), 0xFFFFFFFF00000000); + EXPECT_EQ(shiftValue(g, AARCH64_SFT_ROR, 32), 0xFFFFFFFF00000000); const uint64_t h = 0xFFFFFFFF00000000; - EXPECT_EQ(shiftValue(h, ARM64_SFT_ROR, 63), 0xFFFFFFFE00000001); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_ROR, 63), 0xFFFFFFFE00000001); - EXPECT_EQ(shiftValue(h, ARM64_SFT_ROR, 0), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_ROR, 0), h); } TEST(AArch64AuxiliaryFunctionTest, ShiftValueTest_MSL) { // 8-bit const uint8_t a = 0x0F; - EXPECT_EQ(shiftValue(a, ARM64_SFT_MSL, 4), 0xFF); + EXPECT_EQ(shiftValue(a, AARCH64_SFT_MSL, 4), 0xFF); const uint8_t b = 0xF0; - EXPECT_EQ(shiftValue(b, ARM64_SFT_MSL, 7), 0x7F); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_MSL, 7), 0x7F); - EXPECT_EQ(shiftValue(b, ARM64_SFT_MSL, 0), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_MSL, 0), b); // 16-bit const uint16_t c = 0x00FF; - EXPECT_EQ(shiftValue(c, ARM64_SFT_MSL, 8), 0xFFFF); + EXPECT_EQ(shiftValue(c, AARCH64_SFT_MSL, 8), 0xFFFF); const uint16_t d = 0xFF00; - EXPECT_EQ(shiftValue(d, ARM64_SFT_MSL, 15), 0x7FFF); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_MSL, 15), 0x7FFF); - EXPECT_EQ(shiftValue(d, ARM64_SFT_MSL, 0), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_MSL, 0), d); // 32-bit const uint32_t e = 0x0000FFFF; - EXPECT_EQ(shiftValue(e, ARM64_SFT_MSL, 16), 0xFFFFFFFF); + EXPECT_EQ(shiftValue(e, AARCH64_SFT_MSL, 16), 0xFFFFFFFF); const uint32_t f = 0xFFFF0000; - EXPECT_EQ(shiftValue(f, ARM64_SFT_MSL, 31), 0x7FFFFFFF); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_MSL, 31), 0x7FFFFFFF); - EXPECT_EQ(shiftValue(f, ARM64_SFT_MSL, 0), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_MSL, 0), f); // 64-bit const uint64_t g = 0x00000000FFFFFFFF; - EXPECT_EQ(shiftValue(g, ARM64_SFT_MSL, 32), 0xFFFFFFFFFFFFFFFF); + EXPECT_EQ(shiftValue(g, AARCH64_SFT_MSL, 32), 0xFFFFFFFFFFFFFFFF); const uint64_t h = 0xFFFFFFFF00000000; - EXPECT_EQ(shiftValue(h, ARM64_SFT_MSL, 63), 0x7FFFFFFFFFFFFFFF); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_MSL, 63), 0x7FFFFFFFFFFFFFFF); - EXPECT_EQ(shiftValue(h, ARM64_SFT_MSL, 0), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_MSL, 0), h); } TEST(AArch64AuxiliaryFunctionTest, ShiftValueTest_INVALID) { // 8-bit const uint8_t a = 0x0F; - EXPECT_EQ(shiftValue(a, ARM64_SFT_INVALID, 4), a); + EXPECT_EQ(shiftValue(a, AARCH64_SFT_INVALID, 4), a); const uint8_t b = 0xF0; - EXPECT_EQ(shiftValue(b, ARM64_SFT_INVALID, 7), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_INVALID, 7), b); - EXPECT_EQ(shiftValue(b, ARM64_SFT_INVALID, 0), b); + EXPECT_EQ(shiftValue(b, AARCH64_SFT_INVALID, 0), b); // 16-bit const uint16_t c = 0x00FF; - EXPECT_EQ(shiftValue(c, ARM64_SFT_INVALID, 8), c); + EXPECT_EQ(shiftValue(c, AARCH64_SFT_INVALID, 8), c); const uint16_t d = 0xFF00; - EXPECT_EQ(shiftValue(d, ARM64_SFT_INVALID, 15), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_INVALID, 15), d); - EXPECT_EQ(shiftValue(d, ARM64_SFT_INVALID, 0), d); + EXPECT_EQ(shiftValue(d, AARCH64_SFT_INVALID, 0), d); // 32-bit const uint32_t e = 0x0000FFFF; - EXPECT_EQ(shiftValue(e, ARM64_SFT_INVALID, 16), e); + EXPECT_EQ(shiftValue(e, AARCH64_SFT_INVALID, 16), e); const uint32_t f = 0xFFFF0000; - EXPECT_EQ(shiftValue(f, ARM64_SFT_INVALID, 31), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_INVALID, 31), f); - EXPECT_EQ(shiftValue(f, ARM64_SFT_INVALID, 0), f); + EXPECT_EQ(shiftValue(f, AARCH64_SFT_INVALID, 0), f); // 64-bit const uint64_t g = 0x00000000FFFFFFFF; - EXPECT_EQ(shiftValue(g, ARM64_SFT_INVALID, 32), g); + EXPECT_EQ(shiftValue(g, AARCH64_SFT_INVALID, 32), g); const uint64_t h = 0xFFFFFFFF00000000; - EXPECT_EQ(shiftValue(h, ARM64_SFT_INVALID, 63), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_INVALID, 63), h); - EXPECT_EQ(shiftValue(h, ARM64_SFT_INVALID, 0), h); + EXPECT_EQ(shiftValue(h, AARCH64_SFT_INVALID, 0), h); } } // namespace aarch64 diff --git a/test/unit/aarch64/ExceptionHandlerTest.cc b/test/unit/aarch64/ExceptionHandlerTest.cc index b64e1bfbee..26e6f8dc7a 100644 --- a/test/unit/aarch64/ExceptionHandlerTest.cc +++ b/test/unit/aarch64/ExceptionHandlerTest.cc @@ -447,24 +447,6 @@ TEST_F(AArch64ExceptionHandlerTest, printException) { buffer.str(std::string()); uops.clear(); - // Create instruction for AliasNotYetImplemented - arch.predecode(validInstrBytes.data(), validInstrBytes.size(), insnAddr, - uops); - exception = InstructionException::AliasNotYetImplemented; - insn = std::make_shared( - arch, static_cast(uops[0].get())->getMetadata(), exception); - // Create ExceptionHandler - ExceptionHandler handler_2(insn, core, memory, kernel); - // Capture std::cout and tick exceptionHandler - sbuf = std::cout.rdbuf(); // Save cout's buffer - std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to buffer - handler_2.printException(*static_cast(insn.get())); - std::cout.rdbuf(sbuf); // Restore cout - EXPECT_THAT(buffer.str(), HasSubstr("[SimEng:ExceptionHandler] Encountered " - "alias not-yet-implemented exception")); - buffer.str(std::string()); - uops.clear(); - // Create instruction for MisalignedPC arch.predecode(validInstrBytes.data(), validInstrBytes.size(), insnAddr, uops); diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 92b8e9393a..1ecf14a1a6 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -16,7 +16,7 @@ class AArch64InstructionTest : public testing::Test { .as()), arch(os) { // Create InstructionMetadata objects - cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &capstoneHandle); + cs_open(CS_ARCH_AARCH64, CS_MODE_ARM, &capstoneHandle); cs_option(capstoneHandle, CS_OPT_DETAIL, CS_OPT_ON); // Create instructions which cover the 3 main types: Arithmetic, Memory,