diff --git a/.jenkins/build_arm20.sh b/.jenkins/build_arm22.sh similarity index 57% rename from .jenkins/build_arm20.sh rename to .jenkins/build_arm22.sh index 7d96c08793..7b17f220b1 100644 --- a/.jenkins/build_arm20.sh +++ b/.jenkins/build_arm22.sh @@ -6,14 +6,13 @@ source .jenkins/build_test_run.sh checkout ## Setup environment -module load cdt/20.03 export CMAKE_C_COMPILER=cc export CMAKE_CXX_COMPILER=CC ## Load compilers/libraries -echo "Compiler Armclang 20.0" -module swap PrgEnv-cray PrgEnv-allinea -module swap Generic-AArch64/SUSE/12/arm-linux-compiler/20.0 ThunderX2CN99/SUSE/12/arm-linux-compiler-20.0/armpl/20.0.0 +echo "Compiler Armclang 22.0.2" +module use /software/arm64/modulefiles +module load tools/arm-compiler-sles module load tools/cmake ## Build, test, and run SimEng diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index 1f75735135..44a65d01f2 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -51,16 +51,16 @@ run () { echo "Simulation without configuration file argument:" cat run echo "" - compare_outputs "$(tail -n 3 run | head -n 1)" "retired: 3145731" "retired instructions" - compare_outputs "$(tail -n 1 run | cut -c10-16)" "3145738" "simulated ticks" + compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "3145731" "retired instructions" + compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "3145736" "simulated cycles" echo "" ./bin/simeng "$SIMENG_TOP"/configs/tx2.yaml > run echo "Simulation with configuration file argument:" cat run echo "" - compare_outputs "$(tail -n 3 run | head -n 1)" "retired: 3145732" "retired instructions" - compare_outputs "$(tail -n 1 run | cut -c10-16)" "1048593" "simulated ticks" + compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "3145732" "retired instructions" + compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "1048588" "simulated cycles" echo "" } diff --git a/CMakeLists.txt b/CMakeLists.txt index fdfa0b6bff..2ce5ffa13d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,13 +44,17 @@ FetchContent_Declare( ) FetchContent_Declare( - capstone + capstone-lib GIT_REPOSITORY https://github.com/UoB-HPC/capstone.git - GIT_TAG e7be7d99e718ef9741026b80fc6f5e100fdf4f94 # trunk + GIT_TAG Armv9.2-update + GIT_PROGRESS TRUE + + # Old Git tag pre-Armv9.2 + # GIT_TAG e7be7d99e718ef9741026b80fc6f5e100fdf4f94 # trunk ) cmake_policy(SET CMP0048 NEW) -project(SimEng VERSION 0.9.3 LANGUAGES C CXX) +project(SimEng VERSION 0.9.4 LANGUAGES C CXX) # If no build type was defined, default to Release if(NOT CMAKE_BUILD_TYPE) @@ -87,6 +91,7 @@ install(DIRECTORY src/include/simeng set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable Capstone tests") 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_MIPS_SUPPORT OFF CACHE BOOL "Disable MIPS support") @@ -104,7 +109,7 @@ set(CAPSTONE_WASM_SUPPORT OFF CACHE BOOL "Disable WASM support") set(CAPSTONE_BPF_SUPPORT OFF CACHE BOOL "Disable BPF support") set(CAPSTONE_RISCV_SUPPORT OFF CACHE BOOL "Disable RISCV support") -FetchContent_MakeAvailable_Args(capstone EXCLUDE_FROM_ALL) +FetchContent_MakeAvailable_Args(capstone-lib EXCLUDE_FROM_ALL) include_directories("${capstone_BINARY_DIR}/include" "${capstone_SOURCE_DIR}/include") ## Setup yaml-cpp ## @@ -118,7 +123,7 @@ option(SIMENG_USE_EXTERNAL_LLVM "Use an external LLVM rather than building it as option(SIMENG_SANITIZE "Enable compiler sanitizers" OFF) option(SIMENG_OPTIMIZE "Enable Extra Compiler Optimizatoins" OFF) -if(SIMENG_OPTIMIZE) +if (SIMENG_OPTIMIZE) # Turn on link time optimization for all targets. set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) @@ -177,12 +182,17 @@ if(SIMENG_ENABLE_TESTS) # make sure we get the headers too include_directories("${llvm_BINARY_DIR}/include" "${llvm_SOURCE_DIR}/include") - find_package(LLVM REQUIRED CONFIG NO_DEFAULT_PATH + find_package(LLVM REQUIRED CONFIG NO_DEFAULT_PATH PATHS "${llvm_BINARY_DIR}/lib/cmake/llvm") - + # NOTE: we don't do the usual version checks here because it needs vars exported in find_LLVM # we just assume it's good beacuse it must be whitelisted in FetchContent_Declare - + + endif() + + # Check LLVM version + if ((${LLVM_PACKAGE_VERSION} VERSION_LESS "9.0") OR (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL "13.0")) + message(FATAL_ERROR "LLVM version must be >= 9.0 and < 13.0") endif() set(SIMENG_LLVM_VERSION ${LLVM_VERSION_MAJOR} CACHE INTERNAL "LLVM major version number used.") diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index bc0b4622db..a2485e96e1 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,28 +1,26 @@ Major contributors to SimEng to date include: -Project leader - Simon McIntosh-Smith - +Project leader: + Simon McIntosh-Smith + Original SimEng design and implementation: - Hal Jones - James Price + Hal Jones + James Price Current development team: - Jack Jones (lead developer) - Finn Wilkinson - -Prior development members: - Harry Waugh - -Code reviewers: - Andrei Poenaru - -Build structure design: - Tom Lin + Jack Jones (Lead Developer) + Finn Wilkinson + Rahat Muneeb + Daniel Weaver -Internship contributions: - Daniel Weaver - Mutalib Mohammed - Seunghun Lee +Additional Contributors: + Ainsley Rutterford + Andrei Poenaru + Harry Waugh + Mutalib Mohammed + Seunghun Lee + Tom Hepworth + Tom Lin + Will Robinson SimEng's development has been funded by the UKRI/EPSRC ASiMoV project, EP/S005072/1. diff --git a/LICENSE_CAPSTONE.txt b/LICENSE_CAPSTONE.txt new file mode 100644 index 0000000000..0dabdc749e --- /dev/null +++ b/LICENSE_CAPSTONE.txt @@ -0,0 +1,31 @@ +This is the software license for Capstone disassembly framework. +Capstone has been designed & implemented by Nguyen Anh Quynh + +See http://www.capstone-engine.org for further information. + +Copyright (c) 2013, COSEINC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the developer(s) nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE_GTEST.txt b/LICENSE_GTEST.txt new file mode 100644 index 0000000000..1941a11f8c --- /dev/null +++ b/LICENSE_GTEST.txt @@ -0,0 +1,28 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE_LLVM.txt b/LICENSE_LLVM.txt new file mode 100644 index 0000000000..5715176572 --- /dev/null +++ b/LICENSE_LLVM.txt @@ -0,0 +1,278 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. diff --git a/LICENSE_YAML-CPP.txt b/LICENSE_YAML-CPP.txt new file mode 100644 index 0000000000..991fdbbe7d --- /dev/null +++ b/LICENSE_YAML-CPP.txt @@ -0,0 +1,19 @@ +Copyright (c) 2008-2015 Jesse Beder. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 9a1486a924..070dd1f781 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ The Simulation Engine (SimEng) is a framework for building modern cycle-accurate - Fast - Easy to use and modify to desired configurations - Scalable, supporting simulation of simple scalar cores, up to superscalar out-of-order designs -- Capable of supporting a wide range of ISAs, starting with ARMv8 but eventually including x86, RISC-V, POWER, etc. +- Capable of supporting a wide range of ISAs, starting with AArch64 but eventually including x86, RISC-V, POWER, etc. - Open source, with a permissive license to enable collaboration across academia and industry SimEng places an emphasis on performance and scalability, whilst maintaining a clean, modern, and well-documented code base. diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 4a45cd0e24..99f5c87336 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,4 +1,4 @@ -Welcome to the 0.9.3 open source release of the Simulation Engine! SimEng is a fast, easy to use and modify cycle-level simulator for CPUs. Its initial focus is on simulating single Arm cores in server CPUs, and so the instruction set architecture (ISA) target is initially Armv8.4-a+SVE. Later versions of the Arm ISA, and other ISAs such as RISC-V, will be supported in future releases. +Welcome to the 0.9.4 open source release of the Simulation Engine! SimEng is a fast, easy to use and modify, cycle-level simulator for CPUs. Its initial focus is on simulating single Arm cores in server CPUs, and so the instruction set architecture (ISA) target is initially Armv9.2-a+SVE. Later versions of the Arm ISA, and other ISAs such as RISC-V, will be supported in future releases. This SimEng release should be considered beta software - you are the first users outside of the core developers, so there *will* be lots of bugs and missing features. The good news is that the code has been designed to be simple to understand and modify, so if you find a bug, such as a missing instruction or missing system call, please submit a PR, or report an issue and we’ll get to it as soon as we can. @@ -16,14 +16,15 @@ Things that should work in this first release include: Pre-rolled CPU models in SimEng include: * Marvell ThunderX2 * Fujitsu A64fx +* Apple M1 Firestorm * More Arm code models such as those found in other Arm server CPUs will be included in future releases Current limitations (to be addressed in a future release): * Dynamically linked binaries are not yet supported in SimEng but developments are currently being undertaken * We don't currently support running MPI programs (we’ve had a statically linked OpenMPI single rank program run correctly, but this was painful to build) -* We only support a subset of Linux's system calls, and these run under emulation. The subset of 45 calls is enough to run all the codes we've tried so far +* We only support a subset of Linux's system calls, and these run under emulation. The subset of 42 calls is enough to run all the codes we've tried so far * Only partial support for micro-oping, mainly for Load and Store operations -* Only partial support for the ISA - we’ve focused on implementing the instructions we’ve seen generated by the compiler for all the test cases we’ve considered, about 856 different instructions so far (~20% of the entire ISA). You’re likely to come across “instruction not implemented” errors, just let us know when you see these +* Only partial support for the ISA - we’ve focused on implementing the instructions we’ve seen generated by the compiler for all the test cases we’ve considered, about 930 different instructions so far (~15% of the entire ISA). You’re likely to come across “instruction not implemented” errors, just let us know when you see these * Single core, single thread only for now * SimEng currently only supports a very simple memory model, assuming all load/stores will hit the L1 cache * The longer-term plan is to add a full memory model and support for multicore simulations by using the SST framework - http://sst-simulator.org @@ -32,7 +33,7 @@ Supported OSs (we’ve tested these, SimEng may also work on other platforms): * CentOS 7 * Ubuntu * Cray’s CLE 7, which is based on SLES 15 -* macOS Big Sur +* macOS Big Sur/Monterey Compilers supported for building SimEng itself: * GCC 7 or later @@ -44,6 +45,7 @@ Some benchmarks we’ve run ourselves and so should work: * miniBUDE - https://github.com/UoB-HPC/miniBUDE * CloverLeaf - https://github.com/UK-MAC/CloverLeaf_Serial * Tealeaf - https://github.com/UoB-HPC/TeaLeaf +* FFTW3 - https://github.com/rdolbeau/fftw3/tree/arm-sve When you hit issues building or running SimEng, please do let us know, either by submitting a PR, or filing an issue via the SimEng Github repo: diff --git a/configs/a64fx.yaml b/configs/a64fx.yaml index f4f846cbdd..5006484906 100644 --- a/configs/a64fx.yaml +++ b/configs/a64fx.yaml @@ -8,9 +8,12 @@ Core: Clock-Frequency: 1.8 # Timer-Frequency is in MHz. Timer-Frequency: 100 - Fetch-Block-Size: 32 Micro-Operations: True Vector-Length: 512 +Fetch: + Fetch-Block-Size: 32 + Loop-Buffer-Size: 48 + Loop-Detection-Threshold: 4 Process-Image: Heap-Size: 1073741824 Stack-Size: 1048576 @@ -21,7 +24,6 @@ Register-Set: Conditional-Count: 128 Pipeline-Widths: Commit: 4 - Dispatch-Rate: 2 FrontEnd: 4 LSQ-Completion: 2 Queue-Sizes: @@ -29,8 +31,16 @@ Queue-Sizes: Load: 40 Store: 24 Branch-Predictor: - BTB-bitlength: 11 -L1-Cache: + BTB-Tag-Bits: 11 + Saturating-Count-Bits: 2 + Global-History-Length: 11 + RAS-entries: 8 + Fallback-Static-Predictor: "Always-Taken" +L1-Data-Memory: + Interface-Type: Fixed +L1-Instruction-Memory: + Interface-Type: Flat +LSQ-L1-Interface: Access-Latency: 5 Exclusive: True Load-Bandwidth: 128 @@ -89,25 +99,30 @@ Ports: Reservation-Stations: 0: Size: 20 + Dispatch-Rate: 2 Ports: - FLA - PR - EXA 1: Size: 20 + Dispatch-Rate: 2 Ports: - FLB - EXB 2: Size: 10 + Dispatch-Rate: 2 Ports: - EAGA 3: Size: 10 + Dispatch-Rate: 2 Ports: - EAGB 4: Size: 19 + Dispatch-Rate: 2 Ports: - BR Execution-Units: @@ -232,9 +247,9 @@ Latencies: # CPU-Info mainly used to generate a replica of the special (or system) file directory # structure CPU-Info: - # Set Generate-Special-Dir to 'T' to generate the special files directory, or to 'F' to not. + # Set Generate-Special-Dir to True to generate the special files directory, or to False to not. # (Not generating the special files directory may require the user to copy over files manually) - Generate-Special-Dir: T + Generate-Special-Dir: True # Core-Count MUST be 1 as multi-core is not supported at this time. (A64FX true value is 48) Core-Count: 1 # Socket-Count MUST be 1 as multi-socket simulations are not supported at this time. (A64FX true value is 1) diff --git a/configs/m1_firestorm.yaml b/configs/m1_firestorm.yaml new file mode 100644 index 0000000000..12d341ca1b --- /dev/null +++ b/configs/m1_firestorm.yaml @@ -0,0 +1,320 @@ +# M1 Firestorm core +Core: + Simulation-Mode: outoforder + Clock-Frequency: 3.2 + Timer-Frequency: 100 + Micro-Operations: True +Fetch: + Fetch-Block-Size: 64 + Loop-Buffer-Size: 48 + Loop-Detection-Threshold: 4 +Process-Image: + Heap-Size: 1073741824 + Stack-Size: 1048576 +Register-Set: + GeneralPurpose-Count: 394 + FloatingPoint/SVE-Count: 432 + Conditional-Count: 128 +Pipeline-Widths: + Commit: 16 + FrontEnd: 8 + LSQ-Completion: 4 +Queue-Sizes: + ROB: 630 + Load: 130 + Store: 60 +Branch-Predictor: + BTB-Tag-Bits: 11 + Saturating-Count-Bits: 2 + Global-History-Length: 11 + RAS-entries: 8 + Fallback-Static-Predictor: "Always-Taken" +L1-Data-Memory: + Interface-Type: Fixed +L1-Instruction-Memory: + Interface-Type: Flat +LSQ-L1-Interface: + Access-Latency: 3 + Exclusive: False + L1 Load Bandwidth: 48 + L1 Store Bandwidth: 48 + Permitted Requests-Per-Cycle: 4 + Permitted-Loads-Per-Cycle: 3 + Permitted-Stores-Per-Cycle: 2 +Ports: + 0: + Portname: INT1 + Instruction-Support: + - INT_SIMPLE + - BRANCH + 1: + Portname: INT2 + Instruction-Support: + - INT_SIMPLE + - BRANCH + 2: + Portname: INT3 + Instruction-Support: + - INT_SIMPLE + 3: + Portname: INT4 + Instruction-Support: + - INT_SIMPLE + 4: + Portname: INT5 + Instruction-Support: + - INT_SIMPLE + - INT_MUL + - INT_DIV_OR_SQRT + 5: + Portname: INT6 + Instruction-Support: + - INT_SIMPLE + - INT_MUL + 6: + Portname: LS1 + Instruction-Support: + - STORE + 7: + Portname: LS2 + Instruction-Support: + - LOAD + - STORE + 8: + Portname: LS3 + Instruction-Support: + - LOAD + 9: + Portname: LS4 + Instruction-Support: + - LOAD + 10: + Portname: FP_SIMD1 + Instruction-Support: + - FP + - VECTOR + 11: + Portname: FP_SIMD2 + Instruction-Support: + - FP + - VECTOR + 12: + Portname: FP_SIMD3 + Instruction-Support: + - FP + - VECTOR + 13: + Portname: FP_SIMD4 + Instruction-Support: + - FP + - VECTOR +Reservation-Stations: + 0: + Size: 24 + Dispatch-Rate: 16 + Ports: + - INT1 + 1: + Size: 26 + Dispatch-Rate: 16 + Ports: + - INT2 + 2: + Size: 16 + Dispatch-Rate: 16 + Ports: + - INT3 + 3: + Size: 12 + Dispatch-Rate: 16 + Ports: + - INT4 + 4: + Size: 28 + Dispatch-Rate: 16 + Ports: + - INT5 + 5: + Size: 28 + Dispatch-Rate: 16 + Ports: + - INT6 + 6: + Size: 12 + Dispatch-Rate: 16 + Ports: + - LS1 + 7: + Size: 12 + Dispatch-Rate: 16 + Ports: + - LS2 + 8: + Size: 12 + Dispatch-Rate: 16 + Ports: + - LS3 + 9: + Size: 12 + Dispatch-Rate: 16 + Ports: + - LS4 + 10: + Size: 36 + Dispatch-Rate: 16 + Ports: + - FP_SIMD1 + 11: + Size: 36 + Dispatch-Rate: 16 + Ports: + - FP_SIMD2 + 12: + Size: 36 + Dispatch-Rate: 16 + Ports: + - FP_SIMD3 + 13: + Size: 36 + Dispatch-Rate: 16 + Ports: + - FP_SIMD4 + +Execution-Units: + 0: + Pipelined: True + 1: + Pipelined: True + 2: + Pipelined: True + 3: + Pipelined: True + 4: + Pipelined: True + 5: + Pipelined: True + 6: + Pipelined: True + 7: + Pipelined: True + 8: + Pipelined: True + 9: + Pipelined: True + 10: + Pipelined: True + 11: + Pipelined: True + 12: + Pipelined: True + 13: + Pipelined: True +Latencies: + 0: + Instruction-Groups: + - INT_SIMPLE + - BRANCH + Execution-Latency: 1 + Execution-Throughput: 1 + 1: + Instruction-Groups: + - INT_SIMPLE + - BRANCH + Execution-Latency: 1 + Execution-Throughput: 1 + 2: + Instruction-Groups: + - INT_SIMPLE + Execution-Latency: 1 + Execution-Throughput: 1 + 3: + Instruction-Groups: + - INT_SIMPLE + Execution-Latency: 1 + Execution-Throughput: 1 + 4: + Instruction-Groups: + - INT_SIMPLE + - INT_MUL + - INT_DIV_OR_SQRT + Execution-Latency: 1 + Execution-Throughput: 1 + 5: + Instruction-Groups: + - INT_SIMPLE + - INT_MUL + Execution-Latency: 1 + Execution-Throughput: 1 + 6: + Instruction-Groups: + - STORE + Execution-Latency: 1 + Execution-Throughput: 1 + 7: + Instruction-Groups: + - LOAD + - STORE + Execution-Latency: 1 + Execution-Throughput: 1 + 8: + Instruction-Groups: + - LOAD + Execution-Latency: 1 + Execution-Throughput: 1 + 9: + Instruction-Groups: + - LOAD + Execution-Latency: 1 + Execution-Throughput: 1 + 10: + Instruction-Groups: + - FP + - VECTOR + - SCALAR + Execution-Latency: 3 + Execution-Throughput: 1 + 11: + Instruction-Groups: + - FP + - VECTOR + - SCALAR + Execution-Latency: 3 + Execution-Throughput: 1 + 12: + Instruction-Groups: + - FP + - VECTOR + - SCALAR + Execution-Latency: 3 + Execution-Throughput: 1 + 13: + Instruction-Groups: + - FP + - VECTOR + - SCALAR + Execution-Latency: 3 + Execution-Throughput: 1 +# CPU-Info mainly used to generate a replica of the special (or system) file directory +# structure +CPU-Info: + # Set Generate-Special-Dir to True to generate the special files directory, or to False to not. + # (Not generating the special files directory may require the user to copy over files manually) + Generate-Special-Dir: True + # Core-Count MUST be 1 as multi-core is not supported at this time. (A64FX true value is 48) + Core-Count: 1 + # Socket-Count MUST be 1 as multi-socket simulations are not supported at this time. (A64FX true value is 1) + Socket-Count: 1 + # SMT MUST be 1 as Simultanious-Multi-Threading is not supported at this time. (A64FX true value is 1) + SMT: 1 + # Below are the values needed to generate /proc/cpuinfo + BogoMIPS: 48.00 + Features: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm ssbs sb paca pacg dcpodp flagm2 frint + CPU-Implementer: "0x46" + CPU-Architecture: 8 + CPU-Variant: "0x1" + CPU-Part: "0x001" + CPU-Revision: 0 + # Package-Count is used to generate + # /sys/devices/system/cpu/cpu{0..Core-Count}/topology/{physical_package_id, core_id} + Package-Count: 1 + diff --git a/configs/tx2.yaml b/configs/tx2.yaml index f340468a9a..cbe084cf56 100644 --- a/configs/tx2.yaml +++ b/configs/tx2.yaml @@ -8,8 +8,11 @@ Core: Clock-Frequency: 2.5 # Timer-Frequency is in MHz. Timer-Frequency: 200 - Fetch-Block-Size: 32 Micro-Operations: True +Fetch: + Fetch-Block-Size: 32 + Loop-Buffer-Size: 64 + Loop-Detection-Threshold: 4 Process-Image: Heap-Size: 1073741824 Stack-Size: 1048576 @@ -19,7 +22,6 @@ Register-Set: Conditional-Count: 128 Pipeline-Widths: Commit: 4 - Dispatch-Rate: 4 FrontEnd: 4 LSQ-Completion: 2 Queue-Sizes: @@ -27,8 +29,16 @@ Queue-Sizes: Load: 64 Store: 36 Branch-Predictor: - BTB-bitlength: 16 -L1-Cache: + BTB-Tag-Bits: 11 + Saturating-Count-Bits: 2 + Global-History-Length: 10 + RAS-entries: 5 + Fallback-Static-Predictor: "Always-Taken" +L1-Data-Memory: + Interface-Type: Fixed +L1-Instruction-Memory: + Interface-Type: Flat +LSQ-L1-Interface: Access-Latency: 4 Exclusive: False Load-Bandwidth: 32 @@ -71,6 +81,7 @@ Ports: Reservation-Stations: 0: Size: 60 + Dispatch-Rate: 4 Ports: - Port 0 - Port 1 @@ -152,9 +163,9 @@ Latencies: # CPU-Info mainly used to generate a replica of the special (or system) file directory # structure CPU-Info: - # Set Generate-Special-Dir to 'T' to generate the special files directory, or to 'F' to not. + # Set Generate-Special-Dir to True to generate the special files directory, or to False to not. # (Not generating the special files directory may require the user to copy over files manually) - Generate-Special-Dir: T + Generate-Special-Dir: True # Core-Count MUST be 1 as multi-core is not supported at this time. (TX2 true value is 32) Core-Count: 1 # Socket-Count MUST be 1 as multi-socket simulations are not supported at this time. (TX2 true value is 2) diff --git a/docs/sphinx/assets/elfstruct.png b/docs/sphinx/assets/elfstruct.png new file mode 100644 index 0000000000..2fcb647c90 Binary files /dev/null and b/docs/sphinx/assets/elfstruct.png differ diff --git a/docs/sphinx/developer/arch/index.rst b/docs/sphinx/developer/arch/index.rst index e750cada9d..5555a1f7f5 100644 --- a/docs/sphinx/developer/arch/index.rst +++ b/docs/sphinx/developer/arch/index.rst @@ -5,7 +5,9 @@ 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. -Below provides more information on the abstract structure of a SimEng architecture and currently supported 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 `_. + +Below provides more information on the abstract structure of a SimEng architecture and currently supported ISAs. .. toctree:: :maxdepth: 2 diff --git a/docs/sphinx/developer/arch/supported/aarch64.rst b/docs/sphinx/developer/arch/supported/aarch64.rst index f8a7da1868..f0e9e5a500 100644 --- a/docs/sphinx/developer/arch/supported/aarch64.rst +++ b/docs/sphinx/developer/arch/supported/aarch64.rst @@ -1,7 +1,7 @@ AArch64 ======= -SimEng provides a basic implementation of the 64-bit AArch64 architecture, part of the ARMv8-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.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. .. contents:: Contents @@ -42,12 +42,12 @@ The above diagram describes the instruction groups currently implemented for the This hierarchy-based naming convention has been chosen to provide the user with greater control over the number of instructions grouped under one name, whilst also remaining intuitive. A variety of combinations/instruction scopes can be defined through this method and only uses a small set of easily interpreted operation descriptions. -If the supplied instruction groups don't provide a small enough scope, a Capstone opcode can be used instead (found in ``SimEng/external/capstone/arch/AArch64/AArch64GenInstrInfo.inc``) with the format ``~{CAPSTONE_OPCODE}``. +If the supplied instruction groups don't provide a small enough scope, a Capstone opcode can be used instead (found in ``SimEng/build/_deps/capstone-lib-src/arch/AArch64/AArch64GenInstrInfo.inc``) with the format ``~{CAPSTONE_OPCODE}``. Implementation '''''''''''''' -The available instruction groups can be found in ``SimEng/src/include/simeng/arch/aarch64/Instruction.hh`` under the ``InstructionGroups`` namespace. The implementation of the relationship between groups, as described in the above diagram, can be found in the same file as an ``unordered_map`` named ``groupInheritance``. The keys of ``groupInheritance`` represent the parent node of the relationship and the values, the children nodes. The relationships defined by one entry of the ``groupInheritance`` map only represents a single parent-child relationship, therefore, the reading of ``groupInheritance`` relationships are performed recursively. This decision was made to reduce the amount of code used in the instantiation of the ``groupInheritance`` object. +The available instruction groups can be found in ``SimEng/src/include/simeng/arch/aarch64/InstructionGroups.hh`` under the ``InstructionGroups`` namespace. The implementation of the relationship between groups, as described in the above diagram, can be found in the same file as an ``unordered_map`` named ``groupInheritance``. The keys of ``groupInheritance`` represent the parent node of the relationship and the values, the children nodes. The relationships defined by one entry of the ``groupInheritance`` map only represents a single parent-child relationship, therefore, the reading of ``groupInheritance`` relationships are performed recursively. This decision was made to reduce the amount of code used in the instantiation of the ``groupInheritance`` object. The ``getGroup()`` function in ``SimEng/src/lib/arch/aarch64/Instruction.cc`` contains the logic for converting an instructions' identifiers to an instruction group. The ``InstructionGroups`` namespace has been ordered such that each data type group (``INT``, ``SCALAR``, etc) is followed by the set of possible operation type groups (``*_SIMPLE_ARTH``, ``*_MUL``, etc). A combination of a base and a relative offset value is used to implement the conversion. The base value is defined as one of the data type groups, whilst the relative offset value represents an operation type group. For those groups that don't conform to this relationship, e.g. ``BRANCH`` or ``PREDICATE``, a simple conditional clause is defined. @@ -144,6 +144,8 @@ There are several useful variables that execution behaviours have access to: SimEng supports the ARM SVE extension and thus the use of ``Z`` vector registers. ``Z`` registers are an extension of the ARM NEON ``V`` vector registers whereby the ``V`` register variant occupies the lower 16 bytes of the ``Z`` registers total 256 bytes. Under the ARM SVE extension, the implemented logic for writing to a ``V`` register is to zero-out the upper 240 bytes of the associated ``Z`` register (e.g. ``z1`` and ``v1``) and treat its lower 16 bytes as the ``V`` register. SimEng will automatically apply this logic when the execution of an instruction contains a ``V`` register as a destination location. +.. Note:: We strongly encourage adding regression tests for each implemented instruction at the same time as adding execution behaviour to ensure functional validity. + Helper Functions **************** @@ -202,3 +204,26 @@ 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. + +Common Instruction Execution behaviour issues +********************************************* +Often newly added instructions will be implemented correctly but their tests will fail or they will exhibit incorrect execution behaviour. This is especially common with SVE instructions. The most common reason for this is Capstone assigning incorrect operand access rights to each operand. To fix this, a case should be added to the switch statement in the ``InstructionMetadata.cc`` constructor function. An example statement can be seen below:: + + case Opcode::AArch64_LD1Onev16b_POST: // ld1 {vt.16b}, [xn], #imm + operands[0].access = CS_AC_WRITE; // vt.16b access + operands[1].access = CS_AC_READ | CS_AC_WRITE; // xn access + break; + +If after adding a case to the metadata switch statement the execution behaviour of your instruction is still incorrect, please submit an issue describing the instruction in question along with the error you are experiencing. + +System registers +---------------- + +AArch64 defines many system registers, which are treated the same as any other explicit source or destination register within SimEng. + +Similar to instructions, system register support is added when they are encountered in run programs. To add support for a previously unseen system register, it must be added to the ``systemRegisterMap_`` map in the associated ISA ``Architecture.cc`` file. + +System Counter Timers +--------------------- + +Present in AArch64 are two main system timers; the Counter-timer Virtual Count Register `CNTVCT `_, and the Performance Monitors Cycle Count Register `PMCCNTR `_. The CNTVCT system register holds a virtual cycle count, and is incremented at a defined frequency (see :ref:` Configuring SimEng `). The PMCCNTR system register holds the real processor cycle count. Both are supported in SimEng and are accessible to the programmer through the appropriate ``mrs`` instructions. The logic which updates these registers can be found at ``src/lib/arch/aarch64/Architecture.cc:updateSystemTimerRegisters`` and is invoked inside each of the core model's ``tick()`` function. \ No newline at end of file diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index c473285be0..b49f58c1c1 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -3,28 +3,35 @@ Branch prediction SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredictor`` class to enable speculative execution. -Access to the ``BranchPredictor`` is supported through the ``predict`` and ``update`` functions with the former providing a branch prediction, both target and direction, and the latter updating an instructions' prediction. The ``predict`` function is passed an instruction object allowing for branch algorithms to utilise instruction information such as address and architecture-specific instruction classifiers. The ``update`` function is passed the branch outcome, along with the instruction object itself, so that any algorithms or branch structures may be updated. +Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, and ``flush`` provides optional algorithm specific flushing functionality. -The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a set of predictors detailed below. +The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: -AlwaysNotTakenPredictor ------------------------ +- ``Conditional`` +- ``LoopClosing`` +- ``Return`` +- ``SubroutineCall`` +- ``Unconditional`` -The ``AlwaysNotTakenPredictor`` is the simplest available branch predictor. It is a static predictor, only providing a "not taken" branch direction with no branch target prediction and no update functionality. +The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. +The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -BTBPredictor ------------- +Generic Predictor +----------------- -A more complex branch predictor is the ``BTBPredictor`` utilising a Branch Target Buffer (BTB) and a branch direction buffer. Both structures are indexed by the instruction address, after the application of a mask, and store previous outcomes of executed branches. +The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. -Access to a structure entry with no previous history will supply a "not taken" direction prediction with no known target, similar to the ``AlwaysNotTakenPredictor``. +Global History + For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. -BTB_BWTPredictor ----------------- +Branch Target Buffer (BTB) + For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. -Based on the algorithms used by the A64FX processor, the ``BTB_BWTPredictor`` branch predictor utilises a 4-way associative BTB-style structure with each entry storing a 2-bit direction agreement policy and branch target. An agreement policy assigns an agreement bias value against a chosen branch direction such that, ``11`` relates to a strong agreement and ``00`` a strong disagreement. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. -To index this structure, the instructions' address is used in conjunction with a set of branch directions histories via an XOR operation. This indexing policy aims to reduce the contention of structure entries between branch instructions. +Return Address Stack (RAS) + Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for use by a proceeding Return instruction. -To accompany the BTB-style structure, a return address stack (RAS) is also used. The RAS allows for branch and link instructions to push a return address onto a stack, and return instructions to pop an address from the stack. This methodology allows for a strong prediction of the branch target for return instructions. \ No newline at end of file +Static Prediction + Based on the chosen static prediction method of "always taken" or "always not taken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of taken or not-taken respectively. diff --git a/docs/sphinx/developer/components/coreinstance.rst b/docs/sphinx/developer/components/coreinstance.rst new file mode 100644 index 0000000000..02f69a369a --- /dev/null +++ b/docs/sphinx/developer/components/coreinstance.rst @@ -0,0 +1,23 @@ +Core Instance +============= + +The ``CoreInstance`` component supplies the functionality for instantiating all simulation objects and linking them together. + +The standard process taken to create an instance of the modelled core is as follows: + +Process the config file + Either the passed configuration file path, or default configuration string, is used to generate the model configuration class. All subsequent parameterised instantiations of simulation objects utilise this configuration class. + +Create the image process + From the passed workload path, or default set of instructions, a process image is created. A region of host memory is populated with workload data (e.g. instructions), a region for the HEAP, and an initial stack frame. References to it are then passed between various simulation objects to serve as the underlying process memory space. + +Construct on-chip cache interfaces + Based on the supplied configuration options, the on-chip cache interfaces are constructed. These interfaces sit on top of a reference to the process memory space constructed prior. Currently, only L1 instruction and data caches are supported and the interfaces are defined under the :ref:`L1-Data-Memory ` and :ref:`L1-Instruction-Memory ` config options. + +Construct the core simulation object + After all the general components are created, the simulated core object is constructed. The architecture, branch predictor, and issue port allocator are first constructed and subsequently passed to the core object. Within the core object itself, relevant simulation objects are constructed using the instantiations carried out in the ``CoreInstance`` class. The exact simulation objects created are dependent on the core :ref:`archetype ` in use. + +Special File Directory + Finally, SimEng's special file directory is constructed if enabled within the passed configuration. More information about its usage can be found :ref:`here `. + +The ``CoreInstance`` class also contains a selection of getter functions for obtaining information about the simulation objects constructed. \ No newline at end of file diff --git a/docs/sphinx/developer/components/index.rst b/docs/sphinx/developer/components/index.rst index 736f3bc5bf..620bcc4e46 100644 --- a/docs/sphinx/developer/components/index.rst +++ b/docs/sphinx/developer/components/index.rst @@ -8,6 +8,7 @@ The following information is concerned with those simulation components. .. toctree:: :maxdepth: 2 + coreinstance pipeline/index branchPred registerFiles diff --git a/docs/sphinx/developer/components/pipeline/components.rst b/docs/sphinx/developer/components/pipeline/components.rst index cee79d8aad..ab62a6b919 100644 --- a/docs/sphinx/developer/components/pipeline/components.rst +++ b/docs/sphinx/developer/components/pipeline/components.rst @@ -26,11 +26,18 @@ Only a specific number of instructions can be committed per cycle as defined by .. _microOpCommit: -commitMicroOps +CommitMicroOps ************** When a macro-op is split, all created micro-ops can only be committed when all are ready to do so. These micro-ops firstly enter a "waiting commit" state and once all associated micro-ops are in said state, they can then enter a "ready to commit" state and commit in the standard manner. The ``commitMicroOps`` function facilitates this state transition whilst the ``WritebackUnit`` sets the "waiting commit" state. +.. _loopDetect: + +Loop detection +************** + +For the loop buffer to operate within the fetch unit (detailed :ref:`here `) the detection of loops, and the branches which represent them, must be facilitated. The ROB supports this functionality by tracking the retirement of branch instructions. If the same branch instruction retires a configurable number of times, with the same target and direction, then a loop is detected. No other branch or different outcomes from the same branch can be retired within this period. + LoadStoreQueue -------------- diff --git a/docs/sphinx/developer/components/pipeline/units.rst b/docs/sphinx/developer/components/pipeline/units.rst index 3b950fce02..52358f4658 100644 --- a/docs/sphinx/developer/components/pipeline/units.rst +++ b/docs/sphinx/developer/components/pipeline/units.rst @@ -6,7 +6,7 @@ The SimEng pipeline units provide a ``tick`` method, which performs a single cyc The available units are: * ``FetchUnit``: Reads instruction data from memory, to produce a stream of macro-ops. -* ``DecodeUnit``: Reads macro-ops from the input, converts them into SimEng instruction objects as micro-ops, and writes them to the output. +* ``DecodeUnit``: Reads macro-ops from the input, splits them into micro-ops, and writes them to the output. * ``RenameUnit``: Reads micro-ops from the input, renames their operands, places an entry in a reorder buffer, and writes them to the output. * ``DispatchIssueUnit``: Reads micro-ops from the input, reads operands from register files, and adds them to an internal queue until any missing operands have been broadcast. Writes execution-ready micro-ops to multiple outputs. * ``ExecuteUnit``: Reads micro-ops from the input and holds them in an internal queue for a cycle-duration determined by their execution latency, after which they're written to the output. @@ -23,9 +23,9 @@ Behaviour The fetch unit fetches memory in discrete boundary-aligned blocks, according to the current program counter (PC); this is to prevent the fetched block overlapping an inaccessible or unmapped memory region that may result in the request incorrectly responding with a fault despite the validity of the initial region. -Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the macro-op is passed to the supplied branch predictor: if the instruction is predicted to be a taken branch, then the PC will be updated to the predicted target address and the cycle will end, otherwise, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. +Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a taken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. -This process of pre-decoding, predicting, and updating the PC continues until one of the following occurs: +This standard process of pre-decoding, predicting, and updating the PC continues until one of the following occurs: .. glossary:: @@ -38,6 +38,31 @@ This process of pre-decoding, predicting, and updating the PC continues until on The fetched memory block is exhausted The next block may be requested, and processing will resume once the data is available. +.. _loopBuf: + +Loop Buffer +*********** + +Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is taken and increases the throughput of the fetch unit. + +Each entry of the loop buffer is the encoding of the Macro-Op. Therefore, when supplying an instruction from the loop buffer, the pre-decoding step must still be performed. This was required to avoid any issues with multiple instantiations of the same instruction editing each others class members. + +The Loop buffer has four states: + +IDLE + No loop has been detected so no operation is required. + +WAITING + A loop has been detected and the loop buffer is waiting until the branch representing the loop is found in the instruction stream. + +FILLING + The branch representing the loop has been found and the buffer is being filled until it is seen again. + +SUPPLYING + The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is taken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. + +The detection of a loop and the branch which represents it comes from the ROB. More information can be found :ref:`here `. + If the output buffer is stalled when the cycle begins, the fetch unit will idle and perform no operation. Fetching memory @@ -114,9 +139,9 @@ During dispatch, the unit will read instructions from the input buffer, and chec Before operand checking, each instruction is allocated a destination port that corresponds to one of the output buffers. A supplied port allocator is used to determine the destination port of the supplied instruction. The logic of the port allocator can be model-independent but SimEng provides a basic ``BalancedPortAllocator`` class that attempts to balance port allocation amongst the available reservation stations for that instruction. A ``getRSSizes`` function is supplied to port allocator classes to support algorithms that rely on information relating to the occupancy of reservation stations. Within a port allocator, there also exists a ``tick`` function which, similarly to the pipeline units, allows for per-cycle logic to be triggered. -A reservation station can have many ports, with each port maintaining a ready queue containing instructions that are ready to execute. The port is also assigned an associated destination port number to map reservation station ports to output buffers. Note that there is no dedicated data structure for the instructions in the reservation stations; all instructions it contains are either in the dependency matrix or one of its associated port ready queues, so we simply keep track of the number of instructions instead. +After a destination port has been allocated and all required operands are either supplied or their dependency registered, the instruction is then assigned to a reservation station, where it will remain until issued. A reservation station can have many ports, with each port maintaining a ready queue containing instructions that are ready to execute. The port is also assigned an associated destination port number to map reservation station ports to output buffers. Each reservation station also has an associated dispatch-rate value which limits the number of instructions that can be dispatched to it per cycle. -The instruction is then assigned to a reservation station, where it will remain until issued. If at any point the reservation station becomes full while instructions remain in the input, the cycle stops and the input buffer becomes stalled. The remaining instructions will be processed during a future dispatch, once space is available, and the input buffer will be unstalled once emptied. +If at any point the reservation station becomes full while instructions remain in the input, or the dispatch-rate is exceeded, the cycle stops and the input buffer becomes stalled. The remaining instructions will be processed during a future dispatch, once space is available, and the input buffer will be unstalled once emptied. Note that there is no dedicated data structure for the instructions in the reservation stations; all instructions it contains are either in the dependency matrix or one of its associated port ready queues, so we simply keep track of the number of instructions instead. Operand forwarding '''''''''''''''''' @@ -177,4 +202,4 @@ Behaviour Each cycle, the unit will read instructions from the input buffer, and retrieve any results generated during execution. All results are written to the supplied register file set, and the instructions are flagged as ready to commit. As the unit has no output buffer, instructions are discarded once writeback is complete. -.. Note:: (Relevant for outoforder models) AT the writeback stage, Instructions created from a macro-op split are placed into a ``waitingCommit`` state and inform the ``ReorderBuffer`` that the instruction is ready to commit once all other associated micro-ops are. More information can be found :ref:`here `. \ No newline at end of file +.. Note:: (Relevant for outoforder models) At the writeback stage, instructions created from a macro-op split are placed into a ``waitingCommit`` state and inform the ``ReorderBuffer`` that the instruction is ready to commit once all other associated micro-ops are. More information can be found :ref:`here `. \ No newline at end of file diff --git a/docs/sphinx/developer/concepts/index.rst b/docs/sphinx/developer/concepts/index.rst index c1d1442e29..b1de10f510 100644 --- a/docs/sphinx/developer/concepts/index.rst +++ b/docs/sphinx/developer/concepts/index.rst @@ -1,7 +1,7 @@ Simulation Concepts =================== -A SimEng simulation consists of two core components: a :doc:`model <../models/index>` and an :doc:`architecture <../arch/index>`. The model describes the type and structure of the processor being simulated, while the architecture describes the instruction set and related mechanisms and features. This separation allows for reusing the same basic instruction set across a wide range of simulated processors, such as modelling in-order and out-of-order processors which both support ARMv8. Similarly, similar processor designs with different instruction sets may use the same model, such as a ThunderX2 versus an Ivy Bridge or similar Intel Core processor; while one is ARMv8 and the other x86, they are both out-of-order processors with a unified reservation station and a similar arrangement of execution units. +A SimEng simulation consists of two core components: a :doc:`model <../models/index>` and an :doc:`architecture <../arch/index>`. The model describes the type and structure of the processor being simulated, while the architecture describes the instruction set and related mechanisms and features. This separation allows for reusing the same basic instruction set across a wide range of simulated processors, such as modelling in-order and out-of-order processors which both support Armv9.2-a. Similarly, similar processor designs with different instruction sets may use the same model, such as a ThunderX2 versus an Ivy Bridge or similar Intel Core processor; while one is ARMv8 and the other x86, they are both out-of-order processors with a unified reservation station and a similar arrangement of execution units. The following information is concerned with those concepts whose interactions flow beyond the scope of the processor core or don't fit the description of a :doc:`Simulation Component <../components/index>`. diff --git a/docs/sphinx/developer/concepts/instructions.rst b/docs/sphinx/developer/concepts/instructions.rst index 85bdb35b68..30708108ec 100644 --- a/docs/sphinx/developer/concepts/instructions.rst +++ b/docs/sphinx/developer/concepts/instructions.rst @@ -12,7 +12,7 @@ To permit instructions to function independently of the type of model they exist Post-Decode *********** -This is the initial step of an instruction. At this stage, the instruction has been fully decoded and is now capable of advertising the registers it reads and writes, as well as various metadata such as whether it's a load, store, or branch. The instruction is also allocated an architecture-specific group and, when appropriate, a set of execution ports that it can flow through. The set of ports available in the model is defined by the user through :ref:`configuration options `. +This is the initial step of an instruction. At this stage, the instruction has been fully decoded and is now capable of advertising the registers it reads and writes, as well as various metadata such as whether it's a load, store, or branch. The instruction is also allocated an architecture-specific group (when appropriate), a set of execution ports that it can flow through, and execution latency values. The set of ports available in the model is defined by the user through :ref:`configuration options `. The model can use this information to supply the instruction with the appropriate values for each source operand and determine where the instruction should be sent for processing. diff --git a/docs/sphinx/developer/concepts/kernel.rst b/docs/sphinx/developer/concepts/kernel.rst index 16a4893441..f635ab6615 100644 --- a/docs/sphinx/developer/concepts/kernel.rst +++ b/docs/sphinx/developer/concepts/kernel.rst @@ -8,7 +8,34 @@ The SimEng Kernel is split into two classes, ``LinuxProcess`` and ``Linux``. LinuxProcess ------------ -The ``LinuxProcess`` class provides the functionality to process the supplied program. It creates the initial process memory space, including the Executable and Linkable Format (ELF) process image and the stack. The population of the initial stack state is based on the information `here `_. +The ``LinuxProcess`` class provides the functionality to process the supplied program. It creates the initial process memory space, including the Executable and Linkable Format (ELF) process image and the stack. The process memory space created contains all the data required by the program to run. + +ELF Parsing +~~~~~~~~~~~~ +The ELF binaries have a defined structure for 32-bit and 64-bit architectures, all information regarding parsing ELF binaries has been referenced from the `Linux manual page `_. The ELF binary is divided into multiple parts. SimEng stores all relevant parts of the `ELF Binary` in a ``char[] processImage`` array, which is a private member variable of the ``LinuxProcess`` class. + +.. image:: ../../assets/elfstruct.png + :alt: ELF Structure + :align: center + +* The `ELF Header` is the first part of `ELF binary`. The `ELF Header` holds information regarding the structure of the `ELF Binary`. SimEng extracts the following from the `ELF Header`: + + * The entry point of binary i.e. the virtual address to which the system first transfers control. + * The file offset of the `ELF Program Headers`. + * The size of each entry stored in the `ELF Program Header`. +* The `ELF Program Header` table is an array of structures, each describing a segment or other information the system needs to prepare the program for execution. An object file segment contains one or more sections, each section holds program and control information. SimEng extracts the following from the `ELF Program Headers`: + + * The offset from the beginning of the file at which the first byte of the segment resides. + * The number of bytes in the memory image of the segment. +* SimEng uses these extracted values to loop through all `ELF Program Headers` and looks for the `ELF Program Header` located at largest virtual address range. SimEng uses the largest virtual address and size associated with that `ELF Program Header` to create an array called the ``ElfProcessImage``. Internally, SimEng treats these virtual address as physical addresses to index into said array. + +* The segment referenced by an ELF Program Header has a type attribute which explains its contents and how to interpret it. SimEng, only extracts segments of type ``LOAD`` which specifies a loadable segment. Loadable segments most notably contain the workloads' compiled instructions and initialised data that contributes to the program's memory space. This completes the creation of the ``ElfProcessImage``. + +* After the ``ElfProcessImage`` has been created the ``LinuxProcess`` class creates an array ``char[] processImage``. The size of ``processImage`` is much larger than ``ElfProcessImage`` as SimEng adds the ``HEAP_SIZE`` and ``STACK_SIZE`` values specified in the YAML configuration file to the 32-byte aligned value of ``ElfProcessImage`` size. After this, SimEng proceeds to create a process stack around ``processImage``. + +* The population of the initial stack state is based on the information `here `_. + +Currently, the only environment variable set is ``OMP_NUM_THREADS=1``, however, functionality to add more is available. For the supplied program, the ``LinuxProcess`` class supports both statically compiled binaries and raw instructions in a hexadecimal format. diff --git a/docs/sphinx/developer/concepts/memory.rst b/docs/sphinx/developer/concepts/memory.rst index 790c0efb05..df9962cee8 100644 --- a/docs/sphinx/developer/concepts/memory.rst +++ b/docs/sphinx/developer/concepts/memory.rst @@ -3,6 +3,8 @@ Memory The SimEng core models simulate everything in a core up to and including the load/store units, but stop short of the memory system. This is to allow integration and interoperability with a wide range of external memory models, and to focus the development of SimEng primarily on the simulation of the core itself. +.. _memInt: + MemoryInterface --------------- diff --git a/docs/sphinx/developer/concepts/syscalls.rst b/docs/sphinx/developer/concepts/syscalls.rst index 43ec2e4809..e9de43972c 100644 --- a/docs/sphinx/developer/concepts/syscalls.rst +++ b/docs/sphinx/developer/concepts/syscalls.rst @@ -10,4 +10,6 @@ File input/output Syscalls that interact with files are passed through to the host, in order to allow the simulated program to read and write data files on the host filesystem and interact with ``stdin``, ``stdout`` and ``stderr``. When a file is opened (e.g. with ``open`` or ``openat``), the emulated kernel maps the host file descriptor to a virtual file descriptor (``fileDescriptorTable``) which is returned to the simulated program. When handling syscalls that operate on file descriptors (e.g. ``lseek`` or ``writev``), the kernel looks up the corresponding host file descriptor in the map before passing the call onwards to the host. -The kernel detects attempts to open special files (such as those in ``/dev/`` or ``/proc``) and emulates their access inside SimEng rather than passing the call through to the host. +.. _specialDir: + +The kernel detects attempts to open special files (such as those in ``/dev/`` or ``/proc``) and emulates their access inside SimEng rather than passing the call through to the host. This is achieved by generating the most commonly accessed special files at runtime via information provided in the model :ref:`config file `. The generated special files directory can be found at ``simeng/build/specialFiles/...``. Alternatively, a user can disable the special file generation in the model config file and copy in their own directory to the same location. \ No newline at end of file diff --git a/docs/sphinx/developer/developerInfo.rst b/docs/sphinx/developer/developerInfo.rst index e3ac4740ff..9769ecc6ad 100644 --- a/docs/sphinx/developer/developerInfo.rst +++ b/docs/sphinx/developer/developerInfo.rst @@ -49,7 +49,7 @@ test that each pull request builds and passes the test suite for multiple compil before being merged. Those compilers include: - GCC 7/8/9/10 -- ARMCLANG 20 +- ARMCLANG 22 .. todo:: @@ -89,9 +89,6 @@ Directory structure ``docs/`` Documentation for users and developers -``external/`` - Third-party dependencies, as submodules - ``src/include/simeng/`` Header files for publicly visible SimEng APIs diff --git a/docs/sphinx/developer/index.rst b/docs/sphinx/developer/index.rst index cd8d651409..aa96a425a2 100644 --- a/docs/sphinx/developer/index.rst +++ b/docs/sphinx/developer/index.rst @@ -15,6 +15,7 @@ The following information is intended for those users of SimEng who wish to modi * :doc:`Simulation Components ` + * :doc:`Core Instance ` * :doc:`Pipeline ` * :doc:`Branch Prediction ` * :doc:`Register Files ` diff --git a/docs/sphinx/developer/models/index.rst b/docs/sphinx/developer/models/index.rst index e1f6d7a433..b2ae090e14 100644 --- a/docs/sphinx/developer/models/index.rst +++ b/docs/sphinx/developer/models/index.rst @@ -48,17 +48,10 @@ This model also supports speculative execution, using a supplied branch predicti Current Hardware Models ----------------------- -Through SimEng's configurable options, the above archetypes can be transformed into models based on existing processors. More information on the configurable options of SimEng can be found here. - -.. todo:: - - Insert link to user documentation configuration options Pages +Through SimEng's configurable options, the above archetypes can be transformed into models based on existing processors. More information on the configurable options of SimEng can be found :ref:`here `. The current existing processors have supplied configuration files: - `ThunderX2 `_ -- `A64FX `_ - -.. todo:: - - Insert path to config files \ No newline at end of file +- `A64FX `_ +- `M1 Firestorm `_ diff --git a/docs/sphinx/developer/test/index.rst b/docs/sphinx/developer/test/index.rst index 4f7cb479f4..8034fe3527 100644 --- a/docs/sphinx/developer/test/index.rst +++ b/docs/sphinx/developer/test/index.rst @@ -33,6 +33,7 @@ In addition to tests for the instruction functionality of the ISA, that are loca - Exception: Test non-supervisor call based exceptions. - LoadStoreQueue: Test the correct implementation of load and store instructions concerning their interaction with the LSQ. +- MicroOperation: Test the supported instruction splitting provides the correct output from the execution of said instructions. - SmokeTest: Trivial ISA related tests. - Syscall: Ensure the correct functionality of aarch64 system calls. - SystemRegisters: Ensure aarch64 system registers are correctly written to and read from. @@ -57,7 +58,7 @@ The standard structure of an AArch64 regression test body is as followed: ** Comparisons against values in the SimEng model after simulation ** } -**Note**, the ``RUN_AARCH64`` function is a proxy call to the ``run`` function in the ``RegressionTest`` class with the "aarch64" target defined. Also, helper functions for comparrisons against the SimEng model are implemented and well documented in ``test/regression/aarch64/AArch64RegressionTest.hh``. +**Note**, the ``RUN_AARCH64`` function is a proxy call to the ``run`` function in the ``RegressionTest`` class with the "aarch64" target defined. Also, helper functions for comparisons against the SimEng model are implemented and well documented in ``test/regression/aarch64/AArch64RegressionTest.hh``. Unit suite ---------- diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 791c77e773..65a3d4f6c7 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -24,24 +24,23 @@ The Simulation Engine - SimEng user/running_simeng user/configuring_simeng user/creating_binaries - user/docker SimEng is a framework for building modern, cycle-accurate processor simulators. Its goals are to be: - Fast, typically 4-5X faster than gem5 - Easy to use and modify to model desired microarchitecture configurations. New cores can be configured in just a few hours - Scalable, from simple scalar microarchitectures up to the most sophisticated, superscalar, out-of-order designs -- Capable of supporting a wide range of instruction set architectures (ISAs), starting with Armv8 but eventually including RISC-V, x86, POWER, etc. +- Capable of supporting a wide range of instruction set architectures (ISAs), starting with AArch64 but eventually including RISC-V, x86, POWER, etc. - Accurate, aiming for simulated cycle times being within 5-10% of real hardware - Open source, with a permissive license to enable collaboration across academia and industry -SimEng places an emphasis on performance and ease of use, whilst maintaining a clean, modern, simple and well-documented code base. For example, the current out-of-order (OoO) model is implemented in around 10,000 lines of simple C++, with another 9,000 lines or so implementing the specifics of the Armv8 ISA, and around 13,000 lines of code in the accompanying test suite. SimEng should be simple to read and understand, making it ideal to modify to your requirements and include it in your projects. +SimEng places an emphasis on performance and ease of use, whilst maintaining a clean, modern, simple and well-documented code base. For example, the current out-of-order (OoO) model is implemented in around 10,000 lines of simple C++, with another 16,000 lines or so implementing the specifics of the AArch64 ISA, and around 19,000 lines of code in the accompanying test suite. SimEng should be simple to read and understand, making it ideal to modify to your requirements and include it in your projects. Features -------- -Currently, SimEng targets the Armv8+SVE ISA with 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. SimEng currently models memory as an infinite L1 cache, i.e. it assumes that all loads and stores hit the L1 cache; a future release will add a proper memory hierarchy model (see the discussion about SST below). +Currently, SimEng targets the Armv9.2-a+SVE ISA with 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. SimEng currently models memory as an infinite L1 cache, i.e. it assumes that all loads and stores hit the L1 cache; a future release will add a proper memory hierarchy model (see the discussion about SST below). 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. @@ -68,7 +67,7 @@ Additionally, other works concerning SimEng and its use can be found below: Release ------- -This is SimEng's second release, so should be considered beta level software (version 0.9.0). We expect you to find issues, primarily in unimplemented instructions or unimplemented system calls. Please let us know when you hit these, either by submitting a pull request (PR), or by filing an issue on the Github repo. You can find the all the code and associated test suites for SimEng in the `GitHub repository `_. The file `RELEASE_NOTES.txt `_, found in the root of the project, explains the status of the project and includes other relevant information from the SimEng development team. +This is SimEng's sixth release, so should be considered beta level software (version 0.9.4). We expect you to find issues, primarily in unimplemented instructions or unimplemented system calls. Please let us know when you hit these, either by submitting a pull request (PR), or by filing an issue on the Github repo. You can find the all the code and associated test suites for SimEng in the `GitHub repository `_. The file `RELEASE_NOTES.txt `_, found in the root of the project, explains the status of the project and includes other relevant information from the SimEng development team. SimEng is released under the same license as LLVM, the permissive `Apache 2.0 `_ license. We are passionate about enabling experimentation with computer architectures, and want users and developers in academic and industry to have complete freedom to use SimEng anyway they wish, including using it in commercial settings. @@ -78,7 +77,7 @@ External project usage While we have tried to minimise SimEng's dependencies to keep it as simple as possible, it does make use of a small number of libraries and frameworks to provide crucial capabilities: -- `Capstone disassembly engine `_ - Provides instruction decoding for Armv8, RISC-V, x86 and other important ISAs +- `Capstone disassembly engine `_ - Provides instruction decoding for AArch64, RISC-V, x86 and other important ISAs - `Yaml-cpp `_ - Parsing YAML configuration files - `GoogleTest `_ - Framework for the test suites - `LLVM `_ - Generation of binaries for use in the regression test suite @@ -90,7 +89,6 @@ Contributors Major contributors to SimEng to date include: Project leader: - - Simon McIntosh-Smith Current development team: @@ -99,18 +97,20 @@ Current development team: - Finn Wilkinson Original SimEng design and implementation: - - Hal Jones - James Price -Additional contributions: +Current development team: +- Jack Jones (Lead Developer) +- Finn Wilkinson +- Rahat Muneeb +- Daniel Weaver +Additional Contributors: - Ainsley Rutterford - Andrei Poenaru -- Daniel Weaver - Harry Waugh - Mutalib Mohammed -- Rahat Muneeb - Seunghun Lee - Tom Hepworth - Tom Lin diff --git a/docs/sphinx/user/building_simeng.rst b/docs/sphinx/user/building_simeng.rst index 4f13411fef..2ee416abb5 100644 --- a/docs/sphinx/user/building_simeng.rst +++ b/docs/sphinx/user/building_simeng.rst @@ -18,32 +18,41 @@ Building 2. Configure with CMake, specifying the path to your desired installation directory if necessary:: +.. code-block:: text + cd SimEng - cmake -B build -S . # build files will be generated in a directory called "build" - -DCMAKE_BUILD_TYPE=Release + cmake -B build -S . + -DCMAKE_BUILD_TYPE={Release, Debug, RelWithDebInfo, MinSizeRel} -DCMAKE_INSTALL_PREFIX= - -DSIMENG_ENABLE_TESTS={ON, OFF} # Defaults to OFF - # -GNinja # enable Ninja for faster LLVM builds + -DSIMENG_ENABLE_TESTS={ON, OFF} #Defaults to OFF + +With this configuration, the build files will be generated in a directory called "build". .. - a. The SimEng test suites depend on a selection of LLVM libraries. Building this dependency can take a while, therefore, the use of prebuilt LLVM libraries is supported. The following cmake configuration flags should be set to enable this:: + a. The SimEng test suites depend on a selection of LLVM libraries. Building this dependency can take a while, therefore, the use of prebuilt LLVM libraries is supported. The following CMake configuration flags should be set to enable this:: -DSIMENG_USE_EXTERNAL_LLVM=ON -DLLVM_DIR= # directory of LLVM libraries as CMake targets .. Note:: More information about the LLVM_DIR value can be found `here `_. - -3. Once configured, use ``cmake --build build`` or whichever generator you have selected for CMake to build. Append the ``-j`` flag to build in parallel, keep in mind that building LLVM like this usually has very high (1.5GB per core) memory requirements. -4. (Optional) Run ``cmake --build build --target test`` to run the SimEng regression tests and unit tests. Please report any test failures as `a GitHub issue `_. + .. Note:: + LLVM versions greater than 12 or less than 9 are not supported. We'd recommend using LLVM 12 where possible. + + 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. + +We recommend using the `Ninja `_ build system for faster builds, especially if not using pre-built LLVM libraries. After installation, it can be enabled through the addition of the ``-GNinja`` flag in the above CMake build command. + +1. Once configured, use ``cmake --build build`` or whichever generator you have selected for CMake to build. Append the ``-j{Num_Cores}`` flag to build in parallel, keep in mind that building without a linked external LLVM library usually has very high (1.5GB per core) memory requirements. -5. Finally, run ``cmake --build build --target install`` to install SimEng to the directory specified with CMake. +2. (Optional) Run ``cmake --build build --target test`` to run the SimEng regression tests and unit tests. Please report any test failures as `a GitHub issue `_. +3. Finally, run ``cmake --build build --target install`` to install SimEng to the directory specified with CMake. -Docker ------- +.. Docker +.. ------ -We have also created a SimEng docker container, offering pre-built images with the SimEng source code and binary. More details on the docker container can be found :doc:`here`. +.. We have also created a SimEng docker container, offering pre-built images with the SimEng source code and binary. More details on the docker container can be found :doc:`here`. diff --git a/docs/sphinx/user/configuring_simeng.rst b/docs/sphinx/user/configuring_simeng.rst index 237ba87373..981a82c326 100644 --- a/docs/sphinx/user/configuring_simeng.rst +++ b/docs/sphinx/user/configuring_simeng.rst @@ -1,7 +1,9 @@ +.. _cnfSimEng: + Configuring SimEng ================== -SimEng configuration files are written in a YAML format, and provide values for the parameters of the processor architecture to be simulated. +SimEng configuration files are written in a YAML format, and provide values for the parameters of the processor architecture to be simulated. Pre-written model configuration files can be found in the ``configs/`` directory. The configuration files are split into several sections, each of which is associated with a specific area of the architecture modelled. @@ -21,7 +23,7 @@ SimEng cores can be one of three types: These core types are primarily referred to as core "archetypes". -.. Note:: Currently, the configuration files do not take into account the core archetype being modelled. However, future developments plan for the exemption of those options not used under the selected core archetype. For example, reservation station definitions under the ``inorderpiplined`` archetype will not be required. +.. Note:: Currently, the configuration files do not take into account the core archetype being modelled and require all parameters (without default values) to be defined, even if unused (e.g. reservation station definitions for an ``emulation`` core archetype). However, future developments plan for the exemption of those options not used under the selected core archetype. Configuration options within the Core section are concerned with the functionality of the simulated processor pipeline. These include: @@ -36,15 +38,26 @@ Timer Frequency i.e. For models based on an Arm ISA, this dictates how often the Virtual Counter Timer system register is updated to the number of cycles completed. This value is then accessible to programmers through ``mrs x0 CNTVCT_el0``. -Fetch-Block-sizes - The size, in bytes, of the block fetched from the instruction cache. - Micro-Operations Whether to enable instruction splitting for pre-defined Macro Operations or not. Vector-Length The vector length used by instructions belonging to ARM's Scalable Vector Extension. Supported vector lengths are those between 128 and 2048 in increments of 128. +Fetch +----- + +This section is concerned with the parameterisation of the fetch unit and its internal structures. + +Fetch-Block-Size + The size, in bytes, of the block fetched from the instruction cache. + +Loop-Buffer-Size + The number of Macro-ops which can be stored in the loop buffer. + +Loop-Detection-Threshold + The number of commits a unique branch instruction must go through, without another branch instruction being committed, before a loop is detected and the loop buffer is filled. + Process Image ------------- @@ -81,9 +94,6 @@ This section is concerned with the width of the simulated processor pipeline at Commit The commitment/retirement width from the re-order buffer. -Dispatch-Rate - The width of instruction dispatch into the reservation stations. - FrontEnd The width of the pipeline before the execution stage (also excludes the dispatch/issue stage if simulating an ``outoforder`` core archetype). @@ -114,13 +124,49 @@ The Branch-Prediction section contains those options to parameterise the branch The current options include: -BTB-bitlength - The number of bits used to denote the size of a Branch Target Buffer (BTB). For example, a ``bits`` value of 12 would denote 4096 entries with the calculation 1 << ``bits``. +BTB-Tag-Bits + The number of bits used to denote an entry in the Branch Target Buffer (BTB). For example, a ``bits`` value of 12 could denote 4096 entries with the calculation 1 << ``bits``. -L1-Cache --------- +Saturating-Count-Bits + The number of bits used in the saturating counter value. + +Global-History-Length + The number of bits used to record the global history of branch directions. Each bit represents one branch direction. + +RAS-entries + The number of entries in the Return Address Stack (RAS). + +Fallback-Static-Predictor + The static predictor used when no dynamic prediction is available. The options are either ``"Always-Taken"`` or ``"Always-Not-Taken"``. -This section contains the options used to configure SimEng's simple L1-cache. These options include: +.. _l1dcnf: + +L1-Data-Memory +-------------- + +This section describes the configuration for the L1 data cache in use. + +Interface-Type + The type of memory interface used to model the L1 data cache. Options are currently ``Flat`` or ``Fixed`` which represent a ``FlatMemoryInterface`` or ``FixedMemoryInterface`` respectively. More information concerning these interfaces can be found :ref:`here `. + +.. Note:: Currently, if the chosen ``Simulation-Mode`` option is ``emulation`` or ``inorderpipelined``, then only a ``Flat`` value is permitted. Future developments will seek to allow for more memory interfaces with these simulation archetypes. + +.. _l1icnf: + +L1-Instruction-Memory +--------------------- + +This section describes the configuration for the L1 instruction cache in use. + +Interface-Type + The type of memory interface used to model the L1 instruction cache. Options are currently ``Flat`` or ``Fixed`` which represent a ``FlatMemoryInterface`` or ``FixedMemoryInterface`` respectively. More information concerning these interfaces can be found :ref:`here `. + +.. Note:: Currently, only a ``Flat`` value is permitted for the L1 instruction cache interface. Future developments will seek to allow for more memory interfaces to be used with the L1 instruction cache. + +LSQ-L1-Interface +---------------- + +This section contains the options used to configure SimEng's interface between the LSQ and the L1 data cache. These options include: Access-Latency The cycle latency of L1 cache access. @@ -173,7 +219,7 @@ With N as the number of execution ports. Reservation-Stations -------------------- -The relationships between reservation stations and the execution ports, which reservation stations map to which execution ports, are defined in this section. The configuration of each reservation station contains a size value and a set of port names, previously defined in the Ports section. +The relationships between reservation stations and the execution ports, i.e. which reservation stations map to which execution ports, are defined in this section. The configuration of each reservation station contains a size value, a dispatch rate value, and a set of port names, previously defined in the Ports section. The following structure must be adhered to when defining a reservation station: @@ -181,6 +227,7 @@ The following structure must be adhered to when defining a reservation station: 0: Size: + Dispatch-Rate: Ports: - - ... @@ -188,6 +235,7 @@ The following structure must be adhered to when defining a reservation station: ... N-1: Size: + Dispatch-Rate: Ports: - - ... @@ -230,6 +278,8 @@ Latencies The execution latency and throughput can be configured under the Latencies section. A latency/throughput pair can be defined for a set of instruction groups, the groups available are the same as the set discussed in the Ports section. +The execution latency defines the total number of cycles an instruction will spend in an execution unit. The throughput is how many cycles an instruction will block another instruction entering the execution unit. In non-pipelined execution units, the throughput is equal to the latency. + The following structure must be adhered to when defining group latencies: .. code-block:: text @@ -254,13 +304,15 @@ With N as the number of user-defined latency mappings. The default latencies, bo **Note**, unlike other operations, the execution latency defined for load/store operations are triggered in the LoadStoreQueue as opposed to within the execution unit (more details :ref:`here `). +.. _cpu-info: + CPU Info -------- This section contains information about the physical properties of the CPU. These fields are currently only used to generate a replica of the required Special Files directory structure. Generate-Special-Dir - Values are either "T" or "F", representing True or False. + Values are either "True" or "False". Dictates whether or not SimEng should generate the SpecialFiles directory tree at runtime. The alternative to this would be to copy in the required SpecialFiles by hand. @@ -296,5 +348,5 @@ Package-Count Used to generate `/sys/devices/system/cpu/cpu{0..Core-Count}/topology/{physical_package_id, core_id}` files. On each CPU the cores are split into packages. The number of packages used can be calculated by analysing the `physical_package_id` files on a Linux system using the CPU being modelled. -.. Note:: Core-Count must be wholely divisible by Package-Count. +.. Note:: Core-Count must be wholly divisible by Package-Count. .. Note:: Max Package-Count currently supported is 1. diff --git a/docs/sphinx/user/index.rst b/docs/sphinx/user/index.rst index 315ff551d4..e29fe3a9e3 100644 --- a/docs/sphinx/user/index.rst +++ b/docs/sphinx/user/index.rst @@ -11,4 +11,4 @@ The following provides information on how to build, run, and configure SimEng. F * :doc:`Creating Binaries ` -* :doc:`SimEng docker container ` +.. * :doc:`SimEng docker container ` diff --git a/docs/sphinx/user/running_simeng.rst b/docs/sphinx/user/running_simeng.rst index b428eb8080..5d38ebe7cd 100644 --- a/docs/sphinx/user/running_simeng.rst +++ b/docs/sphinx/user/running_simeng.rst @@ -7,12 +7,31 @@ SimEng uses a configuration file and a program binary to produce a cycle-accurat /bin/simeng -If no arguments are passed to SimEng, default options are used. The default configuration file is tuned to a ThunderX2 processor, and the default program binary is defined in ``src/tools/simeng/main.cc`` under the ``hex[]`` array. +If no arguments are passed to SimEng, default options are used. The default configuration file is tuned to a ThunderX2 processor. The default program binary is defined in ``SimEng/src/include/simeng/CoreInstance.hh`` under the ``hex[]`` array which contains a set of raw instructions in a hexadecimal format. .. Note:: Paths to binaries must be in full, and not relative. Whilst a configuration file can be specified without a program (will use default program), a specified program must be accompanied by a configuration file. +Simulation Output +----------------- + +For a successful simulation, SimEng's output can be split into 4 parts; + +Build Metadata + A summary of the build options set and general information about the SimEng framework built. + +Workload Output + All outputs from the supplied workload under simulation. + +Exit Clause + The reason why the simulation has halted. Most commonly this is due to the invoking of the ``exit()`` system call by the workload under simulation. + +Statistics + A selection of simulation statistics describing the emergent simulated PMU-style hardware events. + +All non-workload outputs from SimEng are prefixed with a tag of the format ``[SimEng:Object]`` (e.g. ``[SimEng:ExceptionHandler]``). If the output came from the root of the framework, the ``Object`` field is omitted. + Configuration files ------------------- diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/AlwaysNotTakenPredictor.hh index 99ec345942..3c1bef7614 100644 --- a/src/include/simeng/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/AlwaysNotTakenPredictor.hh @@ -10,12 +10,17 @@ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ - BranchPrediction predict(std::shared_ptr& uop) override; + BranchPrediction predict(uint64_t address, BranchType type, + uint64_t knownTarget) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ - void update(std::shared_ptr& uop, bool taken, - uint64_t targetAddress) override; + void update(uint64_t address, bool taken, uint64_t targetAddress, + BranchType type) override; + + /** Provide flush logic for branch prediction scheme. As there's no flush + * logic for an always taken predictor, this does nothing. */ + void flush(uint64_t address) override; }; } // namespace simeng diff --git a/src/include/simeng/BTBPredictor.hh b/src/include/simeng/BTBPredictor.hh deleted file mode 100644 index 842625d6dd..0000000000 --- a/src/include/simeng/BTBPredictor.hh +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -#include "simeng/BranchPredictor.hh" - -namespace simeng { - -/** A Branch Target Buffer based branch predictor. Keeps an internal BTB with - * previously seen branch target buffer addresses. */ -class BTBPredictor : public BranchPredictor { - public: - /** Construct a BTB predictor, with 2^bits BTB entries. */ - BTBPredictor(uint8_t bits); - - /** Generate a branch prediction for the supplied instruction address. Finds - * the corresponding BTB entry and returns a "taken" prediction with the - * stored target. If no entry is found, predicts "not taken". */ - BranchPrediction predict(std::shared_ptr& uop) override; - - /** Update the BTB entry for the supplied instruction address with the taken - * state and targt address. */ - void update(std::shared_ptr& uop, bool taken, - uint64_t targetAddress) override; - - private: - /** The bitlength of the BTB index; BTB will have 2^bits entries. */ - uint8_t bits; - - /** A 2^bits length vector used for storing branch targets. */ - std::vector btb; - - /** A 2^bits length vector storing a presence. */ - std::vector hasValue; - - /** Generate a BTB lookup hash for the specified address by trimming the - * lowest `bits` bits. */ - uint64_t hash(uint64_t instructionAddress) const; -}; - -} // namespace simeng diff --git a/src/include/simeng/BTB_BWTPredictor.hh b/src/include/simeng/BTB_BWTPredictor.hh deleted file mode 100644 index 5a3f31d1cb..0000000000 --- a/src/include/simeng/BTB_BWTPredictor.hh +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "simeng/BranchPredictor.hh" - -namespace simeng { - -/** An A64FX based branch predictor containing a Branch Target Buffer, - * a Branch Weight Table, and a Return Address Stack implementation. */ -class BTB_BWTPredictor : public BranchPredictor { - public: - /** Construct a BTB/BWT predictor, with 2^bits rows and a - * number of entires per row defined by associative. */ - BTB_BWTPredictor(uint8_t bits, uint8_t associative); - - /** Generate a branch prediction for the supplied instruction address. - * Use a combination of a BTB entry, a global history, and an agreement - * policy. */ - BranchPrediction predict(std::shared_ptr& uop) override; - - /** Update the BTB entry for the supplied instruction address with the taken - * state and targt address. Also update the global state of the predictor*/ - void update(std::shared_ptr& uop, bool taken, - uint64_t targetAddress) override; - - private: - /** The bitlength of the BTB index; BTB will have 2^bits entries. */ - uint8_t bits; - - /** The width of each entry */ - uint8_t width; - - /** Mask for truncating values to desired number of bits. */ - uint64_t mask; - - /** An x-way associative 2^bits length vector used for storing branch targets. - */ - std::vector>> btb; - - /** The pattern history table. */ - std::vector pht; - - /** A target history for the BTB */ - uint64_t thr; - - /** A global history of branch directions in unsigned format {0|1}. */ - uint64_t ghrUnsigned; - - /** A return address stack */ - std::stack ras; - - /** Records occupied entries in BTB. */ - std::vector> touched; - - /** Records latest used associative entry of a giving BTB row. */ - std::vector associativeIndex; - - /** Records mapping between an instruction and a BTB entry. */ - std::unordered_map> mappings; - - /** Generate a BTB lookup hash for the specified address by trimming the - * lowest `bits` bits. */ - uint64_t hash(uint64_t instructionAddress) const; -}; - -} // namespace simeng diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index b3de356568..88be07dd3f 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -3,22 +3,63 @@ #include #include -#include "simeng/Instruction.hh" - namespace simeng { +/** The types of branches recognised. */ +enum class BranchType { + Conditional = 0, + LoopClosing, + Return, + SubroutineCall, + Unconditional, + Unknown +}; + +/** A branch result prediction for an instruction. */ +struct BranchPrediction { + /** Whether the branch will be taken. */ + bool taken; + + /** The branch instruction's target address. If `taken = false`, the value + * will be ignored. */ + uint64_t target; + + /** Check for equality of two branch predictions . */ + bool operator==(const BranchPrediction& other) { + if ((taken == other.taken) && (target == other.target)) + return true; + else + return false; + } + + /** Check for inequality of two branch predictions . */ + bool operator!=(const BranchPrediction& other) { + if ((taken != other.taken) || (target != other.target)) + return true; + else + return false; + } +}; + /** An abstract branch predictor interface. */ class BranchPredictor { public: virtual ~BranchPredictor(){}; - /** Generate a branch prediction for the specified instruction address. */ - virtual BranchPrediction predict(std::shared_ptr& uop) = 0; + /** Generate a branch prediction for the specified instruction address with a + * branch type and possible known target. */ + virtual BranchPrediction predict(uint64_t address, BranchType type, + uint64_t knownTarget) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. */ - virtual void update(std::shared_ptr& uop, bool taken, - uint64_t targetAddress) = 0; + virtual void update(uint64_t address, bool taken, uint64_t targetAddress, + BranchType type) = 0; + + /** Provides flushing behaviour for the implemented branch prediction schemes + * via the instruction address. + */ + virtual void flush(uint64_t address) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/Core.hh b/src/include/simeng/Core.hh index 353ba7eb11..68c2b3656a 100644 --- a/src/include/simeng/Core.hh +++ b/src/include/simeng/Core.hh @@ -33,10 +33,6 @@ class Core { /** Retrieve a map of statistics to report. */ virtual std::map getStats() const = 0; - - /** Change the value of the Virtual Counter Timer system register to number - * of cycles completed. */ - virtual void incVCT(uint64_t iterations) = 0; }; } // namespace simeng diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh new file mode 100644 index 0000000000..a8916d816e --- /dev/null +++ b/src/include/simeng/CoreInstance.hh @@ -0,0 +1,163 @@ +#pragma once + +#include + +#include "simeng/AlwaysNotTakenPredictor.hh" +#include "simeng/Core.hh" +#include "simeng/Elf.hh" +#include "simeng/FixedLatencyMemoryInterface.hh" +#include "simeng/FlatMemoryInterface.hh" +#include "simeng/GenericPredictor.hh" +#include "simeng/ModelConfig.hh" +#include "simeng/SpecialFileDirGen.hh" +#include "simeng/arch/Architecture.hh" +#include "simeng/arch/aarch64/Architecture.hh" +#include "simeng/arch/aarch64/Instruction.hh" +#include "simeng/arch/aarch64/MicroDecoder.hh" +#include "simeng/kernel/Linux.hh" +#include "simeng/models/emulation/Core.hh" +#include "simeng/models/inorder/Core.hh" +#include "simeng/models/outoforder/Core.hh" +#include "simeng/pipeline/A64FXPortAllocator.hh" +#include "simeng/pipeline/BalancedPortAllocator.hh" +#include "yaml-cpp/yaml.h" + +// Program used when no executable is provided; counts down from +// 1024*1024, with an independent `orr` at the start of each branch. +uint32_t hex_[] = { + 0x320C03E0, // orr w0, wzr, #1048576 + 0x320003E1, // orr w0, wzr, #1 + 0x71000400, // subs w0, w0, #1 + 0x54FFFFC1, // b.ne -8 + // .exit: + 0xD2800000, // mov x0, #0 + 0xD2800BC8, // mov x8, #94 + 0xD4000001, // svc #0 +}; + +namespace simeng { + +/** The available modes of simulation. */ +enum class SimulationMode { Emulation, InOrderPipelined, OutOfOrder }; + +/** A class to create a SimEng core instance from a supplied config. */ +class CoreInstance { + public: + /** Default constructor with an executable and its arguments but no model + * configuration. */ + CoreInstance(std::string executablePath, + std::vector executableArgs); + + /** Constructor with an executable, its arguments, and a model configuration. + */ + CoreInstance(std::string configPath, std::string executablePath, + std::vector executableArgs); + + ~CoreInstance(); + + /** Set the SimEng L1 instruction cache memory. */ + void setL1InstructionMemory(std::shared_ptr memRef); + + /** Set the SimEng L1 data cache memory. */ + void setL1DataMemory(std::shared_ptr memRef); + + /** Construct the core and all its associated simulation objects after the + * process and memory interfaces have been instantiated. */ + void createCore(); + + /** Getter for the set simulation mode. */ + const SimulationMode getSimulationMode() const; + + /** Getter for the set simulation mode in a string format. */ + const std::string getSimulationModeString() const; + + /** Getter for the create core object. */ + std::shared_ptr getCore() const; + + /** Getter for the create data memory object. */ + std::shared_ptr getDataMemory() const; + + /** Getter for the create instruction memory object. */ + std::shared_ptr getInstructionMemory() const; + + /** Getter for a shared pointer to the created process image. */ + std::shared_ptr getProcessImage() const; + + /** Getter for the size of the created process image. */ + const uint64_t getProcessImageSize() const; + + private: + /** Generate the appropriate simulation objects as parameterised by the + * configuration.*/ + void generateCoreModel(std::string executablePath, + std::vector executableArgs); + + /** Extract simulation mode from config file. */ + void setSimulationMode(); + + /** Construct the SimEng linux process object from command line arguments. + * Empty command line arguments denote the usage of hardcoded + * instructions held in the hex_ array. */ + void createProcess(std::string executablePath, + std::vector executableArgs); + + /** Construct the process memory from the generated process_ object. */ + void createProcessMemory(); + + /** Construct the SimEng L1 instruction cache memory. */ + void createL1InstructionMemory(const simeng::MemInterfaceType type); + + /** Construct the SimEng L1 data cache memory. */ + void createL1DataMemory(const simeng::MemInterfaceType type); + + /** Construct the special file directory. */ + void createSpecialFileDirectory(); + + /** The config file describing the modelled core to be created. */ + YAML::Node config_; + + /** Reference to the SimEng linux process object. */ + std::unique_ptr process_ = nullptr; + + /** The size of the process memory. */ + uint64_t processMemorySize_; + + /** The process memory space. */ + std::shared_ptr processMemory_; + + /** The SimEng Linux kernel object. */ + simeng::kernel::Linux kernel_; + + /** Whether or not the dataMemory_ must be set manually. */ + bool setDataMemory_ = false; + + /** Whether or not the instructionMemory_ must be set manually. */ + bool setInstructionMemory_ = false; + + /** Reference to the SimEng architecture object. */ + std::unique_ptr arch_ = nullptr; + + /** Reference to the SimEng branch predictor object. */ + std::unique_ptr predictor_ = nullptr; + + /** Reference to the SimEng port allocator object. */ + std::unique_ptr portAllocator_ = nullptr; + + /** Reference to the SimEng core object. */ + std::shared_ptr core_ = nullptr; + + /** The simulation mode in use, defaulting to emulation. */ + SimulationMode mode_ = SimulationMode::Emulation; + + /** A string format for the simulation mode in use, defaulting to emulation. + */ + std::string modeString_ = "Emulation"; + + /** Reference to the SimEng data memory object. */ + std::shared_ptr dataMemory_ = nullptr; + + /** Reference to the SimEng instruction memory object. */ + std::shared_ptr instructionMemory_ = nullptr; +}; + +} // namespace simeng diff --git a/src/include/simeng/Elf.hh b/src/include/simeng/Elf.hh index 682789692e..88e419e6a5 100644 --- a/src/include/simeng/Elf.hh +++ b/src/include/simeng/Elf.hh @@ -24,18 +24,16 @@ struct ElfHeader { /** A processed Executable and Linkable Format (ELF) file. */ class Elf { public: - Elf(std::string path); + Elf(std::string path, char** imagePointer); ~Elf(); - const span getProcessImage() const; + uint64_t getProcessImageSize() const; bool isValid() const; uint64_t getEntryPoint() const; private: uint64_t entryPoint_; std::vector headers_; - bool isValid_ = false; - char* processImage_; uint64_t processImageSize_; }; diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh new file mode 100644 index 0000000000..21df57a4a5 --- /dev/null +++ b/src/include/simeng/GenericPredictor.hh @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include + +#include "simeng/BranchPredictor.hh" +#include "yaml-cpp/yaml.h" + +namespace simeng { + +/** A generic branch predictor implementing well known/text book branch + * predictor logic. The following predictors have been included: + * + * - Static predictor based on pre-allocated branch type. + * + * - A Branch Target Buffer (BTB) with a local and global indexing scheme and a + * 2-bit saturating counter. + * + * - A Return Address Stack (RAS) is also in use. + */ + +class GenericPredictor : public BranchPredictor { + public: + /** Initialise predictor models. */ + GenericPredictor(YAML::Node config); + ~GenericPredictor(); + + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known target if not 0. Returns a branch direction and + * branch target address. */ + BranchPrediction predict(uint64_t address, BranchType type, + uint64_t knownTarget) override; + + /** Updates appropriate predictor model objects based on the address and + * outcome of the branch instruction. */ + void update(uint64_t address, bool taken, uint64_t targetAddress, + BranchType type) override; + + /** Provides RAS rewinding behaviour. */ + void flush(uint64_t address) override; + + private: + /** The bitlength of the BTB index; BTB will have 2^bits entries. */ + uint64_t btbBits_; + + /** A 2^bits length vector of pairs containing a satCntBits_-bit saturating + * counter and a branch target. */ + std::vector> btb_; + + /** The previous BTB index calculated for an address. */ + std::map btbHistory_; + + /** The number of bits used to form the saturating counter in a BTB entry. */ + uint64_t satCntBits_; + + /** A n-bit history of previous branch directions where n is equal to + * globalHistoryLength_. */ + uint64_t globalHistory_ = 0; + + /** The number of previous branch directions recorded globally. */ + uint64_t globalHistoryLength_; + + /** A return address stack. */ + std::deque ras_; + + /** RAS history with instruction address as the keys. A non-zero value + * represents the target prediction for a return instruction and a 0 entry for + * a branch-and-link instruction. */ + std::map rasHistory_; + + /** The size of the RAS. */ + uint64_t rasSize_; +}; + +} // namespace simeng diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index e6bdba2a5e..8b1cf2f9db 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -3,6 +3,7 @@ #include #include "capstone/capstone.h" +#include "simeng/BranchPredictor.hh" #include "simeng/MemoryInterface.hh" #include "simeng/RegisterFileSet.hh" #include "simeng/RegisterValue.hh" @@ -12,16 +13,6 @@ using InstructionException = short; namespace simeng { -/** A branch result prediction for an instruction. */ -struct BranchPrediction { - /** Whether the branch will be taken. */ - bool taken; - - /** The branch instruction's target address. If `taken = false`, the value - * will be ignored. */ - uint64_t target; -}; - /** An abstract instruction definition. * Each supported ISA should provide a derived implementation of this class. */ class Instruction { @@ -105,6 +96,12 @@ class Instruction { /** Was the branch taken? */ bool wasBranchTaken() const; + /** Retrieve branch type. */ + virtual BranchType getBranchType() const = 0; + + /** Retrieve a branch target from the instruction's metadata if known. */ + virtual uint64_t getKnownTarget() const = 0; + /** Is this a store address operation (a subcategory of store operations which * deal with the generation of store addresses to store data at)? */ virtual bool isStoreAddress() const = 0; @@ -119,12 +116,6 @@ class Instruction { /** Is this a branch operation? */ virtual bool isBranch() const = 0; - /** Is this a return instruction? */ - virtual bool isRET() const = 0; - - /** Is this a branch and link instruction? */ - virtual bool isBL() const = 0; - /** Set this instruction's instruction memory address. */ void setInstructionAddress(uint64_t address); @@ -134,6 +125,9 @@ class Instruction { /** Supply a branch prediction. */ void setBranchPrediction(BranchPrediction prediction); + /** Get a branch prediction. */ + BranchPrediction getBranchPrediction() const; + /** Set this instruction's sequence ID. */ void setSequenceId(uint64_t seqId); @@ -167,7 +161,7 @@ class Instruction { uint16_t getStallCycles() const; /** Get this instruction's supported set of ports. */ - virtual const std::vector& getSupportedPorts() = 0; + virtual const std::vector& getSupportedPorts() = 0; /** Is this a micro-operation? */ bool isMicroOp() const; @@ -203,14 +197,20 @@ class Instruction { // Branches /** The predicted branching result. */ - BranchPrediction prediction_; + BranchPrediction prediction_ = {false, 0}; /** A branching address calculated by this instruction during execution. */ - uint64_t branchAddress_; + uint64_t branchAddress_ = 0; /** Was the branch taken? */ bool branchTaken_ = false; + /** What type of branch this instruction is. */ + BranchType branchType_ = BranchType::Unknown; + + /** If the branch target is known at the time of decode, store it. */ + uint64_t knownTarget_ = 0; + // Flushing /** This instruction's sequence ID; a higher ID represents a chronologically * newer instruction. */ @@ -231,7 +231,7 @@ class Instruction { uint16_t stallCycles_ = 1; /** The execution ports that this instruction can be issued to. */ - std::vector supportedPorts_ = {}; + std::vector supportedPorts_ = {}; // Micro operations /** Is a resultant micro-operation from an instruction split? */ diff --git a/src/include/simeng/MemoryInterface.hh b/src/include/simeng/MemoryInterface.hh index 01d25bd57c..aeddc57d0c 100644 --- a/src/include/simeng/MemoryInterface.hh +++ b/src/include/simeng/MemoryInterface.hh @@ -5,6 +5,14 @@ namespace simeng { +/** The available memory interface types. */ +enum class MemInterfaceType { + Flat, // A zero access latency interface + Fixed, // A fixed, non-zero, access latency interface + External // An interface generated outside of the standard SimEng + // instantiation +}; + /** A generic memory access target; describes a region of memory to access. */ struct MemoryAccessTarget { /** The address to access. */ diff --git a/src/include/simeng/ModelConfig.hh b/src/include/simeng/ModelConfig.hh index e4840e94b6..1e40a1dfd1 100644 --- a/src/include/simeng/ModelConfig.hh +++ b/src/include/simeng/ModelConfig.hh @@ -14,30 +14,33 @@ #include "simeng/arch/aarch64/Instruction.hh" #include "yaml-cpp/yaml.h" -#define DEFAULT_CONFIG \ - ("{Core: {Simulation-Mode: inorderpipelined, Clock-Frequency: 2.5, " \ - "Timer-Frequency: 100, Fetch-Block-Size: 32, Micro-Operations: True, " \ - "Vector-Length: 512}, Process-Image: {Heap-Size: 10485760, Stack-Size: " \ - "1048576}, Register-Set: {GeneralPurpose-Count: 154, " \ - "FloatingPoint/SVE-Count: 90, Predicate-Count: 17, Conditional-Count: " \ - "128}, Pipeline-Widths: {Commit: 4, Dispatch-Rate: 4, FrontEnd: 4, " \ - "LSQ-Completion: 2}, Queue-Sizes: {ROB: 180, Load: 64, Store: 36}, " \ - "Branch-Predictor: {BTB-bitlength: 16}, L1-Cache: {Access-Latency: 4, " \ - "Exclusive: False, Load-Bandwidth: 32, Store-Bandwidth: 16, " \ - "Permitted-Requests-Per-Cycle: 2, Permitted-Loads-Per-Cycle: 2, " \ - "Permitted-Stores-Per-Cycle: 1}, Ports: {'0': {Portname: Port 0, " \ - "Instruction-Group-Support: [1, 8, 14]}, '1': {Portname: Port 1, " \ - "Instruction-Group-Support: [0, 14]}, '2': {Portname: Port 2, " \ - "Instruction-Group-Support: [1, 8, 71]}, '3': {Portname: Port 4, " \ - "Instruction-Group-Support: [67]}, '4': {Portname: Port 5, " \ - "Instruction-Group-Support: [67]}, '5': {Portname: Port 3, " \ - "Instruction-Group-Support: [70]}}, Reservation-Stations: {'0': {Size: " \ - "60, Ports: [0, 1, 2, 3, 4, 5]}}, Execution-Units: {'0': {Pipelined: " \ - "true}, '1': {Pipelined: true}, '2': {Pipelined: true}, '3': {Pipelined: " \ - "true}, '4': {Pipelined: true}, '5': {Pipelined: true}}, CPU-Info: " \ - "{Generate-Special-Dir: F, Core-Count: 1, Socket-Count: 1, SMT: 1, " \ - "BogoMIPS: 200.00, Features: fp asimd evtstrm atomics cpuid, " \ - "CPU-Implementer: 0x0, CPU-Architecture: 0, CPU-Variant: 0x0, CPU-Part: " \ +#define DEFAULT_CONFIG \ + ("{Core: {Simulation-Mode: inorderpipelined, Clock-Frequency: 2.5, " \ + "Timer-Frequency: 100, Micro-Operations: True, Vector-Length: 512}, " \ + "Fetch: {Fetch-Block-Size: 32, Loop-Buffer-Size: 64, " \ + "Loop-Detection-Threshold: 4}, Process-Image: {Heap-Size: 10485760, " \ + "Stack-Size: 1048576}, Register-Set: {GeneralPurpose-Count: 154, " \ + "FloatingPoint/SVE-Count: 90, Predicate-Count: 17, Conditional-Count: " \ + "128}, Pipeline-Widths: {Commit: 4, FrontEnd: 4, LSQ-Completion: 2}, " \ + "Queue-Sizes: {ROB: 180, Load: 64, Store: 36}, Branch-Predictor: " \ + "{BTB-Tag-Bits: 11, Saturating-Count-Bits: 2, Global-History-Length: 10, " \ + "RAS-entries: 5, Fallback-Static-Predictor: 2}, L1-Data-Memory: " \ + "{Interface-Type: Flat}, L1-Instruction-Memory: {Interface-Type: Flat}, " \ + "LSQ-L1-Interface: {Access-Latency: 4, Exclusive: False, Load-Bandwidth: " \ + "32, Store-Bandwidth: 16, Permitted-Requests-Per-Cycle: 2, " \ + "Permitted-Loads-Per-Cycle: 2, Permitted-Stores-Per-Cycle: 1}, Ports: " \ + "{'0': {Portname: Port 0, Instruction-Group-Support: [1, 8, 14]}, '1': " \ + "{Portname: Port 1, Instruction-Group-Support: [0, 14]}, '2': {Portname: " \ + "Port 2, Instruction-Group-Support: [1, 8, 71]}, '3': {Portname: Port 4, " \ + "Instruction-Group-Support: [67]}, '4': {Portname: Port 5, " \ + "Instruction-Group-Support: [67]}, '5': {Portname: Port 3, " \ + "Instruction-Group-Support: [70]}}, Reservation-Stations: {'0': {Size: " \ + "60, Dispatch-Rate: 4, Ports: [0, 1, 2, 3, 4, 5]}}, Execution-Units: " \ + "{'0': {Pipelined: true}, '1': {Pipelined: true}, '2': {Pipelined: true}, " \ + "'3': {Pipelined:true}, '4': {Pipelined: true}, '5': {Pipelined: true}}, " \ + "CPU-Info: {Generate-Special-Dir: false, Core-Count: 1, Socket-Count: 1, " \ + "SMT: 1, BogoMIPS: 200.00, Features: fp asimd evtstrm atomics cpuid, " \ + "CPU-Implementer: 0x0, CPU-Architecture: 0, CPU-Variant: 0x0, CPU-Part: " \ "0x0, CPU-Revision: 0, Package-Count: 1}}") namespace simeng { @@ -77,7 +80,7 @@ class ModelConfig { /** Given a node, value requirements, and possibly a deafult value, * validate the value held within the node. All methods perform, at - * least, an existance and "read as type" check with the latter + * least, an existence and "read as type" check with the latter * reading the value as the given type within a try catch * expressions. */ // Set of values requirement, no default value diff --git a/src/include/simeng/Pool.hh b/src/include/simeng/Pool.hh index fa7c3a3db8..eb2183f83c 100644 --- a/src/include/simeng/Pool.hh +++ b/src/include/simeng/Pool.hh @@ -11,7 +11,7 @@ namespace simeng { /** A class that builds a memory pool with fixed `chunk_size`. It uses a free * list to keep track of free memory. The list is stored within the memory used * by the pool. */ -template +template class fixedPool_ { static_assert(initial_size && (initial_size & (initial_size - 1)) == 0 && "initial_size is not a power of 2"); @@ -43,7 +43,7 @@ class fixedPool_ { /** Allocate more memory and add new chunks to the free list. */ bool grow() noexcept { // The space in bytes needed to fit `n_allocated` aligned chunks. - std::size_t space = sizeof(chunk) * n_allocated; + size_t space = sizeof(chunk) * n_allocated; void* ptr = operator new(space, std::nothrow); if (!ptr) return ptr; @@ -95,7 +95,7 @@ class Pool { /** Allocates `bytes` with alignment `alignof(std::max_align_t)`. If memory in * the pool is exhausted, a block of memory is allocated from the free * store. */ - void* allocate(std::uint32_t bytes) { + void* allocate(uint32_t bytes) { switch (roundUp(bytes)) { case 32: return pool32.allocate(); @@ -114,7 +114,7 @@ class Pool { /** Returns the memory at `ptr` to the memory pool. If `ptr` is a nullptr, it * is a nop. */ - void deallocate(void* ptr, std::uint32_t bytes) noexcept { + void deallocate(void* ptr, uint32_t bytes) noexcept { switch (roundUp(bytes)) { case 32: pool32.deallocate(ptr); @@ -139,7 +139,7 @@ class Pool { private: /** Round up to the nearest power of 2 that is greater than or equal to v. */ - std::uint32_t roundUp(std::uint32_t v) { + uint32_t roundUp(uint32_t v) { --v; v |= v >> 1; v |= v >> 2; @@ -156,4 +156,4 @@ class Pool { fixedPool_<256, 1024> pool256; }; -} // namespace simeng \ No newline at end of file +} // namespace simeng diff --git a/src/include/simeng/SpecialFileDirGen.hh b/src/include/simeng/SpecialFileDirGen.hh index f6ba628ba2..faf5d2fac5 100644 --- a/src/include/simeng/SpecialFileDirGen.hh +++ b/src/include/simeng/SpecialFileDirGen.hh @@ -22,8 +22,7 @@ class SpecialFileDirGen { private: /** Path to the root of the SimEng special files directory. */ - const std::string specialFilesDir_ = - SIMENG_SOURCE_DIR "/src/lib/kernel/specialFiles"; + const std::string specialFilesDir_ = SIMENG_BUILD_DIR "/specialFiles"; /** Values declared in YAML config file needed to create the Special Files * Directory tree. */ diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 2e4ea516c4..bd2f29e39e 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -14,6 +14,7 @@ using MacroOp = std::vector>; namespace arch { +/** The types of changes that can be made to values within the process state. */ enum class ChangeType { REPLACEMENT, INCREMENT, DECREMENT }; /** A structure describing a set of changes to the process state. */ @@ -66,7 +67,6 @@ class Architecture { * for a valid decoding. */ virtual uint8_t predecode(const void* ptr, uint8_t bytesAvailable, uint64_t instructionAddress, - BranchPrediction prediction, MacroOp& output) const = 0; /** Returns a vector of {size, number} pairs describing the available @@ -74,12 +74,17 @@ class Architecture { virtual std::vector getRegisterFileStructures() const = 0; - virtual uint16_t getSystemRegisterTag(uint16_t reg) const = 0; + /** Returns a zero-indexed register tag for a system register encoding. */ + virtual int32_t getSystemRegisterTag(uint16_t reg) const = 0; - /** Create an exception handler for the exception generated by `instruction`, - * providing the core model object and a reference to process memory. - * Returns a smart pointer to an `ExceptionHandler` which may be ticked until - * the exception is resolved, and results then obtained. */ + /** Returns the number of system registers that have a mapping. */ + virtual uint16_t getNumSystemRegisters() const = 0; + + /** Create an exception handler for the exception generated by + * `instruction`, providing the core model object and a reference to + * process memory. Returns a smart pointer to an `ExceptionHandler` which + * may be ticked until the exception is resolved, and results then + * obtained. */ virtual std::shared_ptr handleException( const std::shared_ptr& instruction, const Core& core, MemoryInterface& memory) const = 0; @@ -90,8 +95,9 @@ class Architecture { /** Returns the maximum size of a valid instruction in bytes. */ virtual uint8_t getMaxInstructionSize() const = 0; - /** Returns the system register for the Virtual Counter Timer. */ - virtual simeng::Register getVCTreg() const = 0; + /** Updates System registers of any system-based timers. */ + virtual void updateSystemTimerRegisters(RegisterFileSet* regFile, + const uint64_t iterations) const = 0; }; } // namespace arch diff --git a/src/include/simeng/arch/aarch64/Architecture.hh b/src/include/simeng/arch/aarch64/Architecture.hh index 6ff86364c1..d44abf250a 100644 --- a/src/include/simeng/arch/aarch64/Architecture.hh +++ b/src/include/simeng/arch/aarch64/Architecture.hh @@ -15,7 +15,7 @@ namespace simeng { namespace arch { namespace aarch64 { -/* A basic ARMv8-a implementation of the `Architecture` interface. */ +/* A basic Armv9.2-a implementation of the `Architecture` interface. */ class Architecture : public arch::Architecture { public: Architecture(kernel::Linux& kernel, YAML::Node config); @@ -24,14 +24,18 @@ class Architecture : public arch::Architecture { * instances. Returns the number of bytes consumed to produce it (always 4), * and writes into the supplied macro-op vector. */ uint8_t predecode(const void* ptr, uint8_t bytesAvailable, - uint64_t instructionAddress, BranchPrediction prediction, + uint64_t instructionAddress, MacroOp& output) const override; - /** Returns an ARMv8-a register file structure description. */ + /** Returns an Armv9.2-a register file structure description. */ std::vector getRegisterFileStructures() const override; - /** Returns a zero-indexed register tag for a system register encoding. */ - uint16_t getSystemRegisterTag(uint16_t reg) const override; + /** Returns a zero-indexed register tag for a system register encoding. + * Returns -1 in the case that the system register has no mapping. */ + int32_t getSystemRegisterTag(uint16_t reg) const override; + + /** Returns the number of system registers that have a mapping. */ + uint16_t getNumSystemRegisters() const override; /** Create an exception handler for the exception generated by `instruction`, * providing the core model object and a reference to process memory. @@ -50,8 +54,9 @@ class Architecture : public arch::Architecture { /** Returns the current vector length set by the provided configuration. */ uint64_t getVectorLength() const; - /** Returns the system register for the Virtual Counter Timer. */ - simeng::Register getVCTreg() const override; + /** Updates System registers of any system-based timers. */ + void updateSystemTimerRegisters(RegisterFileSet* regFile, + const uint64_t iterations) const override; /** Retrieve an ExecutionInfo object for the requested instruction. If a * opcode-based override has been defined for the latency and/or @@ -91,6 +96,16 @@ class Architecture : public arch::Architecture { /** The vector length used by the SVE extension in bits. */ uint64_t VL_; + + /** System Register of Virtual Counter Timer. */ + simeng::Register VCTreg_; + + /** System Register of Processor Cycle Counter. */ + simeng::Register PCCreg_; + + /** Modulo component used to define the frequency at which the VCT is updated. + */ + double vctModulo_; }; } // namespace aarch64 diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index b0030b2963..26b26cf9cf 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -32,6 +32,11 @@ std::enable_if_t && std::is_unsigned_v, T> shiftValue( amount &= mask; return (value >> amount) | (value << ((-amount) & mask)); } + case ARM64_SFT_MSL: { + // pad in with ones instead of zeros + const auto mask = (1 << amount) - 1; + return (value << amount) | mask; + } case ARM64_SFT_INVALID: return value; default: @@ -166,9 +171,10 @@ struct ExecutionInfo { uint16_t stallCycles = 1; /** The ports that support the instruction. */ - std::vector ports = {}; + std::vector ports = {}; }; +/** The various exceptions that can be raised by an individual instruction. */ enum class InstructionException { None = 0, EncodingUnallocated, @@ -179,7 +185,8 @@ enum class InstructionException { SupervisorCall, HypervisorCall, SecureMonitorCall, - NoAvailablePort + NoAvailablePort, + UnmappedSysReg }; /** The opcodes of simeng aarch64 micro-operations. */ @@ -202,7 +209,7 @@ struct MicroOpInfo { int microOpIndex = 0; }; -/** A basic ARMv8-a implementation of the `Instruction` interface. */ +/** A basic Armv9.2-a implementation of the `Instruction` interface. */ class Instruction : public simeng::Instruction { public: /** Construct an instruction instance by decoding a provided instruction word. @@ -269,6 +276,12 @@ class Instruction : public simeng::Instruction { * instruction. */ std::tuple checkEarlyBranchMisprediction() const override; + /** Retrieve branch type. */ + BranchType getBranchType() const override; + + /** Retrieve a branch target from the instruction's metadata if known. */ + uint64_t getKnownTarget() const override; + /** Is this a store address operation (a subcategory of store operations which * deal with the generation of store addresses to store data at)? */ bool isStoreAddress() const override; @@ -283,12 +296,6 @@ class Instruction : public simeng::Instruction { /** Is this a branch operation? */ bool isBranch() const override; - /** Is this a return instruction? */ - bool isRET() const override; - - /** Is this a branch and link instruction? */ - bool isBL() const override; - /** Retrieve the instruction group this instruction belongs to. */ uint16_t getGroup() const override; @@ -297,7 +304,7 @@ class Instruction : public simeng::Instruction { void setExecutionInfo(const ExecutionInfo& info); /** Get this instruction's supported set of ports. */ - const std::vector& getSupportedPorts() override; + const std::vector& getSupportedPorts() override; /** Retrieve the instruction's metadata. */ const InstructionMetadata& getMetadata() const; @@ -411,10 +418,6 @@ class Instruction : public simeng::Instruction { bool isStoreData_ = false; /** Is a branch operation. */ bool isBranch_ = false; - /** Is a return instruction. */ - bool isRET_ = false; - /** Is a branch and link instructions. */ - bool isBL_ = false; /** Is the micro-operation opcode of the instruction, where appropriate. */ uint8_t microOpcode_ = MicroOpcode::INVALID; /** Is the micro-operation opcode of the instruction, where appropriate. */ diff --git a/src/include/simeng/arch/aarch64/MicroDecoder.hh b/src/include/simeng/arch/aarch64/MicroDecoder.hh index f218526ae3..2a0f165992 100644 --- a/src/include/simeng/arch/aarch64/MicroDecoder.hh +++ b/src/include/simeng/arch/aarch64/MicroDecoder.hh @@ -85,6 +85,7 @@ class MicroDecoder { {ARM64_SFT_INVALID, 0}, ARM64_EXT_INVALID, ARM64_OP_INVALID, + ARM64_SVCR_INVALID, {}, CS_AC_READ}; diff --git a/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh b/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh index 07e508bea5..036df3f061 100644 --- a/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh +++ b/src/include/simeng/arch/aarch64/helpers/auxiliaryFunctions.hh @@ -51,7 +51,7 @@ class AuxFunc { } /** Manipulate the bitfield `value` according to the logic of the (U|S)BFM - * ARMv8 instructions. */ + * Armv9.2-a instructions. */ template static std::enable_if_t && std::is_unsigned_v, T> bitfieldManipulate(T value, T dest, uint8_t rotateBy, uint8_t sourceBits, @@ -139,16 +139,18 @@ class AuxFunc { // Rounding function that rounds a double to nearest integer (64-bit). In // event of a tie (i.e. 7.5) it will be rounded to the nearest even number. - static int64_t doubleRoundToNearestTiesToEven(double input) { - if (std::fabs(input - std::trunc(input)) == 0.5) { - if (static_cast(input - 0.5) % 2 == 0) { - return static_cast(input - 0.5); - } else { - return static_cast(input + 0.5); - } + template + static OUT roundToNearestTiesToEven(IN input) { + IN half = static_cast(0.5); + if (std::fabs(input - std::trunc(input)) == half) { + OUT truncd = static_cast(std::trunc(input)); + // if value is negative, then may need to -1 from truncd, else may need to + // +1. + OUT addand = (truncd > 0) ? 1 : -1; + return ((truncd % 2 == 0) ? truncd : (truncd + addand)); } // Otherwise round to nearest - return static_cast(std::round(input)); + return static_cast(std::round(input)); } /** Extend `value` according to `extendType`, and left-shift the result by @@ -263,12 +265,22 @@ class AuxFunc { static uint16_t sveGetPattern(const std::string operandStr, const uint8_t esize, const uint16_t VL_) { const uint16_t elements = VL_ / esize; - // If not pattern then same as ALL - if (operandStr.find(",") == std::string::npos) return elements; + 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 + } + } - // Get pattern string - std::string pattern(operandStr.substr(operandStr.find(",") + 2)); - if (pattern == "pow2") { + if (pattern == "all") + return elements; + else if (pattern == "pow2") { int n = 1; while (elements >= std::pow(2, n)) { n = n + 1; diff --git a/src/include/simeng/arch/aarch64/helpers/neon.hh b/src/include/simeng/arch/aarch64/helpers/neon.hh index e4c1307154..8caa88ce7a 100644 --- a/src/include/simeng/arch/aarch64/helpers/neon.hh +++ b/src/include/simeng/arch/aarch64/helpers/neon.hh @@ -547,6 +547,42 @@ class neonHelp { return {out, 256}; } + /** Helper function for NEON instructions with the format `umaxp vd, vn, vm`. + * T represents the type of operands (e.g. for vn.2d, T = uint64_t). + * I represents the number of elements in the output array to be updated (e.g. + * for vd.8b I = 8). + * Returns correctly formatted RegisterValue. */ + template + static RegisterValue vecUMaxP( + std::array& operands) { + const T* n = operands[0].getAsVector(); + const T* m = operands[1].getAsVector(); + + T out[I]; + for (int i = 0; i < I; i++) { + out[i] = std::max(n[i], m[i]); + } + return {out, 256}; + } + + /** Helper function for NEON instructions with the format `uminp vd, vn, vm`. + * T represents the type of operands (e.g. for vn.2d, T = uint64_t). + * I represents the number of elements in the output array to be updated (e.g. + * for vd.8b I = 8). + * Returns correctly formatted RegisterValue. */ + template + static RegisterValue vecUMinP( + std::array& operands) { + const T* n = operands[0].getAsVector(); + const T* m = operands[1].getAsVector(); + + T out[I]; + for (int i = 0; i < I; i++) { + out[i] = std::min(n[i], m[i]); + } + return {out, 256}; + } + /** Helper function for NEON instructions with the format `maxnmp rd, vn`. * T represents the type of operands (e.g. for vn.2d, T = uint64_t). * I represents the number of elements in the output array to be updated (e.g. @@ -738,6 +774,150 @@ class neonHelp { } return {out, 256}; } + + /** Helper function for NEON instructions with the format `tbl Vd.Ta, {Vn.16b, + * ... Vn+3.16b}, Vm.Ta`. + * I represents the number of elements in the output vector to be updated + * (i.e. for vd.8b I = 8, vd.16b I = 16). Only 8 or 16 is valid for TBL + * instructions. + * Returns correctly formatted RegisterValue. */ + template + static RegisterValue vecTbl( + std::array& operands, + const simeng::arch::aarch64::InstructionMetadata& metadata) { + // Vd and Vm are only valid in format 8b or 16b + assert(I == 8 || I == 16); + + // Vm contains the indices to fetch from table + const int8_t* Vm = + operands[metadata.operandCount - 2] + .getAsVector(); // final operand is vecMovi_imm + + // All operands except the first and last are the vector registers to + // construct the table from + const uint8_t n_table_regs = metadata.operandCount - 2; + + // Create table from vectors. All table operands must be of 16b format. + int tableSize = 16 * n_table_regs; + uint8_t table[tableSize]; + for (int i = 0; i < n_table_regs; i++) { + const int8_t* currentVector = operands[i].getAsVector(); + for (int j = 0; j < 16; j++) { + table[16 * i + j] = currentVector[j]; + } + } + + int8_t out[16 / sizeof(int8_t)] = {0}; + for (int i = 0; i < I; i++) { + unsigned int index = Vm[i]; + + // If an index is out of range for the table, the result for that lookup + // is 0 + if (index >= tableSize) { + out[i] = 0; + continue; + } + + out[i] = table[index]; + } + return {out, 256}; + } + + /** Helper function for NEON instructions with the format `rev<16,32,64> Vd.T, + * Vn.T`. + * T represents the type of elements to be reversed (e.g. for Vn.d, T = + * uint64_t). + * V represents the variant: 16-bit, 32-bit, 64-bit. (e.g. for 64-bit each + * doubleword of the vector will be reversed). + * I represents the number of elements in the output array to be updated (e.g. + * for vd.8b I = 8). + * It is only valid for T to be a same or smaller width than V. + * Returns correctly formatted RegisterValue. */ + template + static RegisterValue vecRev( + std::array& operands) { + const T* source = operands[0].getAsVector(); + int element_size = (sizeof(T) * 8); + int datasize = I * element_size; + int container_size = V; + int n_containers = datasize / container_size; + int elements_per_container = container_size / element_size; + + int element = 0; + int rev_element; + T out[16 / sizeof(T)] = {0}; + for (int c = 0; c < n_containers; c++) { + rev_element = element + elements_per_container - 1; + for (int e = 0; e < elements_per_container; e++) { + out[rev_element] = source[element]; + element++; + rev_element--; + } + } + return {out, 256}; + } + + /** Helper function for NEON instructions with the format `trn1 Vd.T, Vn.T, + * Vm.T`. + * T represents the type of operands (e.g. for vn.d, T = uint64_t). + * I represents the number of operands (e.g. for vn.8b, I = 8). + * Returns formatted Register Value. */ + template + static RegisterValue vecTrn1( + std::array& operands) { + const T* n = operands[0].getAsVector(); + const T* m = operands[1].getAsVector(); + + T out[16 / sizeof(T)] = {0}; + for (int i = 0; i < I / 2; i++) { + out[2 * i] = n[2 * i]; + out[(2 * i) + 1] = m[2 * i]; + } + + return {out, 256}; + } + + /** Helper function for NEON instructions with the format `trn2 Vd.T, Vn.T, + * Vm.T`. + * T represents the type of operands (e.g. for Vn.d, T = uint64_t). + * I represents the number of operands (e.g. for Vn.8b, I = 8). + * Returns formatted Register Value. */ + template + static RegisterValue vecTrn2( + std::array& operands) { + const T* n = operands[0].getAsVector(); + const T* m = operands[1].getAsVector(); + + T out[16 / sizeof(T)] = {0}; + for (int i = 0; i < I / 2; i++) { + out[2 * i] = n[(2 * i) + 1]; + out[(2 * i) + 1] = m[(2 * i) + 1]; + } + + return {out, 256}; + } + + /** Helper function for NEON instructions with the format `uzp<1,2> Vd.T, + * Vn.T, Vm.T`. + * T represents the type of operands (e.g. for Vn.d, T = uint64_t). + * I represents the number of operands (e.g. for Vn.8b, I = 8). + * Returns formatted Register Value. */ + template + static RegisterValue vecUzp( + std::array& operands, + bool isUzp1) { + const T* n = operands[0].getAsVector(); + const T* m = operands[1].getAsVector(); + + T out[16 / sizeof(T)] = {0}; + for (int i = 0; i < I / 2; i++) { + int index = isUzp1 ? (2 * i) : (2 * i) + 1; + out[i] = n[index]; + out[(I / 2) + i] = m[index]; + } + + return {out, 256}; + } }; } // namespace aarch64 } // namespace arch diff --git a/src/include/simeng/arch/aarch64/helpers/sve.hh b/src/include/simeng/arch/aarch64/helpers/sve.hh index 7905c29658..fdb2a01c9b 100644 --- a/src/include/simeng/arch/aarch64/helpers/sve.hh +++ b/src/include/simeng/arch/aarch64/helpers/sve.hh @@ -162,7 +162,10 @@ class sveHelp { const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { const uint8_t imm = static_cast(metadata.operands[1].imm); - return (uint64_t)((VL_bits / (sizeof(T) * 8)) * imm); + + const uint16_t elems = + AuxFunc::sveGetPattern(metadata.operandStr, (sizeof(T) * 8), VL_bits); + return (uint64_t)(elems * imm); } /** Helper function for SVE instructions with the format `cntp xd, pg, pn`. @@ -244,15 +247,16 @@ class sveHelp { * pattern{, MUL #imm}}`. * T represents the type of operation (e.g. for DECD, T = uint64_t). * Returns single value of type uint64_t. */ - // TODO : Add support for patterns template - static uint64_t sveDec_scalar( + static int64_t sveDec_scalar( std::array& operands, const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { - const uint64_t n = operands[0].get(); + const int64_t n = operands[0].get(); const uint8_t imm = static_cast(metadata.operands[1].imm); - return (n - ((VL_bits / (sizeof(T) * 8)) * imm)); + const uint16_t elems = + AuxFunc::sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + return (n - static_cast(elems * imm)); } /** Helper function for SVE instructions with the format `dup zd, <#imm{, @@ -331,16 +335,16 @@ class sveHelp { } /** Helper function for SVE instructions with the format `fadda rd, - * pg/m, rn, zm`. + * pg, rn, zm`. * T represents the type of operands (e.g. for zm.d, T = uint64_t). * Returns correctly formatted RegisterValue. */ template static RegisterValue sveFaddaPredicated( std::array& operands, const uint16_t VL_bits) { - const uint64_t* p = operands[1].getAsVector(); - const T n = operands[2].get(); - const T* m = operands[3].getAsVector(); + const uint64_t* p = operands[0].getAsVector(); + const T n = operands[1].get(); + const T* m = operands[2].getAsVector(); const uint16_t partition_num = VL_bits / (sizeof(T) * 8); T out[256 / sizeof(T)] = {0}; @@ -663,8 +667,9 @@ class sveHelp { static RegisterValue sveFnegPredicated( std::array& operands, const uint16_t VL_bits) { - const uint64_t* p = operands[0].getAsVector(); - const T* n = operands[1].getAsVector(); + const T* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + const T* n = operands[2].getAsVector(); const uint16_t partition_num = VL_bits / (sizeof(T) * 8); T out[256 / sizeof(T)] = {0}; @@ -674,7 +679,7 @@ class sveHelp { if (p[i / (64 / sizeof(T))] & shifted_active) out[i] = -n[i]; else - out[i] = n[i]; + out[i] = d[i]; } return {out, 256}; } @@ -735,7 +740,7 @@ class sveHelp { * zn`. * D represents the destination vector register type (e.g. zd.s would be * int32_t). - * N represents the source vector register type (e.g. zd.d would be + * N represents the source vector register type (e.g. zn.d would be * double). * Returns correctly formatted RegisterValue. */ template @@ -751,10 +756,11 @@ class sveHelp { for (int i = 0; i < partition_num; i++) { uint64_t shifted_active = 1ull << ((i % (64 / sizeof(N))) * sizeof(N)); - if (p[i / (64 / sizeof(N))] & shifted_active) - out[i] = AuxFunc::doubleRoundToNearestTiesToEven(n[i]); - else + if (p[i / (64 / sizeof(N))] & shifted_active) { + out[i] = AuxFunc::roundToNearestTiesToEven(n[i]); + } else { out[i] = d[i]; + } } return {out, 256}; } @@ -784,17 +790,19 @@ class sveHelp { } /** Helper function for SVE instructions with the format `inc - * xdn{, pattern{, #imm}}`. + * xdn{, pattern{, MUL #imm}}`. * T represents the type of operation (e.g. for INCB, T = int8_t). - * Returns single value of type uint64_t. */ + * Returns single value of type int64_t. */ template - static uint64_t sveInc_gprImm( + static int64_t sveInc_gprImm( std::array& operands, const simeng::arch::aarch64::InstructionMetadata& metadata, const uint16_t VL_bits) { - const uint64_t n = operands[0].get(); + const int64_t n = operands[0].get(); const uint8_t imm = static_cast(metadata.operands[1].imm); - uint64_t out = n + ((VL_bits / (sizeof(T) * 8)) * imm); + const uint16_t elems = + AuxFunc::sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + int64_t out = n + (elems * imm); return out; } @@ -812,9 +820,11 @@ class sveHelp { const uint16_t partition_num = VL_bits / (sizeof(T) * 8); typename std::make_signed::type out[256 / sizeof(T)] = {0}; + const uint16_t elems = + AuxFunc::sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); for (int i = 0; i < partition_num; i++) { - out[i] = n[i] + ((VL_bits / (sizeof(T) * 8)) * imm); + out[i] = n[i] + (elems * imm); } return {out, 256}; } @@ -894,7 +904,7 @@ class sveHelp { } /** Helper function for SVE instructions with the format ` - * zd, pg/z, zn, zm`. + * zd, pg/m, zn, zm`. * T represents the type of operands (e.g. for zn.d, T = uint64_t). * Returns correctly formatted RegisterValue. */ template @@ -1062,7 +1072,7 @@ class sveHelp { return {out, 256}; } - /** Helper function for SVE instructions with the format `mul zd, pg/m, zn, + /** Helper function for SVE instructions with the format `mul zdn, pg/m, zdn, * `. * T represents the type of operands (e.g. for zn.d, T = uint64_t). * Returns correctly formatted RegisterValue. */ @@ -1170,6 +1180,8 @@ class sveHelp { // Get pattern const uint16_t count = AuxFunc::sveGetPattern(metadata.operandStr, sizeof(T) * 8, VL_bits); + // Exit early if count == 0 + if (count == 0) return out; for (int i = 0; i < partition_num; i++) { if (i < count) { @@ -1248,7 +1260,7 @@ class sveHelp { return {out, 256}; } - /** Helper function for SVE instructions with the format `sel zd, pg/z, zn, + /** Helper function for SVE instructions with the format `sel zd, pg, zn, * zm`. * T represents the type of operands (e.g. for zn.d, T = uint64_t). * Returns correctly formatted RegisterValue. */ @@ -1469,15 +1481,17 @@ class sveHelp { const uint16_t VL_bits) { const D d = operands[0].get(); const uint8_t imm = metadata.operands[1].imm; + const uint16_t count = + AuxFunc::sveGetPattern(metadata.operandStr, 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 // be saturated to fit in uint64_t. - auto intermediate = double(d) - (imm * (VL_bits / N)); + auto intermediate = double(d) - (imm * count); if (intermediate < 0) { return (uint64_t)0; } - return (uint64_t)(d - (imm * (VL_bits / N))); + return (uint64_t)(d - (imm * count)); } /** Helper function for SVE instructions with the format `uzp<1,2> zd, zn, diff --git a/src/include/simeng/kernel/Linux.hh b/src/include/simeng/kernel/Linux.hh index ff23f5429a..0e7e31763f 100644 --- a/src/include/simeng/kernel/Linux.hh +++ b/src/include/simeng/kernel/Linux.hh @@ -250,8 +250,7 @@ class Linux { std::unordered_map specialPathTranslations_; /** Path to the root of the replacement special files. */ - const std::string specialFilesDir_ = - SIMENG_SOURCE_DIR "/src/lib/kernel/specialFiles"; + const std::string specialFilesDir_ = SIMENG_BUILD_DIR "/specialFiles"; /** Vector of all currently supported special file paths & files.*/ std::vector supportedSpecialFiles_; diff --git a/src/include/simeng/kernel/LinuxProcess.hh b/src/include/simeng/kernel/LinuxProcess.hh index 32a286fe82..9796b52937 100644 --- a/src/include/simeng/kernel/LinuxProcess.hh +++ b/src/include/simeng/kernel/LinuxProcess.hh @@ -1,5 +1,7 @@ #pragma once +#include + #include "simeng/Elf.hh" #include "yaml-cpp/yaml.h" @@ -57,8 +59,11 @@ class LinuxProcess { /** Get the page size. */ uint64_t getPageSize() const; - /** Get the process image. */ - const span getProcessImage() const; + /** Get a shared_ptr to process image. */ + std::shared_ptr getProcessImage() const; + + /** Get the size of the process image. */ + uint64_t getProcessImageSize() const; /** Get the entry point. */ uint64_t getEntryPoint() const; @@ -80,7 +85,7 @@ class LinuxProcess { const uint64_t HEAP_SIZE; /** Create and populate the initial process stack. */ - void createStack(); + void createStack(char** processImage); /** The entry point of the process. */ uint64_t entryPoint_ = 0; @@ -97,9 +102,6 @@ class LinuxProcess { /** The address of the stack pointer. */ uint64_t stackPointer_; - /** The process image. */ - char* processImage_; - /** The process image size. */ uint64_t size_; @@ -108,6 +110,9 @@ class LinuxProcess { /** Whether the process image was created successfully. */ bool isValid_ = false; + + /** Shared pointer to processImage. */ + std::shared_ptr processImage_; }; } // namespace kernel diff --git a/src/include/simeng/models/emulation/Core.hh b/src/include/simeng/models/emulation/Core.hh index 1ad64fd0f2..9152c6df03 100644 --- a/src/include/simeng/models/emulation/Core.hh +++ b/src/include/simeng/models/emulation/Core.hh @@ -44,10 +44,6 @@ class Core : public simeng::Core { /** Retrieve a map of statistics to report. */ std::map getStats() const override; - /** Change the value of the Virtual Counter Timer system register to number - * of cycles completed. */ - void incVCT(uint64_t iterations) override; - private: /** Execute an instruction. */ void execute(std::shared_ptr& uop); @@ -109,9 +105,6 @@ class Core : public simeng::Core { /** The number of branches executed. */ uint64_t branchesExecuted_ = 0; - - /** System Register of Virtual Counter Timer. */ - simeng::Register VCTreg_; }; } // namespace emulation diff --git a/src/include/simeng/models/inorder/Core.hh b/src/include/simeng/models/inorder/Core.hh index 722e5963c4..080564f7b7 100644 --- a/src/include/simeng/models/inorder/Core.hh +++ b/src/include/simeng/models/inorder/Core.hh @@ -20,7 +20,7 @@ class Core : public simeng::Core { /** Construct a core model, providing an ISA and branch predictor to use, * along with a pointer and size of instruction memory, and a pointer to * process memory. */ - Core(FlatMemoryInterface& instructionMemory, FlatMemoryInterface& dataMemory, + Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, uint64_t processMemorySize, uint64_t entryPoint, const arch::Architecture& isa, BranchPredictor& branchPredictor); @@ -45,10 +45,6 @@ class Core : public simeng::Core { /** Generate a map of statistics to report. */ std::map getStats() const override; - /** Change the value of the Virtual Counter Timer system register to number - * of cycles completed. */ - void incVCT(uint64_t iterations) override; - private: /** Raise an exception to the core, providing the generating instruction. */ void raiseException(const std::shared_ptr& instruction); @@ -136,9 +132,6 @@ class Core : public simeng::Core { /** The active exception handler. */ std::shared_ptr exceptionHandler_; - - /** System Register of Virtual Counter Timer. */ - simeng::Register VCTreg_; }; } // namespace inorder diff --git a/src/include/simeng/models/outoforder/Core.hh b/src/include/simeng/models/outoforder/Core.hh index 56440941b3..0a1240ab09 100644 --- a/src/include/simeng/models/outoforder/Core.hh +++ b/src/include/simeng/models/outoforder/Core.hh @@ -29,9 +29,7 @@ class Core : public simeng::Core { Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, uint64_t processMemorySize, uint64_t entryPoint, const arch::Architecture& isa, BranchPredictor& branchPredictor, - pipeline::PortAllocator& portAllocator, - const std::vector>& rsArrangment, - YAML::Node config); + pipeline::PortAllocator& portAllocator, YAML::Node config); /** Tick the core. Ticks each of the pipeline stages sequentially, then ticks * the buffers between them. Checks for and executes pipeline flushes at the @@ -54,10 +52,6 @@ class Core : public simeng::Core { /** Generate a map of statistics to report. */ std::map getStats() const override; - /** Change the value of the Virtual Counter Timer system register to number - * of cycles completed. */ - void incVCT(uint64_t iterations) override; - private: /** Raise an exception to the core, providing the generating instruction. */ void raiseException(const std::shared_ptr& instruction); @@ -114,12 +108,12 @@ class Core : public simeng::Core { /** The core's load/store queue. */ pipeline::LoadStoreQueue loadStoreQueue_; - /** The core's reorder buffer. */ - pipeline::ReorderBuffer reorderBuffer_; - /** The fetch unit; fetches instructions from memory. */ pipeline::FetchUnit fetchUnit_; + /** The core's reorder buffer. */ + pipeline::ReorderBuffer reorderBuffer_; + /** The decode unit; decodes instructions into uops and reads operands. */ pipeline::DecodeUnit decodeUnit_; @@ -166,9 +160,6 @@ class Core : public simeng::Core { /** The active exception handler. */ std::shared_ptr exceptionHandler_; - - /** System Register of Virtual Counter Timer. */ - simeng::Register VCTreg_; }; } // namespace outoforder diff --git a/src/include/simeng/pipeline/A64FXPortAllocator.hh b/src/include/simeng/pipeline/A64FXPortAllocator.hh index 38a0294cae..74f27faf25 100644 --- a/src/include/simeng/pipeline/A64FXPortAllocator.hh +++ b/src/include/simeng/pipeline/A64FXPortAllocator.hh @@ -23,14 +23,14 @@ class A64FXPortAllocator : public PortAllocator { public: A64FXPortAllocator(const std::vector>& portArrangement); - uint8_t allocate(const std::vector& ports) override; + uint16_t allocate(const std::vector& ports) override; - void issued(uint8_t port) override; + void issued(uint16_t port) override; - void deallocate(uint8_t port) override; + void deallocate(uint16_t port) override; /** A mapping from issye ports to instruction attribute */ - uint8_t attributeMapping(const std::vector& ports); + uint8_t attributeMapping(const std::vector& ports); /** Set function from DispatchIssueUnit to retrieve reservation * station sizes during execution. */ @@ -50,7 +50,7 @@ class A64FXPortAllocator : public PortAllocator { std::function&)> rsSizes_; /** Mapping from reservation station to ports. */ - std::vector> rsToPort_; + std::vector> rsToPort_; /** Vector of free entires across all reservation stations. */ std::vector freeEntries_; @@ -65,16 +65,16 @@ class A64FXPortAllocator : public PortAllocator { /** RSA with least free entries. */ uint8_t RSAf_; - const std::vector EXA_EXB_EAGA_EAGB = {2, 4, 5, 6}; - const std::vector EXA_EXB = {2, 4}; - const std::vector FLA_FLB = {0, 3}; - const std::vector EAGA_EAGB = {5, 6}; - const std::vector EXA = {2}; - const std::vector FLA = {0}; - const std::vector PR = {1}; - const std::vector EXB = {4}; - const std::vector FLB = {3}; - const std::vector BR = {7}; + const std::vector EXA_EXB_EAGA_EAGB = {2, 4, 5, 6}; + const std::vector EXA_EXB = {2, 4}; + const std::vector FLA_FLB = {0, 3}; + const std::vector EAGA_EAGB = {5, 6}; + const std::vector EXA = {2}; + const std::vector FLA = {0}; + const std::vector PR = {1}; + const std::vector EXB = {4}; + const std::vector FLB = {3}; + const std::vector BR = {7}; }; } // namespace pipeline diff --git a/src/include/simeng/pipeline/BalancedPortAllocator.hh b/src/include/simeng/pipeline/BalancedPortAllocator.hh index 236cd9fbe0..ccd550718d 100644 --- a/src/include/simeng/pipeline/BalancedPortAllocator.hh +++ b/src/include/simeng/pipeline/BalancedPortAllocator.hh @@ -23,13 +23,13 @@ class BalancedPortAllocator : public PortAllocator { /** Allocate the lowest weighted port available for the specified instruction * group. Returns the allocated port, and increases the weight of the port. */ - uint8_t allocate(const std::vector& ports) override; + uint16_t allocate(const std::vector& ports) override; /** Decrease the weight for the specified port. */ - void issued(uint8_t port) override; + void issued(uint16_t port) override; /** Decrease the weight for the specified port. */ - void deallocate(uint8_t port) override; + void deallocate(uint16_t port) override; /** Set function from DispatchIssueUnit to retrieve reservation * station sizes during execution. */ diff --git a/src/include/simeng/pipeline/DispatchIssueUnit.hh b/src/include/simeng/pipeline/DispatchIssueUnit.hh index 91cbc3fb29..4cc095bb65 100644 --- a/src/include/simeng/pipeline/DispatchIssueUnit.hh +++ b/src/include/simeng/pipeline/DispatchIssueUnit.hh @@ -3,12 +3,14 @@ #include #include #include +#include #include #include #include "simeng/Instruction.hh" #include "simeng/pipeline/PipelineBuffer.hh" #include "simeng/pipeline/PortAllocator.hh" +#include "yaml-cpp/yaml.h" namespace simeng { namespace pipeline { @@ -16,7 +18,7 @@ namespace pipeline { /** A reservation station issue port */ struct ReservationStationPort { /** Issue port this port maps to */ - uint8_t issuePort; + uint16_t issuePort; /** Queue of instructions that are ready to be * issued */ std::deque> ready; @@ -26,6 +28,8 @@ struct ReservationStationPort { struct ReservationStation { /** Size of reservation station */ uint16_t capacity; + /** Number of instructions that can be dispatched to this unit per cycle. */ + uint16_t dispatchRate; /** Current number of non-stalled instructions * in reservation station */ uint16_t currentSize; @@ -38,7 +42,7 @@ struct dependencyEntry { /** The instruction to execute. */ std::shared_ptr uop; /** The port to issue to. */ - uint8_t port; + uint16_t port; /** The operand waiting on a value. */ uint8_t operandIndex; }; @@ -56,8 +60,7 @@ class DispatchIssueUnit { std::vector>>& issuePorts, const RegisterFileSet& registerFileSet, PortAllocator& portAllocator, const std::vector& physicalRegisterStructure, - std::vector> rsArrangment, - uint8_t dispatchRate = UINT8_MAX); + YAML::Node config); /** Ticks the dispatch/issue unit. Reads available input operands for * instructions and sets scoreboard flags for destination registers. */ @@ -113,12 +116,8 @@ class DispatchIssueUnit { /** Reservation stations */ std::vector reservationStations_; - /** Stores the number of instructions dispatched each cycle, for each - reservation station. */ - std::vector dispatches = {}; - /** A mapping from port to RS port */ - std::vector> portMapping_; + std::vector> portMapping_; /** A dependency matrix, containing all the instructions waiting on an * operand. For a register `{type,tag}`, the vector of dependents may be found @@ -126,16 +125,12 @@ class DispatchIssueUnit { std::vector>> dependencyMatrix_; /** A map to collect flushed instructions for each reservation station. */ - std::unordered_map>> + std::unordered_map>> flushed_; /** A reference to the execution port allocator. */ PortAllocator& portAllocator_; - /** The number of instructions that can be dispatched to a reservation station - * per cycle. */ - uint64_t dispatchRate_; - /** The number of cycles stalled due to a full reservation station. */ uint64_t rsStalls_ = 0; diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index d76f81c1fb..46de523393 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -1,5 +1,7 @@ #pragma once +#include + #include "simeng/MemoryInterface.hh" #include "simeng/arch/Architecture.hh" #include "simeng/pipeline/PipelineBuffer.hh" @@ -7,6 +9,29 @@ namespace simeng { namespace pipeline { +/** The various states of the loop buffer. */ +enum class LoopBufferState { + IDLE = 0, // No operations + WAITING, // Waiting to find boundary instruction in fetch stream + FILLING, // Filling loop buffer with loop body + SUPPLYING // Feeding loop buffer content to output buffer +}; + +// Struct to hold information about a fetched instruction +struct loopBufferEntry { + // Encoding of the instruction + const uint64_t encoding; + + // Size of the instruction + const uint16_t instructionSize; + + // PC of the instruction + const uint64_t address; + + // Branch prediction made for instruction + const BranchPrediction prediction; +}; + /** A fetch and pre-decode unit for a pipelined processor. Responsible for * reading instruction memory and maintaining the program counter. */ class FetchUnit { @@ -23,6 +48,9 @@ class FetchUnit { * current program counter. */ void tick(); + /** Function handle to retrieve branch that represents loop boundary. */ + void registerLoopBoundary(uint64_t branchAddress); + /** Check whether the program has ended. Returns `true` if the current PC is * outside of instruction memory. */ bool hasHalted() const; @@ -37,6 +65,9 @@ class FetchUnit { * branch. */ uint64_t getBranchStalls() const; + /** Clear the loop buffer. */ + void flushLoopBuffer(); + private: /** An output buffer connecting this unit to the decode unit. */ PipelineBuffer& output_; @@ -56,6 +87,15 @@ class FetchUnit { /** Reference to the current branch predictor. */ BranchPredictor& branchPredictor_; + /** A loop buffer to supply a detected loop instruction stream. */ + std::deque loopBuffer_; + + /** State of the loop buffer. */ + LoopBufferState loopBufferState_ = LoopBufferState::IDLE; + + /** The branch instruction that forms the loop. */ + uint64_t loopBoundaryAddress_ = 0; + /** The current program halt state. Set to `true` when the PC leaves the * instruction memory region, and set back to `false` if the PC is returned to * the instruction region. */ @@ -66,6 +106,7 @@ class FetchUnit { /** The size of a fetch block, in bytes. */ uint8_t blockSize_; + /** A mask of the bits of the program counter to use for obtaining the block * address to fetch. */ uint64_t blockMask_; diff --git a/src/include/simeng/pipeline/LoadStoreQueue.hh b/src/include/simeng/pipeline/LoadStoreQueue.hh index a5aa6332ca..a1cad904ee 100644 --- a/src/include/simeng/pipeline/LoadStoreQueue.hh +++ b/src/include/simeng/pipeline/LoadStoreQueue.hh @@ -13,6 +13,7 @@ namespace simeng { namespace pipeline { +/** The memory access types which are processed. */ enum accessType { LOAD = 0, STORE }; /** A requestQueue_ entry. */ @@ -34,9 +35,11 @@ class LoadStoreQueue { unsigned int maxCombinedSpace, MemoryInterface& memory, span>> completionSlots, std::function, span)> forwardOperands, - bool exclusive = false, uint8_t loadBandwidth = UINT8_MAX, - uint8_t storeBandwidth = UINT8_MAX, uint8_t permittedRequests = UINT8_MAX, - uint8_t permittedLoads = UINT8_MAX, uint8_t permittedStores = UINT8_MAX); + bool exclusive = false, uint16_t loadBandwidth = UINT16_MAX, + uint16_t storeBandwidth = UINT16_MAX, + uint16_t permittedRequests = UINT16_MAX, + uint16_t permittedLoads = UINT16_MAX, + uint16_t permittedStores = UINT16_MAX); /** Constructs a split load/store queue model, simulating discrete queues for * load and store instructions, supplying completion slots for loads and an @@ -46,9 +49,11 @@ class LoadStoreQueue { MemoryInterface& memory, span>> completionSlots, std::function, span)> forwardOperands, - bool exclusive = false, uint8_t loadBandwidth = UINT8_MAX, - uint8_t storeBandwidth = UINT8_MAX, uint8_t permittedRequests = UINT8_MAX, - uint8_t permittedLoads = UINT8_MAX, uint8_t permittedStores = UINT8_MAX); + bool exclusive = false, uint16_t loadBandwidth = UINT16_MAX, + uint16_t storeBandwidth = UINT16_MAX, + uint16_t permittedRequests = UINT16_MAX, + uint16_t permittedLoads = UINT16_MAX, + uint16_t permittedStores = UINT16_MAX); /** Retrieve the available space for load uops. For combined queue this is the * total remaining space. */ @@ -173,16 +178,16 @@ class LoadStoreQueue { bool exclusive_; /** The amount of data readable from the L1D cache per cycle. */ - uint64_t loadBandwidth_; + uint16_t loadBandwidth_; /** The amount of data writable to the L1D cache per cycle. */ - uint64_t storeBandwidth_; + uint16_t storeBandwidth_; /** The combined limit of loads and store requests permitted per cycle. */ - uint8_t totalLimit_; + uint16_t totalLimit_; /** The number of loads and stores permitted per cycle. */ - std::array reqLimits_; + std::array reqLimits_; }; } // namespace pipeline diff --git a/src/include/simeng/pipeline/M1PortAllocator.hh b/src/include/simeng/pipeline/M1PortAllocator.hh new file mode 100644 index 0000000000..1139f9bc8a --- /dev/null +++ b/src/include/simeng/pipeline/M1PortAllocator.hh @@ -0,0 +1,63 @@ +#pragma once + +#include +#include + +#include "simeng/pipeline/PortAllocator.hh" + +namespace simeng { +namespace pipeline { + +/** A load-balancing port allocator implementation. Maintains demand weightings + * for each port, and allocates instructions to the suitable port with the + * lowest weighting. */ +class M1PortAllocator : public PortAllocator { + public: + /** Construct a load-balancing port allocator, providing a port arrangement + * specification. Each element of the port arrangement should represent a + * port, and contain a list of the instruction groups that port supports and + * a port type which denotes the matching requirements of said instruction + * groups. */ + M1PortAllocator(const std::vector>& portArrangement, + std::vector> rsArrangement); + + /** Allocate the lowest weighted port available for the specified instruction + * group. Returns the allocated port, and increases the weight of the port. + */ + uint16_t allocate(const std::vector& ports) override; + + /** Decrease the weight for the specified port. */ + void issued(uint16_t port) override; + + /** Decrease the weight for the specified port. */ + void deallocate(uint16_t port) override; + + /** Set function from DispatchIssueUnit to retrieve reservation + * station sizes during execution. */ + void setRSSizeGetter( + std::function&)> rsSizes) override; + + /** Tick the port allocator to allow it to process internal tasks. */ + void tick() override; + + private: + /** The instruction group support matrix. An instruction-group-indexed map + * containing lists of the ports that support each instruction group. */ + std::vector> supportMatrix; + + /** The port weighting map. Each element corresponds to a port, and contains a + * weighting representing the number of in-flight instructions allocated to + * that port. */ + std::vector weights; + + std::vector rsFreeSpaces; + + /** Get the current capacity of the reservation stations */ + std::function&)> rsSizes_; + + /** Mapping from port index to reservation station */ + std::vector> rsArrangement_; +}; + +} // namespace pipeline +} // namespace simeng diff --git a/src/include/simeng/pipeline/PortAllocator.hh b/src/include/simeng/pipeline/PortAllocator.hh index b71c63b9c7..8d6f79a5f8 100644 --- a/src/include/simeng/pipeline/PortAllocator.hh +++ b/src/include/simeng/pipeline/PortAllocator.hh @@ -20,15 +20,15 @@ class PortAllocator { /** Allocate a port for the specified instruction group; returns the allocated * port. */ - virtual uint8_t allocate(const std::vector& ports) = 0; + virtual uint16_t allocate(const std::vector& ports) = 0; /** Inform the allocator that an instruction was issued to the specified port. */ - virtual void issued(uint8_t port) = 0; + virtual void issued(uint16_t port) = 0; /** Inform the allocator that an instruction will not issue to its * allocated port. */ - virtual void deallocate(uint8_t port) = 0; + virtual void deallocate(uint16_t port) = 0; /** Set function from DispatchIssueUnit to retrieve reservation * station sizes during execution. */ diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index 49baa0becc..25929097cc 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -10,6 +10,19 @@ namespace simeng { namespace pipeline { +/** A branch prediction outcome with an associated instruction address. */ +struct latestBranch { + /** Branch instruction address. */ + uint64_t address; + + /** Outcome of the branch. */ + BranchPrediction outcome; + + /** The related instructionsCommitted_ value that this instruction was + * committed on. */ + uint64_t commitNumber; +}; + /** A Reorder Buffer (ROB) implementation. Contains an in-order queue of * in-flight instructions. */ class ReorderBuffer { @@ -18,7 +31,10 @@ class ReorderBuffer { * reference to the register alias table. */ ReorderBuffer( unsigned int maxSize, RegisterAliasTable& rat, LoadStoreQueue& lsq, - std::function&)> raiseException); + std::function&)> raiseException, + std::function sendLoopBoundary, + BranchPredictor& predictor, uint16_t loopBufSize, + uint16_t loopDetectionThreshold); /** Add the provided instruction to the ROB. */ void reserve(const std::shared_ptr& insn); @@ -68,6 +84,15 @@ class ReorderBuffer { /** A function to call upon exception generation. */ std::function)> raiseException_; + /** A function to send an instruction at a detected loop boundary. */ + std::function sendLoopBoundary_; + + /** Whether or not a loop has been detected. */ + bool loopDetected_ = false; + + /** A reference to the current branch predictor. */ + BranchPredictor& predictor_; + /** The buffer containing in-flight instructions. */ std::deque> buffer_; @@ -83,6 +108,16 @@ class ReorderBuffer { * current flush. */ uint64_t flushAfter_; + /** Latest retired branch outcome with a counter. */ + std::pair branchCounter_ = {{0, {false, 0}, 0}, 0}; + + /** Loop buffer size. */ + uint16_t loopBufSize_; + + /** Amount of times a branch must be seen without interruption for it to be + * considered a loop. */ + uint16_t loopDetectionThreshold_; + /** The next available sequence ID. */ uint64_t seqId_ = 0; diff --git a/src/include/simeng/version.hh.in b/src/include/simeng/version.hh.in index 1ce0b0de89..5f1e8f410b 100644 --- a/src/include/simeng/version.hh.in +++ b/src/include/simeng/version.hh.in @@ -8,5 +8,6 @@ #define SIMENG_SOURCE_DIR "${PROJECT_SOURCE_DIR}" #define SIMENG_LLVM_VERSION @SIMENG_LLVM_VERSION@ #define SIMENG_ENABLE_TESTS "${SIMENG_ENABLE_TESTS}" +#define SIMENG_BUILD_DIR "${CMAKE_BINARY_DIR}" #endif \ No newline at end of file diff --git a/src/lib/AlwaysNotTakenPredictor.cc b/src/lib/AlwaysNotTakenPredictor.cc index 5dd94bb1c6..784c9f5cc9 100644 --- a/src/lib/AlwaysNotTakenPredictor.cc +++ b/src/lib/AlwaysNotTakenPredictor.cc @@ -2,12 +2,15 @@ namespace simeng { -BranchPrediction AlwaysNotTakenPredictor::predict( - std::shared_ptr& uop) { +BranchPrediction AlwaysNotTakenPredictor::predict(uint64_t address, + BranchType type, + uint64_t knownTarget) { return {false, 0}; } -void AlwaysNotTakenPredictor::update(std::shared_ptr& uop, - bool taken, uint64_t targetAddress) {} +void AlwaysNotTakenPredictor::update(uint64_t address, bool taken, + uint64_t targetAddress, BranchType type) {} + +void AlwaysNotTakenPredictor::flush(uint64_t address) {} } // namespace simeng diff --git a/src/lib/BTBPredictor.cc b/src/lib/BTBPredictor.cc deleted file mode 100644 index 3dffaf1144..0000000000 --- a/src/lib/BTBPredictor.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "simeng/BTBPredictor.hh" - -namespace simeng { - -BTBPredictor::BTBPredictor(uint8_t bits) - : bits(bits), btb(1 << bits), hasValue(1 << bits, false) {} - -BranchPrediction BTBPredictor::predict(std::shared_ptr& uop) { - auto instructionAddress = uop->getInstructionAddress(); - // Simple hash; lowest `bits` bits of address - auto addressHash = hash(instructionAddress); - - return {hasValue[addressHash], btb[addressHash]}; -} - -void BTBPredictor::update(std::shared_ptr& uop, bool taken, - uint64_t targetAddress) { - auto instructionAddress = uop->getInstructionAddress(); - auto addressHash = hash(instructionAddress); - - hasValue[addressHash] = taken; - btb[addressHash] = targetAddress; -} - -uint64_t BTBPredictor::hash(uint64_t instructionAddress) const { - uint64_t mask = (1 << bits) - 1; - return instructionAddress & mask; -} - -} // namespace simeng diff --git a/src/lib/BTB_BWTPredictor.cc b/src/lib/BTB_BWTPredictor.cc deleted file mode 100644 index eb108b9ceb..0000000000 --- a/src/lib/BTB_BWTPredictor.cc +++ /dev/null @@ -1,96 +0,0 @@ -#include "simeng/BTB_BWTPredictor.hh" - -#include - -namespace simeng { - -BTB_BWTPredictor::BTB_BWTPredictor(uint8_t bits, uint8_t associative) - : bits(bits), - width(associative), - mask((1 << bits) - 1), - btb(1 << bits, *(new std::vector>( - associative))), - pht(1 << bits, 1), - touched(std::vector>( - 1 << bits, *(new std::vector(associative)))), - associativeIndex(1 << 11, 0) { - thr = 0; - ghrUnsigned = 0; -} - -BranchPrediction BTB_BWTPredictor::predict(std::shared_ptr& uop) { - auto instructionAddress = uop->getInstructionAddress(); - std::pair& btbIndex = mappings[instructionAddress]; - - BranchPrediction prediction; - // Provide new BTB entry if the branch doesn't have one or it's - // previous allocation has been replaced. - if (touched[btbIndex.first][btbIndex.second] != instructionAddress) { - auto addressHash = hash(instructionAddress); - btbIndex.first = addressHash; - // Increment secondary index for oldest-replacement scheme - btbIndex.second = (++associativeIndex[addressHash]) % width; - mappings[instructionAddress] = btbIndex; - touched[btbIndex.first][btbIndex.second] = instructionAddress; - std::get<2>(btb[btbIndex.first][btbIndex.second]) = -1; - } - - // If the branch is a subroutine return then try and use return address stack - if (uop->isRET() && ras.size() > 0) { - uint64_t target = ras.top(); - ras.pop(); - prediction = {true, target}; - } else { - uint64_t phtIndex = ghrUnsigned ^ (instructionAddress & mask); - std::get<1>(btb[btbIndex.first][btbIndex.second]) = phtIndex; - - uint8_t agreement = pht[phtIndex] / 2; - if (std::get<2>(btb[btbIndex.first][btbIndex.second]) == - -1) { // Static prediction - prediction.taken = 0; - } else if (agreement) { - prediction.taken = std::get<2>(btb[btbIndex.first][btbIndex.second]); - } else { - prediction.taken = !std::get<2>(btb[btbIndex.first][btbIndex.second]); - } - prediction.target = std::get<0>(btb[btbIndex.first][btbIndex.second]); - } - - // If appropiate branch type, add to return address stack. - if (uop->isBL()) { - ras.push(instructionAddress + 4); - } - - return prediction; -} - -void BTB_BWTPredictor::update(std::shared_ptr& uop, bool taken, - uint64_t targetAddress) { - auto instructionAddress = uop->getInstructionAddress(); - std::pair& btbIndex = mappings[instructionAddress]; - - // Update btb entry - if (taken) std::get<0>(btb[btbIndex.first][btbIndex.second]) = targetAddress; - if (std::get<2>(btb[btbIndex.first][btbIndex.second]) == -1) { - std::get<2>(btb[btbIndex.first][btbIndex.second]) = taken; - } - - // Update pattern history table. - uint64_t phtIndex = std::get<1>(btb[btbIndex.first][btbIndex.second]); - if (std::get<2>(btb[btbIndex.first][btbIndex.second]) == taken) { - pht[phtIndex] = pht[phtIndex] == 4 ? 4 : pht[phtIndex] + 1; - } else { - pht[phtIndex] = pht[phtIndex] == 0 ? 0 : pht[phtIndex] - 1; - } - - // Update bitlength history registers. - thr = targetAddress & mask; - ghrUnsigned = ((ghrUnsigned << 1) | taken) & mask; -} - -uint64_t BTB_BWTPredictor::hash(uint64_t instructionAddress) const { - uint64_t combination = thr ^ ghrUnsigned; - return combination ^ (instructionAddress & mask); -} - -} // namespace simeng diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index a7f0860ee2..48713f4d85 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,6 +14,7 @@ set(SIMENG_SOURCES models/outoforder/Core.cc pipeline/A64FXPortAllocator.cc pipeline/BalancedPortAllocator.cc + pipeline/M1PortAllocator.cc pipeline/DecodeUnit.cc pipeline/DispatchIssueUnit.cc pipeline/ExecuteUnit.cc @@ -26,18 +27,18 @@ set(SIMENG_SOURCES pipeline/WritebackUnit.cc AlwaysNotTakenPredictor.cc ArchitecturalRegisterFileSet.cc - BTB_BWTPredictor.cc - BTBPredictor.cc CMakeLists.txt + CoreInstance.cc Elf.cc FixedLatencyMemoryInterface.cc FlatMemoryInterface.cc + GenericPredictor.cc Instruction.cc ModelConfig.cc RegisterFileSet.cc RegisterValue.cc SpecialFileDirGen.cc - ) +) configure_file(${capstone_SOURCE_DIR}/arch/AArch64/AArch64GenInstrInfo.inc AArch64GenInstrInfo.inc COPYONLY) @@ -46,7 +47,7 @@ set_target_properties(libsimeng PROPERTIES OUTPUT_NAME simeng) target_include_directories(libsimeng PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(libsimeng PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(libsimeng capstone-static yaml-cpp) +target_link_libraries(libsimeng capstone yaml-cpp) set_target_properties(libsimeng PROPERTIES VERSION ${SimEng_VERSION}) set_target_properties(libsimeng PROPERTIES SOVERSION ${SimEng_VERSION_MAJOR}) @@ -57,4 +58,4 @@ install(TARGETS libsimeng DESTINATION lib) get_target_property(SIMENG_COMPILE_OPTIONS libsimeng COMPILE_OPTIONS) get_target_property(SIMENG_COMPILE_DEFINITIONS libsimeng COMPILE_DEFINITIONS) get_target_property(SIMENG_VERSION libsimeng VERSION) -configure_file(${PROJECT_SOURCE_DIR}/src/include/simeng/version.hh.in ${PROJECT_SOURCE_DIR}/src/include/simeng/version.hh) \ No newline at end of file +configure_file(${PROJECT_SOURCE_DIR}/src/include/simeng/version.hh.in ${PROJECT_SOURCE_DIR}/src/include/simeng/version.hh) diff --git a/src/lib/CoreInstance.cc b/src/lib/CoreInstance.cc new file mode 100644 index 0000000000..c150185b60 --- /dev/null +++ b/src/lib/CoreInstance.cc @@ -0,0 +1,310 @@ +#include "simeng/CoreInstance.hh" + +namespace simeng { + +CoreInstance::CoreInstance(std::string executablePath, + std::vector executableArgs) { + config_ = YAML::Load(DEFAULT_CONFIG); + generateCoreModel(executablePath, executableArgs); +} + +CoreInstance::CoreInstance(std::string configPath, std::string executablePath, + std::vector executableArgs) { + config_ = simeng::ModelConfig(configPath).getConfigFile(); + generateCoreModel(executablePath, executableArgs); +} + +CoreInstance::~CoreInstance() {} + +void CoreInstance::generateCoreModel(std::string executablePath, + std::vector executableArgs) { + setSimulationMode(); + createProcess(executablePath, executableArgs); + // Check to see if either of the instruction or data memory interfaces should + // be created. Don't create the core if either interface is marked as External + // as they must be set manually prior to the core's creation. + + // Convert Data-Memory's Interface-Type value from a string to + // simeng::MemInterfaceType + std::string dType_string = + config_["L1-Data-Memory"]["Interface-Type"].as(); + simeng::MemInterfaceType dType = simeng::MemInterfaceType::Flat; + if (dType_string == "Fixed") { + dType = simeng::MemInterfaceType::Fixed; + } else if (dType_string == "External") { + dType = simeng::MemInterfaceType::External; + } + // Create data memory if appropriate + if (dType == simeng::MemInterfaceType::External) { + setDataMemory_ = true; + } else { + createL1DataMemory(dType); + } + + // Convert Instruction-Memory's Interface-Type value from a string to + // simeng::MemInterfaceType + std::string iType_string = + config_["L1-Instruction-Memory"]["Interface-Type"].as(); + simeng::MemInterfaceType iType = simeng::MemInterfaceType::Flat; + if (iType_string == "Fixed") { + iType = simeng::MemInterfaceType::Fixed; + } else if (iType_string == "External") { + iType = simeng::MemInterfaceType::External; + } + // Create instruction memory if appropriate + if (iType == simeng::MemInterfaceType::External) { + setInstructionMemory_ = true; + } else { + createL1InstructionMemory(iType); + } + + // Create the core if neither memory interfaces are externally constructed + if (!(setDataMemory_ || setInstructionMemory_)) createCore(); + + return; +} + +void CoreInstance::setSimulationMode() { + // Get the simualtion mode as defined by the set configuration, defaulting to + // emulation + if (config_["Core"]["Simulation-Mode"].as() == + "inorderpipelined") { + mode_ = SimulationMode::InOrderPipelined; + modeString_ = "In-Order Pipelined"; + } else if (config_["Core"]["Simulation-Mode"].as() == + "outoforder") { + mode_ = SimulationMode::OutOfOrder; + modeString_ = "Out-of-Order"; + } + + return; +} + +void CoreInstance::createProcess(std::string executablePath, + std::vector executableArgs) { + if (executablePath.length() > 0) { + // Concatenate the command line arguments into a single vector and create + // the process image + std::vector commandLine = {executablePath}; + commandLine.insert(commandLine.end(), executableArgs.begin(), + executableArgs.end()); + process_ = + std::make_unique(commandLine, config_); + + // Raise error if created process is not valid + if (!process_->isValid()) { + std::cerr << "[SimEng:CoreInstance] Could not read/parse " + << commandLine[0] << std::endl; + exit(1); + } + } else { + // Create a process image from the set of instructions held in hex_ + process_ = std::make_unique( + simeng::span(reinterpret_cast(hex_), sizeof(hex_)), + config_); + + // Raise error if created process is not valid + if (!process_->isValid()) { + std::cerr << "[SimEng:CoreInstance] Could not create process based on " + "supplied instruction span" + << std::endl; + exit(1); + } + } + + // Create the process memory space from the generated process image + createProcessMemory(); + + // Create the OS kernel with the process + kernel_.createProcess(*process_.get()); + + return; +} + +void CoreInstance::createProcessMemory() { + // Get the process image and its size + processMemory_ = process_->getProcessImage(); + processMemorySize_ = process_->getProcessImageSize(); + + return; +} + +void CoreInstance::createL1InstructionMemory( + const simeng::MemInterfaceType type) { + // Create a L1I cache instance based on type supplied + if (type == simeng::MemInterfaceType::Flat) { + instructionMemory_ = std::make_shared( + processMemory_.get(), processMemorySize_); + } else if (type == simeng::MemInterfaceType::Fixed) { + instructionMemory_ = std::make_shared( + processMemory_.get(), processMemorySize_, + config_["LSQ-L1-Interface"]["Access-Latency"].as()); + } else { + std::cerr + << "[SimEng:CoreInstance] Unsupported memory interface type used in " + "createL1InstructionMemory()." + << std::endl; + exit(1); + } + + return; +} + +void CoreInstance::setL1InstructionMemory( + std::shared_ptr memRef) { + assert(setInstructionMemory_ && + "setL1InstructionMemory(...) called but the interface was created by " + "the CoreInstance class."); + // Set the L1I cache instance to use + instructionMemory_ = memRef; + return; +} + +void CoreInstance::createL1DataMemory(const simeng::MemInterfaceType type) { + // Create a L1D cache instance based on type supplied + if (type == simeng::MemInterfaceType::Flat) { + dataMemory_ = std::make_shared( + processMemory_.get(), processMemorySize_); + } else if (type == simeng::MemInterfaceType::Fixed) { + dataMemory_ = std::make_shared( + processMemory_.get(), processMemorySize_, + config_["LSQ-L1-Interface"]["Access-Latency"].as()); + } else { + std::cerr << "[SimEng:CoreInstance] Unsupported memory interface type used " + "in createL1DataMemory()." + << std::endl; + exit(1); + } + + return; +} + +void CoreInstance::setL1DataMemory( + std::shared_ptr memRef) { + assert(setDataMemory_ && + "setL1DataMemory(...) called but the interface was created by the " + "CoreInstance class."); + // Set the L1D cache instance to use + dataMemory_ = memRef; + return; +} + +void CoreInstance::createCore() { + // If memory interfaces must be manually set, ensure they have been + if (setDataMemory_ && (dataMemory_ == nullptr)) { + std::cerr << "[SimEng:CoreInstance] Data memory not set. External Data " + "memory must be manually " + "set using the setL1DataMemory(...) function." + << std::endl; + exit(1); + } else if (setInstructionMemory_ && (instructionMemory_ == nullptr)) { + std::cerr << "[SimEng:CoreInstance] Instruction memory not set. External " + "instruction memory " + "interface must be manually set using the " + "setL1InstructionMemory(...) function." + << std::endl; + exit(1); + } + + // Construct architecture object + arch_ = + std::make_unique(kernel_, config_); + + // Construct branch predictor object + predictor_ = std::make_unique(config_); + + // Extract port arrangement from config file + auto config_ports = config_["Ports"]; + std::vector> portArrangement(config_ports.size()); + for (size_t i = 0; i < config_ports.size(); i++) { + auto config_groups = config_ports[i]["Instruction-Group-Support"]; + // Read groups in associated port + for (size_t j = 0; j < config_groups.size(); j++) { + portArrangement[i].push_back(config_groups[j].as()); + } + } + portAllocator_ = std::make_unique( + portArrangement); + + // Construct the core object based on the defined simulation mode + uint64_t entryPoint = process_->getEntryPoint(); + if (mode_ == SimulationMode::Emulation) { + core_ = std::make_shared( + *instructionMemory_, *dataMemory_, entryPoint, processMemorySize_, + *arch_); + } else if (mode_ == SimulationMode::InOrderPipelined) { + core_ = std::make_shared( + *instructionMemory_, *dataMemory_, processMemorySize_, entryPoint, + *arch_, *predictor_); + } else if (mode_ == SimulationMode::OutOfOrder) { + core_ = std::make_shared( + *instructionMemory_, *dataMemory_, processMemorySize_, entryPoint, + *arch_, *predictor_, *portAllocator_, config_); + } + + createSpecialFileDirectory(); + + return; +} + +void CoreInstance::createSpecialFileDirectory() { + // Create the Special Files directory if indicated to do so in Config + if (config_["CPU-Info"]["Generate-Special-Dir"].as() == true) { + simeng::SpecialFileDirGen SFdir = simeng::SpecialFileDirGen(config_); + // Remove any current special files dir + SFdir.RemoveExistingSFDir(); + // Create new special files dir + SFdir.GenerateSFDir(); + } + + return; +} + +const SimulationMode CoreInstance::getSimulationMode() const { return mode_; } + +const std::string CoreInstance::getSimulationModeString() const { + return modeString_; +} + +std::shared_ptr CoreInstance::getCore() const { + if (core_ == nullptr) { + std::cerr + << "[SimEng:CoreInstance] Core object not constructed. If either data " + "or instruction memory " + "interfaces are marked as an `External` type, they must be set " + "manually and then core's creation must be called manually." + << std::endl; + exit(1); + } + return core_; +} + +std::shared_ptr CoreInstance::getDataMemory() const { + if (setDataMemory_ && (dataMemory_ == nullptr)) { + std::cerr << "[SimEng:CoreInstance] `External` data memory object not set." + << std::endl; + exit(1); + } + return dataMemory_; +} + +std::shared_ptr CoreInstance::getInstructionMemory() + const { + if (setInstructionMemory_ && (instructionMemory_ == nullptr)) { + std::cerr + << "`[SimEng:CoreInstance] External` instruction memory object not set." + << std::endl; + exit(1); + } + return instructionMemory_; +} + +std::shared_ptr CoreInstance::getProcessImage() const { + return processMemory_; +} + +const uint64_t CoreInstance::getProcessImageSize() const { + return processMemorySize_; +} + +} // namespace simeng diff --git a/src/lib/Elf.cc b/src/lib/Elf.cc index b23b615959..6654cc86a8 100644 --- a/src/lib/Elf.cc +++ b/src/lib/Elf.cc @@ -5,14 +5,33 @@ namespace simeng { -Elf::Elf(std::string path) { +/** + * Extract information from an ELF binary. + * 32-bit and 64-bit architectures have variance in the structs + * used to define the structure of an ELF binary. All information + * presented as documentation has been referenced from: + * https://man7.org/linux/man-pages/man5/elf.5.html + */ + +Elf::Elf(std::string path, char** imagePointer) { std::ifstream file(path, std::ios::binary); if (!file.is_open()) { return; } - // Check file's magic number + /** + * In the Linux source tree the ELF header + * is defined by the elf64_hdr struct for 64-bit systems. + * `elf64_hdr->e_ident` is an array of bytes which specifies + * how to interpret the ELF file, independent of the + * processor or the file's remaining contents. All ELF + * files start with the ELF header. + */ + + /** + * First four bytes of the ELF header represent the ELF Magic Number. + */ char elfMagic[4] = {0x7f, 'E', 'L', 'F'}; char fileMagic[4]; file.read(fileMagic, 4); @@ -20,7 +39,12 @@ Elf::Elf(std::string path) { return; } - // Check whether this is a 32- or 64-bit executable + /** + * The fifth byte of the ELF Header identifies the architecture + * of the ELF binary i.e 32-bit or 64-bit. + */ + + // Check whether this is a 32 or 64-bit executable char bitFormat; file.read(&bitFormat, sizeof(bitFormat)); if (bitFormat != ElfBitFormat::Format64) { @@ -29,28 +53,84 @@ Elf::Elf(std::string path) { isValid_ = true; + /** + * Starting from the 24th byte of the ELF header a 64-bit value + * represents the virtual address to which the system first transfers + * control, thus starting the process. + * In `elf64_hdr` this value maps to the member `Elf64_Addr e_entry`. + */ + + // Seek to the entry point of the file. + // The information in between is discarded file.seekg(0x18); - // Entry point file.read(reinterpret_cast(&entryPoint_), sizeof(entryPoint_)); - // Header table offset + /** + * Starting from the 32nd byte of the ELF Header a 64-bit value + * represents the offset of the ELF Program header or + * Program header table in the ELF file. + * In `elf64_hdr` this value maps to the member `Elf64_Addr e_phoff`. + */ + + // Seek to the byte representing the start of the header offset table. uint64_t headerOffset; file.read(reinterpret_cast(&headerOffset), sizeof(headerOffset)); - // Header table info + /** + * Starting 54th byte of the ELF Header a 16-bit value indicates + * the size of each entry in the ELF Program header. In the `elf64_hdr` + * struct this value maps to the member `Elf64_Half e_phentsize`. All + * header entries have the same size. + * Starting from the 56th byte a 16-bit value represents the number + * of header entries in the ELF Program header. In the `elf64_hdr` + * struct this value maps to `Elf64_Half e_phnum`. + */ + + // Seek to the byte representing header entry size. file.seekg(0x36); uint16_t headerEntrySize; file.read(reinterpret_cast(&headerEntrySize), sizeof(headerEntrySize)); uint16_t headerEntries; file.read(reinterpret_cast(&headerEntries), sizeof(headerEntries)); + // Resize the header to equal the number of header entries. headers_.resize(headerEntries); processImageSize_ = 0; - // Extract headers + + // Loop over all headers and extract them. for (size_t i = 0; i < headerEntries; i++) { + // Since all headers entries have the same size. + // We can extract the nth header using the header offset + // and header entry size. file.seekg(headerOffset + (i * headerEntrySize)); auto& header = headers_[i]; + /** + * Like the ELF Header, the ELF Program header is also defined + * using a struct: + * typedef struct { + * uint32_t p_type; + * uint32_t p_flags; + * Elf64_Off p_offset; + * Elf64_Addr p_vaddr; + * Elf64_Addr p_paddr; + * uint64_t p_filesz; + * uint64_t p_memsz; + * uint64_t p_align; + * } Elf64_Phdr; + * + * The ELF Program header table is an array of structures, + * each describing a segment or other information the system + * needs to prepare the program for execution. A segment + * contains one or more sections (ELF Program Section). + * + * The `p_vaddr` field holds the virtual address at which the first + * byte of the segment resides in memory and the `p_memsz` field + * holds the number of bytes in the memory image of the segment. + * It may be zero. The `p_offset` member holds the offset from the + * beginning of the file at which the first byte of the segment resides. + */ + // Each address-related field is 8 bytes in a 64-bit ELF file const int fieldBytes = 8; file.read(reinterpret_cast(&(header.type)), sizeof(header.type)); @@ -61,12 +141,25 @@ Elf::Elf(std::string path) { file.read(reinterpret_cast(&(header.fileSize)), fieldBytes); file.read(reinterpret_cast(&(header.memorySize)), fieldBytes); + // To construct the process we look for the largest virtual address and + // add it to the memory size of the header. This way we obtain a very + // large array which can hold data at large virtual address. + // However, this way we end up creating a sparse array, in which most + // of the entries are unused. Also SimEng internally treats these + // virtual address as physical addresses to index into this large array. if (header.virtualAddress + header.memorySize > processImageSize_) { processImageSize_ = header.virtualAddress + header.memorySize; } } - processImage_ = new char[processImageSize_]; + *imagePointer = (char*)malloc(processImageSize_ * sizeof(char)); + /** + * The ELF Program header has a member called `p_type`, which represents + * the kind of data or memory segments described by the program header. + * The value PT_LOAD=1 represents a loadable segment. In other words, + * it contains initialized data that contributes to the program's + * memory image. + */ // Process headers; only observe LOAD sections for this basic implementation for (const auto& header : headers_) { @@ -74,24 +167,20 @@ Elf::Elf(std::string path) { file.seekg(header.offset); // Read `fileSize` bytes from `file` into the appropriate place in process // memory - file.read(processImage_ + header.virtualAddress, header.fileSize); + file.read(*imagePointer + header.virtualAddress, header.fileSize); } } file.close(); + return; } -Elf::~Elf() { - if (isValid_) { - delete[] processImage_; - } -} +Elf::~Elf() {} -const span Elf::getProcessImage() const { - return {processImage_, processImageSize_}; -} +uint64_t Elf::getProcessImageSize() const { return processImageSize_; } uint64_t Elf::getEntryPoint() const { return entryPoint_; } + bool Elf::isValid() const { return isValid_; } } // namespace simeng diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc new file mode 100644 index 0000000000..4030a85133 --- /dev/null +++ b/src/lib/GenericPredictor.cc @@ -0,0 +1,113 @@ +#include "simeng/GenericPredictor.hh" + +#include + +namespace simeng { + +GenericPredictor::GenericPredictor(YAML::Node config) + : btbBits_(config["Branch-Predictor"]["BTB-Tag-Bits"].as()), + btb_(1 << btbBits_, + {config["Branch-Predictor"]["Fallback-Static-Predictor"] + .as(), + 0}), + satCntBits_( + config["Branch-Predictor"]["Saturating-Count-Bits"].as()), + globalHistoryLength_( + config["Branch-Predictor"]["Global-History-Length"].as()), + rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { + // Alter globalHistoryLength_ value to better suit required format in update() + globalHistoryLength_ = (1 << globalHistoryLength_) - 1; +} + +GenericPredictor::~GenericPredictor() { + btb_.clear(); + ras_.clear(); + rasHistory_.clear(); +} + +BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, + uint64_t knownTarget) { + // Get index via an XOR hash between the global history and the lower btbBits_ + // bits of the instruction address + uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + btbHistory_[address] = hashedIndex; + + // Get prediction from BTB + bool direction = + btb_[hashedIndex].first < (1 << (satCntBits_ - 1)) ? false : true; + uint64_t target = + (knownTarget != 0) ? address + knownTarget : btb_[hashedIndex].second; + BranchPrediction prediction = {direction, target}; + + // Ammend prediction based on branch type + if (type == BranchType::Unconditional) { + prediction.taken = true; + } else if (type == BranchType::Return) { + prediction.taken = true; + // Return branches can use the RAS if an entry is available + if (ras_.size() > 0) { + prediction.target = ras_.back(); + // Record top of RAS used for target prediction + rasHistory_[address] = ras_.back(); + ras_.pop_back(); + } + } else if (type == BranchType::SubroutineCall) { + prediction.taken = true; + // Subroutine call branches must push their assoicated return address to RAS + if (ras_.size() >= rasSize_) { + ras_.pop_front(); + } + ras_.push_back(address + 4); + // Record that this address is a branch-and-link instruction + rasHistory_[address] = 0; + } else if (type == BranchType::Conditional) { + if (!prediction.taken) prediction.target = address + 4; + } + return prediction; +} + +void GenericPredictor::update(uint64_t address, bool taken, + uint64_t targetAddress, BranchType type) { + // Get previous index calculated for the instruction address supplied + uint64_t hashedIndex = btbHistory_[address]; + + // Calculate 2-bit saturating counter value + uint8_t satCntVal = btb_[hashedIndex].first; + // Only alter value if it would transition to a valid state + if (!((satCntVal == (1 << satCntBits_) - 1) && taken) && + !(satCntVal == 0 && !taken)) { + satCntVal += taken ? 1 : -1; + } + + // Update BTB entry + btb_[hashedIndex] = {satCntVal, targetAddress}; + + // Update global history value with new direction + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; + return; +} + +void GenericPredictor::flush(uint64_t address) { + // If address interacted with RAS, rewind entry + auto it = rasHistory_.find(address); + if (it != rasHistory_.end()) { + uint64_t target = it->second; + if (target != 0) { + // If history entry belongs to a return instruction, push target back onto + // stack + if (ras_.size() >= rasSize_) { + ras_.pop_front(); + } + ras_.push_back(target); + } else { + // If history entry belongs to a branch-and-link instruction, pop target + // off of stack + if (ras_.size()) { + ras_.pop_back(); + } + } + rasHistory_.erase(it); + } +} + +} // namespace simeng diff --git a/src/lib/Instruction.cc b/src/lib/Instruction.cc index 7aada739f9..ac923c11b2 100644 --- a/src/lib/Instruction.cc +++ b/src/lib/Instruction.cc @@ -15,6 +15,10 @@ void Instruction::setBranchPrediction(BranchPrediction prediction) { prediction_ = prediction; } +BranchPrediction Instruction::getBranchPrediction() const { + return prediction_; +} + uint64_t Instruction::getBranchAddress() const { return branchAddress_; } bool Instruction::wasBranchTaken() const { return branchTaken_; } @@ -25,7 +29,7 @@ bool Instruction::wasBranchMispredicted() const { // Flag as mispredicted if taken state was wrongly predicted, or taken and // predicted target is wrong return (branchTaken_ != prediction_.taken || - (branchTaken_ && prediction_.target != branchAddress_)); + (prediction_.target != branchAddress_)); } void Instruction::setSequenceId(uint64_t seqId) { sequenceId_ = seqId; }; diff --git a/src/lib/ModelConfig.cc b/src/lib/ModelConfig.cc index 10c7c63a4d..13e877252a 100644 --- a/src/lib/ModelConfig.cc +++ b/src/lib/ModelConfig.cc @@ -1,12 +1,14 @@ #include "simeng/ModelConfig.hh" +#include + namespace simeng { ModelConfig::ModelConfig(std::string path) { // Ensure the file exists std::ifstream file(path); if (!file.is_open()) { - std::cerr << "Could not read " << path << std::endl; + std::cerr << "[SimEng:ModelConfig] Could not read " << path << std::endl; exit(1); } file.close(); @@ -31,7 +33,8 @@ void ModelConfig::inherit() { if (!configFile_["Inherit-From"]) { return; } else { - std::cerr << "Config inheritance not yet supported" << std::endl; + std::cerr << "[SimEng:ModelConfig] Config inheritance not yet supported" + << std::endl; exit(1); // TODO: Merge files } @@ -44,8 +47,8 @@ void ModelConfig::validate() { std::string root = ""; // Core root = "Core"; - subFields = {"Simulation-Mode", "Clock-Frequency", "Timer-Frequency", - "Fetch-Block-Size", "Micro-Operations", "Vector-Length"}; + subFields = {"Simulation-Mode", "Clock-Frequency", "Timer-Frequency", + "Micro-Operations", "Vector-Length"}; nodeChecker(configFile_[root][subFields[0]], subFields[0], {"emulation", "inorderpipelined", "outoforder"}, ExpectedValue::String); @@ -54,10 +57,22 @@ void ModelConfig::validate() { nodeChecker(configFile_[root][subFields[2]], subFields[2], std::make_pair(1, UINT32_MAX), ExpectedValue::UInteger, 100); - if (nodeChecker(configFile_[root][subFields[3]], subFields[3], + nodeChecker(configFile_[root][subFields[3]], subFields[3], + std::make_pair(false, true), ExpectedValue::Bool, false); + nodeChecker(configFile_[root][subFields[4]], subFields[4], + {128, 256, 384, 512, 640, 768, 896, 1024, 1152, 1280, + 1408, 1536, 1664, 1792, 1920, 2048}, + ExpectedValue::UInteger, 512); + subFields.clear(); + + // Fetch + root = "Fetch"; + subFields = {"Fetch-Block-Size", "Loop-Buffer-Size", + "Loop-Detection-Threshold"}; + if (nodeChecker(configFile_[root][subFields[0]], subFields[0], std::make_pair(4, UINT16_MAX), ExpectedValue::UInteger)) { - uint16_t block_size = configFile_[root][subFields[3]].as(); + uint16_t block_size = configFile_[root][subFields[0]].as(); // Ensure fetch block size is a power of 2 if ((block_size & (block_size - 1)) == 0) { uint8_t alignment_bits = log2(block_size); @@ -67,12 +82,10 @@ void ModelConfig::validate() { invalid_ << "\t- Fetch-Block-Size must be a power of 2\n"; } } - nodeChecker(configFile_[root][subFields[4]], subFields[4], - std::make_pair(false, true), ExpectedValue::Bool, false); - nodeChecker(configFile_[root][subFields[5]], subFields[5], - {128, 256, 384, 512, 640, 768, 896, 1024, 1152, 1280, - 1408, 1536, 1664, 1792, 1920, 2048}, - ExpectedValue::UInteger, 512); + nodeChecker(configFile_[root][subFields[1]], subFields[1], + std::make_pair(0, UINT16_MAX), ExpectedValue::UInteger); + nodeChecker(configFile_[root][subFields[2]], subFields[2], + std::make_pair(0, UINT16_MAX), ExpectedValue::UInteger); subFields.clear(); // Process-Image @@ -90,13 +103,72 @@ void ModelConfig::validate() { // Branch-Predictor root = "Branch-Predictor"; - subFields = {"BTB-bitlength"}; - nodeChecker(configFile_[root][subFields[0]], subFields[0], - std::make_pair(1, UINT8_MAX), ExpectedValue::UInteger); + subFields = {"BTB-Tag-Bits", "Saturating-Count-Bits", "Global-History-Length", + "RAS-entries", "Fallback-Static-Predictor"}; + nodeChecker(configFile_[root][subFields[0]], subFields[0], + std::make_pair(1, UINT64_MAX), ExpectedValue::UInteger); + nodeChecker(configFile_[root][subFields[2]], subFields[2], + std::make_pair(0, 64), ExpectedValue::UInteger); + nodeChecker(configFile_[root][subFields[3]], subFields[3], + std::make_pair(1, UINT64_MAX), ExpectedValue::UInteger); + if (nodeChecker( + configFile_[root][subFields[4]], subFields[4], + std::vector{"Always-Taken", "Always-Not-Taken"}, + ExpectedValue::String)) { + // If the Saturating-Count-Bits option is valid, set fallback static + // prediction to weakest value of the specific direction (i.e weakly taken + // or weakly not-taken) + if (nodeChecker(configFile_[root][subFields[1]], subFields[1], + std::make_pair(1, UINT64_MAX), + ExpectedValue::UInteger)) { + // Calculate saturation counter boundary between weakly taken and + // not-taken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly taken state + // value + uint16_t weaklyTaken = + std::pow(2, (configFile_[root][subFields[1]].as() - 1)); + // Swap Fallback-Static-Predictor scheme out for equivalent saturating + // counter value + configFile_[root][subFields[4]] = + (configFile_[root][subFields[4]].as() == "Always-Taken") + ? weaklyTaken + : (weaklyTaken - 1); + } + } subFields.clear(); - // L1-Cache - root = "L1-Cache"; + // Data Memory + root = "L1-Data-Memory"; + subFields = {"Interface-Type"}; + nodeChecker( + configFile_[root][subFields[0]], root + " " + subFields[0], + std::vector{"Flat", "Fixed", "External"}, + ExpectedValue::String); + // Currently, fixed instruction memory interfaces are unsupported for + // emulation and inorder simulation modes + if (configFile_[root][subFields[0]].as() != "Flat") { + std::string mode = configFile_["Core"]["Simulation-Mode"].as(); + if (mode == "emulation" || mode == "inorderpipelined") { + invalid_ << "\t- Non-Flat data memory interface types are " + "currently unsupported for 'emulation' and " + "'inorderpipelined' simulation modes\n"; + } + } + + // Instruction Memory + root = "L1-Instruction-Memory"; + subFields = {"Interface-Type"}; + nodeChecker( + configFile_[root][subFields[0]], root + " " + subFields[0], + std::vector{"Flat", "Fixed", "External"}, + ExpectedValue::String); + // Currently, fixed instruction memory interfaces are unsupported + if (configFile_[root][subFields[0]].as() != "Flat") { + invalid_ << "\t- Non-Flat instruction memory interface types are currently " + "unsupported\n"; + } + + // LSQ-L1-Interface + root = "LSQ-L1-Interface"; subFields = {"Access-Latency", "Exclusive", "Load-Bandwidth", @@ -110,20 +182,20 @@ void ModelConfig::validate() { nodeChecker(configFile_[root][subFields[1]], subFields[1], std::vector{true, false}, ExpectedValue::Bool, false); nodeChecker(configFile_[root][subFields[2]], subFields[2], - std::make_pair(1, UINT8_MAX), ExpectedValue::UInteger, - UINT8_MAX); + std::make_pair(1, UINT16_MAX), ExpectedValue::UInteger, + UINT16_MAX); nodeChecker(configFile_[root][subFields[3]], subFields[3], - std::make_pair(1, UINT8_MAX), ExpectedValue::UInteger, - UINT8_MAX); + std::make_pair(1, UINT16_MAX), ExpectedValue::UInteger, + UINT16_MAX); nodeChecker(configFile_[root][subFields[4]], subFields[4], - std::make_pair(1, UINT8_MAX), ExpectedValue::UInteger, - UINT8_MAX); + std::make_pair(1, UINT16_MAX), ExpectedValue::UInteger, + UINT16_MAX); nodeChecker(configFile_[root][subFields[5]], subFields[5], - std::make_pair(1, UINT8_MAX), ExpectedValue::UInteger, - UINT8_MAX); + std::make_pair(1, UINT16_MAX), ExpectedValue::UInteger, + UINT16_MAX); nodeChecker(configFile_[root][subFields[6]], subFields[6], - std::make_pair(1, UINT8_MAX), ExpectedValue::UInteger, - UINT8_MAX); + std::make_pair(1, UINT16_MAX), ExpectedValue::UInteger, + UINT16_MAX); subFields.clear(); // Ports @@ -140,7 +212,7 @@ void ModelConfig::validate() { char port_msg[10]; sprintf(port_msg, "Port %zu ", i); std::string port_num = std::string(port_msg); - // Check for existance of Portname field and record name + // Check for existence of Portname field and record name if (nodeChecker(port_node["Portname"], port_num + "Portname", std::vector{}, ExpectedValue::String)) { @@ -155,7 +227,7 @@ void ModelConfig::validate() { << "\" already used\n"; } } - // Check for existance of Instruction-Support field + // Check for existence of Instruction-Support field if (!(port_node["Instruction-Support"].IsDefined()) || port_node["Instruction-Support"].IsNull()) { missing_ << "\t- " << port_num << "Instruction-Support\n"; @@ -208,6 +280,9 @@ void ModelConfig::validate() { nodeChecker(rs["Size"], rs_num + "Size", std::make_pair(1, UINT16_MAX), ExpectedValue::UInteger); + nodeChecker(rs["Dispatch-Rate"], rs_num + "Dispatch-Rate", + std::make_pair(1, UINT16_MAX), + ExpectedValue::UInteger); // Check for existance of Ports field if (!(rs["Ports"].IsDefined()) || rs["Ports"].IsNull()) { missing_ << "\t- " << rs_num << "Ports\n"; @@ -222,7 +297,7 @@ void ModelConfig::validate() { if (nodeChecker(port_node, rs_num + port_num + "Portname", portNames, ExpectedValue::String)) { // Change port name to port index - for (uint8_t k = 0; k < portNames.size(); k++) { + for (size_t k = 0; k < portNames.size(); k++) { if (port_node.as() == portNames[k]) { configFile_["Reservation-Stations"][i]["Ports"][j] = unsigned(k); portLinked[portNames[k]] = true; @@ -273,7 +348,7 @@ void ModelConfig::validate() { // Pipeline-Widths root = "Pipeline-Widths"; - subFields = {"Commit", "Dispatch-Rate", "FrontEnd", "LSQ-Completion"}; + subFields = {"Commit", "FrontEnd", "LSQ-Completion"}; nodeChecker(configFile_[root][subFields[0]], subFields[0], std::make_pair(1, UINT_MAX), ExpectedValue::UInteger); @@ -283,9 +358,6 @@ void ModelConfig::validate() { nodeChecker(configFile_[root][subFields[2]], subFields[2], std::make_pair(1, UINT_MAX), ExpectedValue::UInteger); - nodeChecker(configFile_[root][subFields[3]], subFields[3], - std::make_pair(1, UINT_MAX), - ExpectedValue::UInteger); subFields.clear(); // Execution-Units @@ -406,8 +478,8 @@ void ModelConfig::validate() { "CPU-Part", "CPU-Revision", "Package-Count"}; - nodeChecker(configFile_[root][subFields[0]], subFields[0], - {"T", "F", ""}, ExpectedValue::String, "F"); + nodeChecker(configFile_[root][subFields[0]], subFields[0], + std::vector{false, true}, ExpectedValue::Bool, false); nodeChecker(configFile_[root][subFields[1]], subFields[1], std::make_pair(1, UINT_MAX), ExpectedValue::UInteger, 1); @@ -457,15 +529,16 @@ void ModelConfig::validate() { std::string invalidStr = invalid_.str(); // Print all missing fields if (missingStr.length()) { - std::cerr << "The following fields are missing from the provided " + std::cerr << "[SimEng:ModelConfig] The following fields are missing from " + "the provided " "configuration file:\n" << missingStr << std::endl; } // Print all invalid values if (invalidStr.length()) { - std::cerr - << "The following values are invalid for their associated field:\n" - << invalidStr << std::endl; + std::cerr << "[SimEng:ModelConfig] The following values are invalid for " + "their associated field:\n" + << invalidStr << std::endl; } if (missingStr.length() || invalidStr.length()) exit(1); return; @@ -557,7 +630,7 @@ template int ModelConfig::nodeChecker(const YAML::Node& node, const std::string& field, const std::vector& value_set, uint8_t expected) { - // Check for the existance of the given node + // Check for the existence of the given node if (!(node.IsDefined()) || node.IsNull()) { missing_ << "\t- " << field << "\n"; return 0; @@ -570,7 +643,7 @@ template int ModelConfig::nodeChecker(YAML::Node node, const std::string& field, const std::vector& value_set, uint8_t expected, T default_value) { - // Check for the existance of the given node + // Check for the existence of the given node if (!(node.IsDefined()) || node.IsNull()) { node = default_value; return 1; @@ -582,7 +655,7 @@ int ModelConfig::nodeChecker(YAML::Node node, const std::string& field, template int ModelConfig::nodeChecker(const YAML::Node& node, const std::string& field, const std::pair& bounds, uint8_t expected) { - // Check for the existance of the given node + // Check for the existence of the given node if (!(node.IsDefined()) || node.IsNull()) { missing_ << "\t- " << field << "\n"; return 0; @@ -595,7 +668,7 @@ template int ModelConfig::nodeChecker(YAML::Node node, const std::string& field, const std::pair& bounds, uint8_t expected, const T& default_value) { - // Check for the existance of the given node + // Check for the existence of the given node if (!(node.IsDefined()) || node.IsNull()) { node = default_value; return 1; diff --git a/src/lib/arch/aarch64/Architecture.cc b/src/lib/arch/aarch64/Architecture.cc index 1bfced8940..60fd17de68 100644 --- a/src/lib/arch/aarch64/Architecture.cc +++ b/src/lib/arch/aarch64/Architecture.cc @@ -13,9 +13,12 @@ std::forward_list Architecture::metadataCache; Architecture::Architecture(kernel::Linux& kernel, YAML::Node config) : linux_(kernel), microDecoder_(std::make_unique(config)), - VL_(config["Core"]["Vector-Length"].as()) { + VL_(config["Core"]["Vector-Length"].as()), + vctModulo_((config["Core"]["Clock-Frequency"].as() * 1e9) / + (config["Core"]["Timer-Frequency"].as() * 1e6)) { if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &capstoneHandle) != CS_ERR_OK) { - std::cerr << "Could not create capstone handle" << std::endl; + std::cerr << "[SimEng:Architecture] Could not create capstone handle" + << std::endl; exit(1); } @@ -28,6 +31,15 @@ Architecture::Architecture(kernel::Linux& kernel, YAML::Node config) systemRegisterMap_[ARM64_SYSREG_TPIDR_EL0] = systemRegisterMap_.size(); systemRegisterMap_[ARM64_SYSREG_MIDR_EL1] = systemRegisterMap_.size(); systemRegisterMap_[ARM64_SYSREG_CNTVCT_EL0] = systemRegisterMap_.size(); + systemRegisterMap_[ARM64_SYSREG_PMCCNTR_EL0] = systemRegisterMap_.size(); + + // Get Virtual Counter Timer and Processor Cycle Counter system registers. + VCTreg_ = { + RegisterType::SYSTEM, + static_cast(getSystemRegisterTag(ARM64_SYSREG_CNTVCT_EL0))}; + PCCreg_ = { + RegisterType::SYSTEM, + static_cast(getSystemRegisterTag(ARM64_SYSREG_PMCCNTR_EL0))}; // Instantiate an ExecutionInfo entry for each group in the InstructionGroup // namespace. @@ -130,9 +142,8 @@ Architecture::~Architecture() { uint8_t Architecture::predecode(const void* ptr, uint8_t bytesAvailable, uint64_t instructionAddress, - BranchPrediction prediction, MacroOp& output) const { - // Check that instruction address is 4-byte aligned as required by Armv8 + // Check that instruction address is 4-byte aligned as required by Armv9.2-a if (instructionAddress & 0x3) { // Consume 1-byte and raise a misaligned PC exception auto metadata = InstructionMetadata((uint8_t*)ptr, 1); @@ -142,7 +153,6 @@ uint8_t Architecture::predecode(const void* ptr, uint8_t bytesAvailable, uop = std::make_shared(*this, metadataCache.front(), InstructionException::MisalignedPC); uop->setInstructionAddress(instructionAddress); - uop->setBranchPrediction(prediction); // Return non-zero value to avoid fatal error return 1; } @@ -192,7 +202,6 @@ uint8_t Architecture::predecode(const void* ptr, uint8_t bytesAvailable, // Set instruction address and branch prediction for each micro-op generated for (int i = 0; i < num_ops; i++) { output[i]->setInstructionAddress(instructionAddress); - output[i]->setBranchPrediction(prediction); } return 4; @@ -232,14 +241,18 @@ std::vector Architecture::getRegisterFileStructures() }; } -uint16_t Architecture::getSystemRegisterTag(uint16_t reg) const { +int32_t Architecture::getSystemRegisterTag(uint16_t reg) const { // Check below is done for speculative instructions that may be passed into // the function but will not be executed. If such invalid speculative // instructions get through they can cause an out-of-range error. - if (!systemRegisterMap_.count(reg)) return 0; + if (!systemRegisterMap_.count(reg)) return -1; return systemRegisterMap_.at(reg); } +uint16_t Architecture::getNumSystemRegisters() const { + return static_cast(systemRegisterMap_.size()); +} + ProcessStateChange Architecture::getInitialState() const { ProcessStateChange changes; // Set ProcessStateChange type @@ -254,7 +267,8 @@ ProcessStateChange Architecture::getInitialState() const { // Temporary: state that DCZ can support clearing 64 bytes at a time, // but is disabled due to bit 4 being set changes.modifiedRegisters.push_back( - {RegisterType::SYSTEM, getSystemRegisterTag(ARM64_SYSREG_DCZID_EL0)}); + {RegisterType::SYSTEM, + static_cast(getSystemRegisterTag(ARM64_SYSREG_DCZID_EL0))}); changes.modifiedRegisterValues.push_back(static_cast(0b10100)); return changes; @@ -264,8 +278,15 @@ uint8_t Architecture::getMaxInstructionSize() const { return 4; } uint64_t Architecture::getVectorLength() const { return VL_; } -simeng::Register Architecture::getVCTreg() const { - return {RegisterType::SYSTEM, getSystemRegisterTag(ARM64_SYSREG_CNTVCT_EL0)}; +void Architecture::updateSystemTimerRegisters(RegisterFileSet* regFile, + const uint64_t iterations) const { + // Update the Processor Cycle Counter to total cycles completed. + regFile->set(PCCreg_, iterations); + + // Update Virtual Counter Timer at correct frequency. + if (iterations % (uint64_t)vctModulo_ == 0) { + regFile->set(VCTreg_, regFile->get(VCTreg_).get() + 1); + } } } // namespace aarch64 diff --git a/src/lib/arch/aarch64/ExceptionHandler.cc b/src/lib/arch/aarch64/ExceptionHandler.cc index d9e2197d6a..ee45d6928b 100644 --- a/src/lib/arch/aarch64/ExceptionHandler.cc +++ b/src/lib/arch/aarch64/ExceptionHandler.cc @@ -4,6 +4,7 @@ #include #include +#include #include "InstructionMetadata.hh" #include "simeng/ArchitecturalRegisterFileSet.hh" @@ -363,7 +364,8 @@ bool ExceptionHandler::init() { } case 94: { // exit_group auto exitCode = registerFileSet.get(R0).get(); - std::cout << "Received exit_group syscall: terminating with exit code " + std::cout << "\n[SimEng:ExceptionHandler] Received exit_group syscall: " + "terminating with exit code " << exitCode << std::endl; return fatal(); } @@ -379,8 +381,9 @@ bool ExceptionHandler::init() { int op = registerFileSet.get(R1).get(); if (op != 129) { printException(instruction_); - std::cout << "Unsupported arguments for syscall: " << syscallId - << std::endl; + std::cout << "\n[SimEng:ExceptionHandler] Unsupported arguments for " + "syscall: " + << syscallId << std::endl; return fatal(); } stateChange = {ChangeType::REPLACEMENT, {R0}, {1ull}}; @@ -442,6 +445,12 @@ bool ExceptionHandler::init() { } break; } + case 131: { // tgkill + // TODO: Functionality temporarily omitted since simeng only has a + // single thread at the moment + stateChange = {ChangeType::REPLACEMENT, {R0}, {0ull}}; + break; + } case 134: { // rt_sigaction // TODO: Implement syscall logic. Ignored for now as it's assumed the // current use of this syscall is to setup error handlers. Simualted @@ -538,6 +547,14 @@ bool ExceptionHandler::init() { ChangeType::REPLACEMENT, {R0}, {static_cast(result)}}; break; } + case 210: { // shutdown + // TODO: Functionality omitted - returns -38 (errno 38, function not + // implemented) is to mimic the behaviour on isambard and avoid an + // unrecognised syscall error + stateChange = { + ChangeType::REPLACEMENT, {R0}, {static_cast(-38)}}; + break; + } case 215: { // munmap uint64_t addr = registerFileSet.get(R0).get(); size_t length = registerFileSet.get(R1).get(); @@ -569,8 +586,9 @@ bool ExceptionHandler::init() { break; } else { printException(instruction_); - std::cout << "Unsupported arguments for syscall: " << syscallId - << std::endl; + std::cout << "\n[SimEng:ExceptionHandler] Unsupported arguments for " + "syscall: " + << syscallId << std::endl; return fatal(); } } @@ -586,9 +604,38 @@ bool ExceptionHandler::init() { stateChange = {ChangeType::REPLACEMENT, {R0}, {0ull}}; break; } + case 278: { // getrandom + // TODO: support flags argument + + // seed random numbers + srand(clock()); + + // Write random bytes to buf + uint64_t bufPtr = registerFileSet.get(R0).get(); + size_t buflen = registerFileSet.get(R1).get(); + + char buf[buflen]; + for (size_t i = 0; i < buflen; i++) { + buf[i] = (uint8_t)rand(); + } + + stateChange = {ChangeType::REPLACEMENT, {R0}, {(uint64_t)buflen}}; + + stateChange.memoryAddresses.push_back({bufPtr, (uint8_t)buflen}); + stateChange.memoryAddressValues.push_back(RegisterValue(buf, buflen)); + + break; + } + case 293: // rseq + { + stateChange = {ChangeType::REPLACEMENT, {R0}, {0ull}}; + break; + } + default: printException(instruction_); - std::cout << "Unrecognised syscall: " << syscallId << std::endl; + std::cout << "\n[SimEng:ExceptionHandler] Unrecognised syscall: " + << syscallId << std::endl; return fatal(); } @@ -655,7 +702,8 @@ bool ExceptionHandler::readStringThen(char* buffer, uint64_t address, void ExceptionHandler::readLinkAt(span path) { if (path.size() == kernel::Linux::LINUX_PATH_MAX) { // TODO: Handle LINUX_PATH_MAX case - std::cout << "Path exceeds LINUX_PATH_MAX" << std::endl; + std::cout << "\n[SimEng:ExceptionHandler] Path exceeds LINUX_PATH_MAX" + << std::endl; fatal(); return; } @@ -670,7 +718,8 @@ void ExceptionHandler::readLinkAt(span path) { if (result < 0) { // TODO: Handle error case - std::cout << "Error generated by readlinkat" << std::endl; + std::cout << "\n[SimEng:ExceptionHandler] Error generated by readlinkat" + << std::endl; fatal(); return; } @@ -746,7 +795,7 @@ const ExceptionResult& ExceptionHandler::getResult() const { return result_; } void ExceptionHandler::printException(const Instruction& insn) const { auto exception = insn.getException(); std::cout << std::endl; - std::cout << "Encountered "; + std::cout << "[SimEng:ExceptionHandler] Encountered "; switch (exception) { case InstructionException::EncodingUnallocated: std::cout << "illegal instruction"; @@ -772,14 +821,19 @@ void ExceptionHandler::printException(const Instruction& insn) const { case InstructionException::NoAvailablePort: std::cout << "unsupported execution port"; break; + case InstructionException::UnmappedSysReg: + std::cout << "unmapped system register"; + break; default: std::cout << "unknown (id: " << static_cast(exception) << ")"; } - std::cout << " exception\n"; + std::cout << " exception" << std::endl; - std::cout << " Generated by instruction: \n" - << " 0x" << std::hex << std::setfill('0') << std::setw(16) + std::cout << "[SimEng:ExceptionHandler] Generated by instruction:" + << std::endl; + std::cout << "[SimEng:ExceptionHandler] 0x" << std::hex + << std::setfill('0') << std::setw(16) << insn.getInstructionAddress() << ": "; auto& metadata = insn.getMetadata(); @@ -793,8 +847,9 @@ void ExceptionHandler::printException(const Instruction& insn) const { } else { std::cout << metadata.mnemonic << " " << metadata.operandStr; } - std::cout << "\n opcode ID: " << metadata.opcode; std::cout << std::endl; + std::cout << "[SimEng:ExceptionHandler] opcode ID: " << metadata.opcode + << std::endl; } bool ExceptionHandler::fatal() { diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index ade2b96f0d..f6596aeeeb 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -120,8 +120,6 @@ bool Instruction::isStoreAddress() const { return isStoreAddress_; } bool Instruction::isStoreData() const { return isStoreData_; } bool Instruction::isLoad() const { return isLoad_; } bool Instruction::isBranch() const { return isBranch_; } -bool Instruction::isRET() const { return isRET_; } -bool Instruction::isBL() const { return isBL_; } void Instruction::setMemoryAddresses( const std::vector& addresses) { @@ -156,6 +154,10 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { return {false, 0}; } +BranchType Instruction::getBranchType() const { return branchType_; } + +uint64_t Instruction::getKnownTarget() const { return knownTarget_; } + uint16_t Instruction::getGroup() const { // Use identifiers to decide instruction group // Set base @@ -193,7 +195,7 @@ void Instruction::setExecutionInfo(const ExecutionInfo& info) { stallCycles_ = info.stallCycles; supportedPorts_ = info.ports; } -const std::vector& Instruction::getSupportedPorts() { +const std::vector& Instruction::getSupportedPorts() { if (supportedPorts_.size() == 0) { exception_ = InstructionException::NoAvailablePort; exceptionEncountered_ = true; diff --git a/src/lib/arch/aarch64/InstructionMetadata.cc b/src/lib/arch/aarch64/InstructionMetadata.cc index 31ed0083ce..70b837a3a2 100644 --- a/src/lib/arch/aarch64/InstructionMetadata.cc +++ b/src/lib/arch/aarch64/InstructionMetadata.cc @@ -87,6 +87,10 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) // 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; @@ -258,11 +262,6 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) // FMOVXDHighr incorrectly flags destination as only WRITE operands[0].access = CS_AC_READ | CS_AC_WRITE; break; - case Opcode::AArch64_FMOVSi: - operands[0].access = CS_AC_WRITE; - operands[1].access = CS_AC_READ; - operands[1].type = ARM64_OP_IMM; - break; case Opcode::AArch64_FNMSB_ZPmZZ_D: [[fallthrough]]; case Opcode::AArch64_FNMSB_ZPmZZ_S: @@ -271,8 +270,6 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) [[fallthrough]]; case Opcode::AArch64_FNMLS_ZPmZZ_S: [[fallthrough]]; - case Opcode::AArch64_FADDA_VPZ_D: - [[fallthrough]]; case Opcode::AArch64_FMAD_ZPmZZ_D: [[fallthrough]]; case Opcode::AArch64_FMAD_ZPmZZ_S: @@ -380,10 +377,6 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) [[fallthrough]]; case Opcode::AArch64_FMUL_ZZZ_S: [[fallthrough]]; - case Opcode::AArch64_FNEG_ZPmZ_D: - [[fallthrough]]; - case Opcode::AArch64_FNEG_ZPmZ_S: - [[fallthrough]]; case Opcode::AArch64_SMAX_ZI_S: [[fallthrough]]; case Opcode::AArch64_SMINV_VPZ_S: @@ -416,6 +409,10 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) [[fallthrough]]; case Opcode::AArch64_FCPY_ZPmI_S: [[fallthrough]]; + case Opcode::AArch64_FNEG_ZPmZ_D: + [[fallthrough]]; + case Opcode::AArch64_FNEG_ZPmZ_S: + [[fallthrough]]; case Opcode::AArch64_FRINTN_ZPmZ_D: [[fallthrough]]; case Opcode::AArch64_FRINTN_ZPmZ_S: @@ -773,9 +770,29 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) 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; @@ -786,6 +803,8 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) 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; @@ -796,6 +815,9 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) 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; @@ -806,6 +828,9 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) 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; @@ -813,6 +838,14 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) // For vector arrangment of 32-bit, post_index immediate is 4 operands[2].imm = 4; 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_LD1Twov16b_POST: @@ -1060,11 +1093,11 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) operands[1].access = CS_AC_READ; break; } - case Opcode::AArch64_SST1B_D: + case Opcode::AArch64_SST1B_D_REAL: [[fallthrough]]; - case Opcode::AArch64_SST1D: + case Opcode::AArch64_SST1D_REAL: [[fallthrough]]; - case Opcode::AArch64_SST1D_SCALED: { + 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 @@ -1392,6 +1425,40 @@ InstructionMetadata::InstructionMetadata(const cs_insn& insn) 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; } revertAliasing(); @@ -1675,9 +1742,9 @@ void InstructionMetadata::revertAliasing() { operands[2].vector_index = -1; return; } - if (opcode == Opcode::AArch64_CPYi8 || opcode == Opcode::AArch64_CPYi16 || - opcode == Opcode::AArch64_CPYi32 || - opcode == Opcode::AArch64_CPYi64) { + 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; } @@ -1791,17 +1858,14 @@ void InstructionMetadata::revertAliasing() { opcode == Opcode::AArch64_DUP_ZZI_D || opcode == Opcode::AArch64_DUP_ZZI_Q) { // mov Zd.T, Vn; alias for dup Zd.T, Zn.T[0] - operandCount = 2; operands[0].access = CS_AC_WRITE; - operands[1].type = ARM64_OP_REG; operands[1].access = CS_AC_READ; uint8_t start = operandStr[2] == '.' ? 7 : 8; uint8_t end = operandStr.length() - start; - // ARM64_REG_Z0 == 245 - operands[1].reg = - static_cast(245 + stoi(operandStr.substr(start, end))); + operands[1].reg = static_cast( + ARM64_REG_Z0 + stoi(operandStr.substr(start, end))); operands[1].vector_index = 0; return; } @@ -1811,6 +1875,15 @@ void InstructionMetadata::revertAliasing() { // 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_ORRWri || opcode == Opcode::AArch64_ORRWrs || opcode == Opcode::AArch64_ORRXri || @@ -1896,6 +1969,11 @@ void InstructionMetadata::revertAliasing() { // 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: if (opcode == Opcode::AArch64_MADDXrrr || @@ -2000,6 +2078,18 @@ void InstructionMetadata::revertAliasing() { } 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: if (opcode == Opcode::AArch64_RORVWr || diff --git a/src/lib/arch/aarch64/Instruction_address.cc b/src/lib/arch/aarch64/Instruction_address.cc index 6ebeed5ae1..3b9ea3d320 100644 --- a/src/lib/arch/aarch64/Instruction_address.cc +++ b/src/lib/arch/aarch64/Instruction_address.cc @@ -110,67 +110,75 @@ span Instruction::generateAddresses() { break; } case Opcode::AArch64_LD1Rv16b: { // ld1r {vt.16b}, [xn] - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv16b_POST: { // ld1r {vt.16b}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv1d: { // ld1r {vt.1d}, [xn] - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv1d_POST: { // ld1r {vt.1d}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv2d: { // ld1r {vt.2d}, [xn] - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv2d_POST: { // ld1r {vt.2d}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv2s: { // ld1r {vt.2s}, [xn] - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv2s_POST: { // ld1r {vt.2s}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv4h: { // ld1r {vt.4h}, [xn] - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv4h_POST: { // ld1r {vt.4h}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv8b: { // ld1r {vt.8b}, [xn] - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv8b_POST: { // ld1r {vt.8b}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 8}}); + setMemoryAddresses({{operands[0].get(), 8}}); break; } case Opcode::AArch64_LD1Rv8h: { // ld1r {vt.8h}, [xn] - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv8h_POST: { // ld1r {vt.8h}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv4s: { // ld1r {vt.4s}, [xn] - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Rv4s_POST: { // ld1r {vt.4s}, [xn], #imm - setMemoryAddresses({{operands[1].get(), 16}}); + setMemoryAddresses({{operands[0].get(), 16}}); + break; + } + case Opcode::AArch64_LD1Onev16b: { // ld1 {vt.16b}, [xn] + setMemoryAddresses({{operands[0].get(), 16}}); + break; + } + case Opcode::AArch64_LD1Onev16b_POST: { // ld1 {vt.16b}, [xn], #imm + setMemoryAddresses({{operands[0].get(), 16}}); break; } case Opcode::AArch64_LD1Twov16b: { // ld1 {vt1.16b, vt2.16b}, [xn] @@ -415,6 +423,9 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } + case Opcode::AArch64_LD2Twov4s: { // ld2 {vt1.4s, vt2.4s}, [xn] + [[fallthrough]]; + } case Opcode::AArch64_LD2Twov4s_POST: { // ld2 {vt1.4s, vt2.4s}, [xn], // #imm const uint64_t base = operands[2].get(); @@ -822,7 +833,7 @@ span Instruction::generateAddresses() { setMemoryAddresses(std::move(addresses)); break; } - case Opcode::AArch64_SST1B_D: { // st1b {zd.d}, pg, [xn, zm.d] + case Opcode::AArch64_SST1B_D_REAL: { // st1b {zd.d}, pg, [xn, zm.d] const uint64_t* p = operands[1].getAsVector(); const uint16_t partition_num = VL_bits / 64; @@ -841,7 +852,7 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_SST1D: { // st1d {zt.d}, pg, [xn, zm.d] + case Opcode::AArch64_SST1D_REAL: { // st1d {zt.d}, pg, [xn, zm.d] const uint64_t* p = operands[1].getAsVector(); const uint16_t partition_num = VL_bits / 64; @@ -861,8 +872,8 @@ span Instruction::generateAddresses() { setMemoryAddresses(addresses); break; } - case Opcode::AArch64_SST1D_SCALED: { // st1d {zt.d}, pg, [xn, zm.d, lsl - // #3] + case Opcode::AArch64_SST1D_SCALED_SCALED_REAL: { // st1d {zt.d}, pg, [xn, + // zm.d, lsl #3] const uint64_t* p = operands[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 b328fe1ed9..42fe13a809 100644 --- a/src/lib/arch/aarch64/Instruction_decode.cc +++ b/src/lib/arch/aarch64/Instruction_decode.cc @@ -221,14 +221,32 @@ void Instruction::decode() { sourceRegisterCount++; } } else if (op.type == ARM64_OP_REG_MRS) { - sourceRegisters[sourceRegisterCount] = { - RegisterType::SYSTEM, architecture_.getSystemRegisterTag(op.imm)}; - sourceRegisterCount++; - operandsPending++; + int32_t sysRegTag = architecture_.getSystemRegisterTag(op.imm); + if (sysRegTag == -1) { + exceptionEncountered_ = true; + exception_ = InstructionException::UnmappedSysReg; + // Clear any registered operands + sourceRegisterCount = 0; + destinationRegisterCount = 0; + } else { + sourceRegisters[sourceRegisterCount] = { + RegisterType::SYSTEM, static_cast(sysRegTag)}; + sourceRegisterCount++; + operandsPending++; + } } else if (op.type == ARM64_OP_REG_MSR) { - destinationRegisters[destinationRegisterCount] = { - RegisterType::SYSTEM, architecture_.getSystemRegisterTag(op.imm)}; - destinationRegisterCount++; + int32_t sysRegTag = architecture_.getSystemRegisterTag(op.imm); + if (sysRegTag == -1) { + exceptionEncountered_ = true; + exception_ = InstructionException::UnmappedSysReg; + // Clear any registered operands + sourceRegisterCount = 0; + destinationRegisterCount = 0; + } else { + destinationRegisters[destinationRegisterCount] = { + RegisterType::SYSTEM, static_cast(sysRegTag)}; + destinationRegisterCount++; + } } } @@ -238,11 +256,69 @@ void Instruction::decode() { isBranch_ = true; } } - if (metadata.opcode == 325 || metadata.opcode == 326) { - isBL_ = true; - } - if (metadata.opcode == 2756) { - isRET_ = true; + + // Identify branch type + if (isBranch_) { + switch (metadata.opcode) { + case Opcode::AArch64_B: // b label + branchType_ = BranchType::Unconditional; + knownTarget_ = metadata.operands[0].imm; + break; + case Opcode::AArch64_BR: { // br xn + branchType_ = BranchType::Unconditional; + break; + } + case Opcode::AArch64_BL: // bl #imm + branchType_ = BranchType::SubroutineCall; + knownTarget_ = metadata.operands[0].imm; + break; + case Opcode::AArch64_BLR: { // blr xn + branchType_ = BranchType::SubroutineCall; + break; + } + case Opcode::AArch64_Bcc: { // b.cond label + if (metadata.operands[0].imm < 0) + branchType_ = BranchType::LoopClosing; + else + branchType_ = BranchType::Conditional; + knownTarget_ = metadata.operands[0].imm; + break; + } + case Opcode::AArch64_CBNZW: // cbnz wn, #imm + [[fallthrough]]; + case Opcode::AArch64_CBNZX: // cbnz xn, #imm + [[fallthrough]]; + case Opcode::AArch64_CBZW: // cbz wn, #imm + [[fallthrough]]; + case Opcode::AArch64_CBZX: { // cbz xn, #imm + if (metadata.operands[1].imm < 0) + branchType_ = BranchType::LoopClosing; + else + branchType_ = BranchType::Conditional; + knownTarget_ = metadata.operands[1].imm; + break; + } + case Opcode::AArch64_TBNZW: // tbnz wn, #imm, label + [[fallthrough]]; + case Opcode::AArch64_TBNZX: // tbnz xn, #imm, label + [[fallthrough]]; + case Opcode::AArch64_TBZW: // tbz wn, #imm, label + [[fallthrough]]; + case Opcode::AArch64_TBZX: { // tbz xn, #imm, label + if (metadata.operands[2].imm < 0) + branchType_ = BranchType::LoopClosing; + else + branchType_ = BranchType::Conditional; + knownTarget_ = metadata.operands[2].imm; + break; + } + case Opcode::AArch64_RET: { // ret {xr} + branchType_ = BranchType::Return; + break; + } + default: + break; + } } // Identify loads/stores @@ -302,17 +378,21 @@ void Instruction::decode() { isLoad_ = true; } - if ((227 < metadata.opcode && metadata.opcode < 254) || // AND - (299 < metadata.opcode && metadata.opcode < 321) || // BIC - (733 < metadata.opcode && metadata.opcode < 759) || // EOR/EON - (2626 < metadata.opcode && metadata.opcode < 2655)) { // ORR/ORN + 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) isLogical_ = true; } - if ((379 < metadata.opcode && metadata.opcode < 388) || - (437 < metadata.opcode && metadata.opcode < 625) || - (789 < metadata.opcode && metadata.opcode < 812) || - (850 < metadata.opcode && metadata.opcode < 979)) { + 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)) { isCompare_ = true; // Capture those floating point compare instructions with no destination // register @@ -322,10 +402,14 @@ void Instruction::decode() { } } - if ((984 < metadata.opcode && metadata.opcode < 1190) || - (metadata.opcode == 1210) || - (2871 < metadata.opcode && metadata.opcode < 2907) || - (4010 < metadata.opcode && metadata.opcode < 4046)) { + 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)) { isConvert_ = true; // Capture those floating point convert instructions whose destination // register is general purpose @@ -335,26 +419,74 @@ void Instruction::decode() { } // Identify divide or square root operations - if ((1189 < metadata.opcode && metadata.opcode < 1204) || - (1605 < metadata.opcode && metadata.opcode < 1617) || - (2906 < metadata.opcode && metadata.opcode < 2913) || - (4045 < metadata.opcode && metadata.opcode < 4052)) { + 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)) { isDivideOrSqrt_ = true; } // Identify multiply operations - if ((1210 < metadata.opcode && metadata.opcode < 1214) || - (1328 < metadata.opcode && metadata.opcode < 1367) || - (1393 < metadata.opcode && metadata.opcode < 1444) || - (1454 < metadata.opcode && metadata.opcode < 1458) || - (1469 < metadata.opcode && metadata.opcode < 1476) || - (2502 < metadata.opcode && metadata.opcode < 2505) || - (2578 < metadata.opcode && metadata.opcode < 2599) || - (2992 == metadata.opcode) || - (3076 < metadata.opcode && metadata.opcode < 3093) || - (3148 < metadata.opcode && metadata.opcode < 3197) || - (4072 == metadata.opcode) || - (4154 < metadata.opcode && metadata.opcode < 4171)) { + 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)) { isMultiply_ = true; } @@ -364,17 +496,18 @@ void Instruction::decode() { isPredicate_ = true; } // Uncaught float data assignment for FMOV move to general instructions - if ((1366 < metadata.opcode && metadata.opcode < 1391) && + if (((430 <= metadata.opcode && metadata.opcode <= 432) || + (2409 <= metadata.opcode && metadata.opcode <= 2429)) && !(isScalarData_ || isVectorData_)) { isScalarData_ = true; } // Uncaught vector data assignment for SMOV and UMOV instructions - if ((3071 < metadata.opcode && metadata.opcode < 3077) || - (4150 < metadata.opcode && metadata.opcode < 4155)) { + if ((4341 <= metadata.opcode && metadata.opcode <= 4350) || + (5795 <= metadata.opcode && metadata.opcode <= 5802)) { isVectorData_ = true; } // Uncaught float data assignment for FCVT convert to general instructions - if ((984 < metadata.opcode && metadata.opcode < 1190) && + if ((1976 <= metadata.opcode && metadata.opcode <= 2186) && !(isScalarData_ || isVectorData_)) { isScalarData_ = true; } diff --git a/src/lib/arch/aarch64/Instruction_execute.cc b/src/lib/arch/aarch64/Instruction_execute.cc index 7114bd4e52..aabe39bb22 100644 --- a/src/lib/arch/aarch64/Instruction_execute.cc +++ b/src/lib/arch/aarch64/Instruction_execute.cc @@ -63,95 +63,11 @@ void Instruction::execute() { } } else { switch (metadata.opcode) { - case Opcode::AArch64_ABS_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABS_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABS_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABS_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ABSv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADCSWr: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADCSXr: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADCWr: { - return executionNYI(); - break; - } case Opcode::AArch64_ADCXr: { // adc xd, xn, xm auto [result, nzcv] = arithmeticHelp::addCarry_3ops(operands); results[0] = result; break; } - case Opcode::AArch64_ADDHNv2i64_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDHNv2i64_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDHNv4i32_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDHNv4i32_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDHNv8i16_v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDHNv8i16_v8i8: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDPL_XXI: { // addpl xd, xn, #imm auto x = operands[0].get(); auto y = static_cast(metadata.operands[2].imm); @@ -164,10 +80,6 @@ void Instruction::execute() { results[0] = neonHelp::vecAddp_3ops(operands); break; } - case Opcode::AArch64_ADDPv2i32: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDPv2i64: { // addp vd.2d, vn.2d, vm.2d results[0] = neonHelp::vecAddp_3ops(operands); break; @@ -176,10 +88,6 @@ void Instruction::execute() { results[0] = neonHelp::vecSumElems_2ops(operands); break; } - case Opcode::AArch64_ADDPv4i16: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDPv4i32: { // addp vd.4s, vn.4s, vm.4s results[0] = neonHelp::vecAddp_3ops(operands); break; @@ -188,10 +96,6 @@ void Instruction::execute() { results[0] = neonHelp::vecAddp_3ops(operands); break; } - case Opcode::AArch64_ADDPv8i8: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDSWri: { // adds wd, wn, #imm{, shift} auto [result, nzcv] = arithmeticHelp::addShift_imm(operands, metadata, true); @@ -199,10 +103,6 @@ void Instruction::execute() { results[1] = {result, 8}; break; } - case Opcode::AArch64_ADDSWrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDSWrs: { // adds wd, wn, wm{, shift} auto [result, nzcv] = arithmeticHelp::addShift_3ops(operands, metadata, true); @@ -224,10 +124,6 @@ void Instruction::execute() { results[1] = result; break; } - case Opcode::AArch64_ADDSXrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDSXrs: { // adds xd, xn, xm{, shift} auto [result, nzcv] = arithmeticHelp::addShift_3ops(operands, metadata, true); @@ -251,22 +147,6 @@ void Instruction::execute() { results[0] = x + (VL * y); break; } - case Opcode::AArch64_ADDVv16i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADDVv8i16v: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDVv8i8v: { // addv bd, vn.8b results[0] = neonHelp::vecSumElems_2ops(operands); break; @@ -277,10 +157,6 @@ void Instruction::execute() { results[0] = {result, 8}; break; } - case Opcode::AArch64_ADDWrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDWrs: { // add wd, wn, wm{, shift #amount} auto [result, nzcv] = arithmeticHelp::addShift_3ops(operands, metadata, false); @@ -299,10 +175,6 @@ void Instruction::execute() { results[0] = result; break; } - case Opcode::AArch64_ADDXrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDXrs: { // add xd, xn, xm, {shift #amount} auto [result, nzcv] = arithmeticHelp::addShift_3ops(operands, metadata, false); @@ -316,22 +188,6 @@ void Instruction::execute() { results[0] = result; break; } - case Opcode::AArch64_ADD_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADD_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADD_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADD_ZI_S: { - return executionNYI(); - break; - } case Opcode::AArch64_ADD_ZPmZ_B: { // add zdn.b, pg/m, zdn.b, zm.b results[0] = sveHelp::sveAddPredicated_vecs(operands, VL_bits); break; @@ -367,10 +223,6 @@ void Instruction::execute() { results[0] = sveHelp::sveAdd_3ops(operands, VL_bits); break; } - case Opcode::AArch64_ADDlowTLS: { - return executionNYI(); - break; - } case Opcode::AArch64_ADDv16i8: { // add vd.16b, vn.16b, vm.16b results[0] = neonHelp::vecAdd_3ops(operands); break; @@ -403,14 +255,6 @@ void Instruction::execute() { results[0] = neonHelp::vecAdd_3ops(operands); break; } - case Opcode::AArch64_ADJCALLSTACKDOWN: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADJCALLSTACKUP: { - return executionNYI(); - break; - } case Opcode::AArch64_ADR: { // adr xd, #imm results[0] = instructionAddress_ + metadata.operands[1].imm; break; @@ -438,62 +282,6 @@ void Instruction::execute() { VL_bits); break; } - case Opcode::AArch64_ADR_SXTW_ZZZ_D_0: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_SXTW_ZZZ_D_1: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_SXTW_ZZZ_D_2: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_SXTW_ZZZ_D_3: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_UXTW_ZZZ_D_0: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_UXTW_ZZZ_D_1: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_UXTW_ZZZ_D_2: { - return executionNYI(); - break; - } - case Opcode::AArch64_ADR_UXTW_ZZZ_D_3: { - return executionNYI(); - break; - } - case Opcode::AArch64_AESDrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_AESErr: { - return executionNYI(); - break; - } - case Opcode::AArch64_AESIMCrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_AESIMCrrTied: { - return executionNYI(); - break; - } - case Opcode::AArch64_AESMCrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_AESMCrrTied: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDSWri: { // ands wd, wn, #imm auto [result, nzcv] = logicalHelp::logicOp_imm( operands, metadata, true, @@ -502,10 +290,6 @@ void Instruction::execute() { results[1] = {result, 8}; break; } - case Opcode::AArch64_ANDSWrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDSWrs: { // ands wd, wn, wm{, shift #amount} auto [result, nzcv] = logicalHelp::logicOpShift_3ops( operands, metadata, true, @@ -522,10 +306,6 @@ void Instruction::execute() { results[1] = result; break; } - case Opcode::AArch64_ANDSXrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDSXrs: { // ands xd, xn, xm{, shift #amount} auto [result, nzcv] = logicalHelp::logicOpShift_3ops( operands, metadata, true, @@ -534,26 +314,6 @@ void Instruction::execute() { results[1] = result; break; } - case Opcode::AArch64_ANDS_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_ANDV_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ANDV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ANDV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ANDV_VPZ_S: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDWri: { // and wd, wn, #imm auto [result, nzcv] = logicalHelp::logicOp_imm( operands, metadata, false, @@ -561,10 +321,6 @@ void Instruction::execute() { results[0] = {result, 8}; break; } - case Opcode::AArch64_ANDWrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDWrs: { // and wd, wn, wm{, shift #amount} auto [result, nzcv] = logicalHelp::logicOpShift_3ops( operands, metadata, false, @@ -579,10 +335,6 @@ void Instruction::execute() { results[0] = result; break; } - case Opcode::AArch64_ANDXrr: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDXrs: { // and xd, xn, xm{, shift #amount} auto [result, nzcv] = logicalHelp::logicOpShift_3ops( operands, metadata, false, @@ -632,10 +384,6 @@ void Instruction::execute() { [](uint32_t x, uint32_t y) -> uint32_t { return x & y; }); break; } - case Opcode::AArch64_AND_ZZZ: { - return executionNYI(); - break; - } case Opcode::AArch64_ANDv16i8: { // and vd.16b, vn.16b, vm.16b results[0] = neonHelp::vecLogicOp_3vecs( operands, [](uint8_t x, uint8_t y) -> uint8_t { return x & y; }); @@ -646,17904 +394,4501 @@ void Instruction::execute() { operands, [](uint8_t x, uint8_t y) -> uint8_t { return x & y; }); break; } - case Opcode::AArch64_ASRD_ZPmI_B: { - return executionNYI(); + case Opcode::AArch64_ASRVWr: { // asrv wd, wn, wm + results[0] = {logicalHelp::asrv_3gpr(operands), 8}; break; } - case Opcode::AArch64_ASRD_ZPmI_D: { - return executionNYI(); + case Opcode::AArch64_ASRVXr: { // asrv xd, xn, xm + results[0] = logicalHelp::asrv_3gpr(operands); break; } - case Opcode::AArch64_ASRD_ZPmI_H: { - return executionNYI(); + case Opcode::AArch64_B: { // b label + branchTaken_ = true; + branchAddress_ = instructionAddress_ + metadata.operands[0].imm; break; } - case Opcode::AArch64_ASRD_ZPmI_S: { - return executionNYI(); + case Opcode::AArch64_BFMWri: { // bfm wd, wn, #immr, #imms + results[0] = { + bitmanipHelp::bfm_2imms(operands, metadata, false, false), + 8}; break; } - case Opcode::AArch64_ASRR_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_BFMXri: { // bfm xd, xn, #immr, #imms + results[0] = + bitmanipHelp::bfm_2imms(operands, metadata, false, false); break; } - case Opcode::AArch64_ASRR_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_BICSWrs: { // bics wd, wn, wm{, shift #amount} + auto [result, nzcv] = + logicalHelp::bicShift_3ops(operands, metadata, true); + results[0] = nzcv; + results[1] = {result, 8}; break; } - case Opcode::AArch64_ASRR_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_BICSXrs: { // bics xd, xn, xm{, shift #amount} + auto [result, nzcv] = + logicalHelp::bicShift_3ops(operands, metadata, true); + results[0] = nzcv; + results[1] = result; break; } - case Opcode::AArch64_ASRR_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_BICWrs: { // bic wd, wn, wm{, shift #amount} + auto [result, nzcv] = + logicalHelp::bicShift_3ops(operands, metadata, false); + results[0] = {result, 8}; break; } - case Opcode::AArch64_ASRVWr: { // asrv wd, wn, wm - results[0] = {logicalHelp::asrv_3gpr(operands), 8}; + case Opcode::AArch64_BICXrs: { // bic xd, xn, xm{, shift #amount} + auto [result, nzcv] = + logicalHelp::bicShift_3ops(operands, metadata, false); + results[0] = result; break; } - case Opcode::AArch64_ASRVXr: { // asrv xd, xn, xm - results[0] = logicalHelp::asrv_3gpr(operands); + case Opcode::AArch64_BICv16i8: { // bic vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecBic_3ops(operands); break; } - case Opcode::AArch64_ASR_WIDE_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_BICv4i32: { // bic vd.4s, #imm{, lsl #shift} + results[0] = neonHelp::vecBicShift_imm(operands, metadata); break; } - case Opcode::AArch64_ASR_WIDE_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_BICv8i16: { // bic vd.8h, #imm{, lsl #shift} + results[0] = neonHelp::vecBicShift_imm(operands, metadata); break; } - case Opcode::AArch64_ASR_WIDE_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_BICv8i8: { // bic vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecBic_3ops(operands); break; } - case Opcode::AArch64_ASR_WIDE_ZZZ_B: { - return executionNYI(); + case Opcode::AArch64_BIFv16i8: { // bif vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecBitwiseInsert<16>(operands, true); break; } - case Opcode::AArch64_ASR_WIDE_ZZZ_H: { - return executionNYI(); + case Opcode::AArch64_BITv16i8: { // bit vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecBitwiseInsert<16>(operands, false); break; } - case Opcode::AArch64_ASR_WIDE_ZZZ_S: { - return executionNYI(); + case Opcode::AArch64_BITv8i8: { // bit vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecBitwiseInsert<8>(operands, false); break; } - case Opcode::AArch64_ASR_ZPmI_B: { - return executionNYI(); + case Opcode::AArch64_BL: { // bl #imm + branchTaken_ = true; + branchAddress_ = instructionAddress_ + metadata.operands[0].imm; + results[0] = static_cast(instructionAddress_ + 4); break; } - case Opcode::AArch64_ASR_ZPmI_D: { - return executionNYI(); + case Opcode::AArch64_BLR: { // blr xn + branchTaken_ = true; + branchAddress_ = operands[0].get(); + results[0] = static_cast(instructionAddress_ + 4); break; } - case Opcode::AArch64_ASR_ZPmI_H: { - return executionNYI(); + case Opcode::AArch64_BR: { // br xn + branchTaken_ = true; + branchAddress_ = operands[0].get(); break; } - case Opcode::AArch64_ASR_ZPmI_S: { - return executionNYI(); + case Opcode::AArch64_BRK: { + // TODO: Generate breakpoint exception break; } - case Opcode::AArch64_ASR_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_BSLv16i8: { // bsl vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecBsl<16>(operands); break; } - case Opcode::AArch64_ASR_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_Bcc: { // b.cond label + if (AuxFunc::conditionHolds(metadata.cc, operands[0].get())) { + branchTaken_ = true; + branchAddress_ = instructionAddress_ + metadata.operands[0].imm; + } else { + branchTaken_ = false; + branchAddress_ = instructionAddress_ + 4; + } break; } - case Opcode::AArch64_ASR_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_CASALW: { // casal ws, wt, [xn|sp] + // LOAD / STORE + const uint32_t s = operands[0].get(); + const uint32_t t = operands[1].get(); + const uint32_t n = memoryData[0].get(); + if (n == s) memoryData[0] = t; break; } - case Opcode::AArch64_ASR_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_CASALX: { // casal xs, xt, [xn|sp] + // LOAD / STORE + const uint64_t s = operands[0].get(); + const uint64_t t = operands[1].get(); + const uint64_t n = memoryData[0].get(); + if (n == s) memoryData[0] = t; break; } - case Opcode::AArch64_ASR_ZZI_B: { - return executionNYI(); + case Opcode::AArch64_CBNZW: { // cbnz wn, #imm + auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( + operands, metadata, instructionAddress_, + [](uint32_t x) -> bool { return x != 0; }); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_ASR_ZZI_D: { - return executionNYI(); + case Opcode::AArch64_CBNZX: { // cbnz xn, #imm + auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( + operands, metadata, instructionAddress_, + [](uint64_t x) -> bool { return x != 0; }); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_ASR_ZZI_H: { - return executionNYI(); + case Opcode::AArch64_CBZW: { // cbz wn, #imm + auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( + operands, metadata, instructionAddress_, + [](uint32_t x) -> bool { return x == 0; }); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_ASR_ZZI_S: { - return executionNYI(); + case Opcode::AArch64_CBZX: { // cbz xn, #imm + auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( + operands, metadata, instructionAddress_, + [](uint64_t x) -> bool { return x == 0; }); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_AUTDA: { - return executionNYI(); + case Opcode::AArch64_CCMNWi: { // ccmn wn, #imm, #nzcv, cc + results[0] = conditionalHelp::ccmn_imm(operands, metadata); break; } - case Opcode::AArch64_AUTDB: { - return executionNYI(); + case Opcode::AArch64_CCMNXi: { // ccmn xn, #imm, #nzcv, cc + results[0] = conditionalHelp::ccmn_imm(operands, metadata); break; } - case Opcode::AArch64_AUTDZA: { - return executionNYI(); + case Opcode::AArch64_CCMPWi: { // ccmp wn, #imm, #nzcv, cc + results[0] = conditionalHelp::ccmp_imm(operands, metadata); break; } - case Opcode::AArch64_AUTDZB: { - return executionNYI(); + case Opcode::AArch64_CCMPWr: { // ccmp wn, wm, #nzcv, cc + results[0] = conditionalHelp::ccmp_reg(operands, metadata); break; } - case Opcode::AArch64_AUTIA: { - return executionNYI(); + case Opcode::AArch64_CCMPXi: { // ccmp xn, #imm, #nzcv, cc + results[0] = conditionalHelp::ccmp_imm(operands, metadata); break; } - case Opcode::AArch64_AUTIA1716: { - return executionNYI(); + case Opcode::AArch64_CCMPXr: { // ccmp xn, xm, #nzcv, cc + results[0] = conditionalHelp::ccmp_reg(operands, metadata); break; } - case Opcode::AArch64_AUTIASP: { - return executionNYI(); + case Opcode::AArch64_CLZXr: { // clz xd, xn + results[0] = arithmeticHelp::clz_reg(operands); break; } - case Opcode::AArch64_AUTIAZ: { - return executionNYI(); + case Opcode::AArch64_CMEQv16i8: { // cmeq vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecCompare( + operands, false, + [](uint8_t x, uint8_t y) -> bool { return (x == y); }); break; } - case Opcode::AArch64_AUTIB: { - return executionNYI(); + case Opcode::AArch64_CMEQv16i8rz: { // cmeq vd.16b, vn.16b, #0 + results[0] = neonHelp::vecCompare( + operands, true, + [](uint8_t x, uint8_t y) -> bool { return (x == y); }); break; } - case Opcode::AArch64_AUTIB1716: { - return executionNYI(); + case Opcode::AArch64_CMEQv4i32: { // cmeq vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecCompare( + operands, false, + [](uint32_t x, uint32_t y) -> bool { return (x == y); }); break; } - case Opcode::AArch64_AUTIBSP: { - return executionNYI(); + case Opcode::AArch64_CMEQv8i8: { // cmeq vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecCompare( + operands, false, + [](int8_t x, int8_t y) -> bool { return (x == y); }); break; } - case Opcode::AArch64_AUTIBZ: { - return executionNYI(); + case Opcode::AArch64_CMEQv8i8rz: { // cmeq vd.8b, vn.8b, #0 + results[0] = neonHelp::vecCompare( + operands, true, + [](int8_t x, int8_t y) -> bool { return (x == y); }); break; } - case Opcode::AArch64_AUTIZA: { - return executionNYI(); + case Opcode::AArch64_CMHIv4i32: { // cmhi vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecCompare( + operands, false, + [](uint32_t x, uint32_t y) -> bool { return (x > y); }); break; } - case Opcode::AArch64_AUTIZB: { - return executionNYI(); + case Opcode::AArch64_CMHSv16i8: { // cmhs vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecCompare( + operands, false, + [](int8_t x, int8_t y) -> bool { return (x >= y); }); break; } - case Opcode::AArch64_B: { // b label - branchTaken_ = true; - branchAddress_ = instructionAddress_ + metadata.operands[0].imm; + case Opcode::AArch64_CMPEQ_PPzZI_B: { // cmpeq pd.b, pg/z, zn.b, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](uint8_t x, uint8_t y) -> bool { return x == y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BCAX: { - return executionNYI(); + case Opcode::AArch64_CMPEQ_PPzZI_D: { // cmpeq pd.d, pg/z, zn.d, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](uint64_t x, uint64_t y) -> bool { return x == y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BFMWri: { // bfm wd, wn, #immr, #imms - results[0] = { - bitmanipHelp::bfm_2imms(operands, metadata, false, false), - 8}; + case Opcode::AArch64_CMPEQ_PPzZI_H: { // cmpeq pd.h, pg/z, zn.h, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](uint16_t x, uint16_t y) -> bool { return x == y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BFMXri: { // bfm xd, xn, #immr, #imms - results[0] = - bitmanipHelp::bfm_2imms(operands, metadata, false, false); + case Opcode::AArch64_CMPEQ_PPzZI_S: { // cmpeq pd.s, pg/z, zn.s, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](uint32_t x, uint32_t y) -> bool { return x == y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICSWrr: { - return executionNYI(); + case Opcode::AArch64_CMPEQ_PPzZZ_B: { // cmpeq pd.b, pg/z, zn.b, zm.b + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint8_t x, uint8_t y) -> bool { return x == y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICSWrs: { // bics wd, wn, wm{, shift #amount} - auto [result, nzcv] = - logicalHelp::bicShift_3ops(operands, metadata, true); + case Opcode::AArch64_CMPEQ_PPzZZ_D: { // cmpeq pd.d, pg/z, zn.d, zm.d + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint64_t x, uint64_t y) -> bool { return x == y; }); results[0] = nzcv; - results[1] = {result, 8}; + results[1] = output; break; } - case Opcode::AArch64_BICSXrr: { - return executionNYI(); + case Opcode::AArch64_CMPEQ_PPzZZ_H: { // cmpeq pd.h, pg/z, zn.h, zm.h + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint16_t x, uint16_t y) -> bool { return x == y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICSXrs: { // bics xd, xn, xm{, shift #amount} - auto [result, nzcv] = - logicalHelp::bicShift_3ops(operands, metadata, true); + case Opcode::AArch64_CMPEQ_PPzZZ_S: { // cmpeq pd.s, pg/z, zn.s, zm.s + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint32_t x, uint32_t y) -> bool { return x == y; }); results[0] = nzcv; - results[1] = result; + results[1] = output; break; } - case Opcode::AArch64_BICS_PPzPP: { - return executionNYI(); + case Opcode::AArch64_CMPGT_PPzZZ_B: { // cmpgt pd.b, pg/z, zn.b, zm.b + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int8_t x, int8_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICWrr: { - return executionNYI(); + case Opcode::AArch64_CMPGT_PPzZZ_D: { // cmpgt pd.d, pg/z, zn.d, zm.d + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int64_t x, int64_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICWrs: { // bic wd, wn, wm{, shift #amount} - auto [result, nzcv] = - logicalHelp::bicShift_3ops(operands, metadata, false); - results[0] = {result, 8}; + case Opcode::AArch64_CMPGT_PPzZZ_H: { // cmpgt pd.h, pg/z, zn.h, zm.h + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int16_t x, int16_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICXrr: { - return executionNYI(); + case Opcode::AArch64_CMPGT_PPzZZ_S: { // cmpgt pd.s, pg/z, zn.s, zm.s + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int32_t x, int32_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICXrs: { // bic xd, xn, xm{, shift #amount} - auto [result, nzcv] = - logicalHelp::bicShift_3ops(operands, metadata, false); - results[0] = result; + case Opcode::AArch64_CMPHI_PPzZZ_B: { // cmphi pd.b, pg/z, zn.b, zm.b + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint8_t x, uint8_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BIC_PPzPP: { - return executionNYI(); + case Opcode::AArch64_CMPHI_PPzZZ_D: { // cmphi pd.d, pg/z, zn.d, zm.d + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint64_t x, uint64_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BIC_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_CMPHI_PPzZZ_H: { // cmphi pd.h, pg/z, zn.h, zm.h + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint16_t x, uint16_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BIC_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_CMPHI_PPzZZ_S: { // cmphi pd.s, pg/z, zn.s, zm.s + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](uint32_t x, uint32_t y) -> bool { return x > y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BIC_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_CMPNE_PPzZI_B: { // cmpne pd.b, pg/z. zn.b, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](int8_t x, int8_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BIC_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_CMPNE_PPzZI_D: { // cmpne pd.d, pg/z. zn.d, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](int64_t x, int64_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BIC_ZZZ: { - return executionNYI(); + case Opcode::AArch64_CMPNE_PPzZI_H: { // cmpne pd.h, pg/z. zn.h, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](int16_t x, int16_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICv16i8: { // bic vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecBic_3ops(operands); + case Opcode::AArch64_CMPNE_PPzZI_S: { // cmpne pd.s, pg/z. zn.s, #imm + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, true, + [](int32_t x, int32_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICv2i32: { - return executionNYI(); + case Opcode::AArch64_CMPNE_PPzZZ_B: { // cmpne pd.b, pg/z, zn.b, zm.b + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int8_t x, int8_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICv4i16: { - return executionNYI(); + case Opcode::AArch64_CMPNE_PPzZZ_D: { // cmpne pd.d, pg/z, zn.d, zm.d + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int64_t x, int64_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICv4i32: { // bic vd.4s, #imm{, lsl #shift} - results[0] = neonHelp::vecBicShift_imm(operands, metadata); + case Opcode::AArch64_CMPNE_PPzZZ_H: { // cmpne pd.h, pg/z, zn.h, zm.h + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int16_t x, int16_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICv8i16: { - return executionNYI(); + case Opcode::AArch64_CMPNE_PPzZZ_S: { // cmpne pd.s, pg/z, zn.s, zm.s + auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( + operands, metadata, VL_bits, false, + [](int32_t x, int32_t y) -> bool { return x != y; }); + results[0] = nzcv; + results[1] = output; break; } - case Opcode::AArch64_BICv8i8: { // bic vd.8b, vn.8b, vm.8b - results[0] = neonHelp::vecBic_3ops(operands); + case Opcode::AArch64_CNTB_XPiI: { // cntb xd{, pattern{, #imm}} + results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); break; } - case Opcode::AArch64_BIFv16i8: { // bif vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecBitwiseInsert<16>(operands, true); + case Opcode::AArch64_CNTD_XPiI: { // cntd xd{, pattern{, #imm}} + results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); break; } - case Opcode::AArch64_BIFv8i8: { - return executionNYI(); + case Opcode::AArch64_CNTH_XPiI: { // cnth xd{, pattern{, #imm}} + results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); break; } - case Opcode::AArch64_BITv16i8: { // bit vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecBitwiseInsert<16>(operands, false); + case Opcode::AArch64_CNTP_XPP_B: { // cntp xd, pg, pn.b + results[0] = sveHelp::sveCntp(operands, VL_bits); break; } - case Opcode::AArch64_BITv8i8: { // bit vd.8b, vn.8b, vm.8b - results[0] = neonHelp::vecBitwiseInsert<8>(operands, false); + case Opcode::AArch64_CNTP_XPP_D: { // cntp xd, pg, pn.d + results[0] = sveHelp::sveCntp(operands, VL_bits); break; } - case Opcode::AArch64_BL: { // bl #imm - branchTaken_ = true; - branchAddress_ = instructionAddress_ + metadata.operands[0].imm; - results[0] = static_cast(instructionAddress_ + 4); + case Opcode::AArch64_CNTP_XPP_H: { // cntp xd, pg, pn.h + results[0] = sveHelp::sveCntp(operands, VL_bits); break; } - case Opcode::AArch64_BLR: { // blr xn - branchTaken_ = true; - branchAddress_ = operands[0].get(); - results[0] = static_cast(instructionAddress_ + 4); + case Opcode::AArch64_CNTP_XPP_S: { // cntp xd, pg, pn.s + results[0] = sveHelp::sveCntp(operands, VL_bits); break; } - case Opcode::AArch64_BLRAA: { - return executionNYI(); + case Opcode::AArch64_CNTW_XPiI: { // cntw xd{, pattern{, #imm}} + results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); break; } - case Opcode::AArch64_BLRAAZ: { - return executionNYI(); + case Opcode::AArch64_CNTv8i8: { // cnt vd.8b, vn.8b + results[0] = neonHelp::vecCountPerByte(operands); break; } - case Opcode::AArch64_BLRAB: { - return executionNYI(); + case Opcode::AArch64_CPY_ZPzI_B: { // cpy zd.b, pg/z, #imm{, shift} + results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_BLRABZ: { - return executionNYI(); + case Opcode::AArch64_CPY_ZPzI_D: { // cpy zd.d, pg/z, #imm{, shift} + results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_BR: { // br xn - branchTaken_ = true; - branchAddress_ = operands[0].get(); + case Opcode::AArch64_CPY_ZPzI_H: { // cpy zd.h, pg/z, #imm{, shift} + results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_BRAA: { - return executionNYI(); + case Opcode::AArch64_CPY_ZPzI_S: { // cpy zd.s, pg/z, #imm{, shift} + results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_BRAAZ: { - return executionNYI(); + case Opcode::AArch64_DUPi32: { // dup vd, vn.s[index] + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, false); break; } - case Opcode::AArch64_BRAB: { - return executionNYI(); + case Opcode::AArch64_DUPi64: { // dup vd, vn.d[index] + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, false); break; } - case Opcode::AArch64_BRABZ: { - return executionNYI(); + case Opcode::AArch64_CSELWr: { // csel wd, wn, wm, cc + results[0] = { + conditionalHelp::cs_4ops( + operands, metadata, [](uint32_t x) -> uint32_t { return x; }), + 8}; break; } - case Opcode::AArch64_BRK: { - return executionNYI(); + case Opcode::AArch64_CSELXr: { // csel xd, xn, xm, cc + results[0] = conditionalHelp::cs_4ops( + operands, metadata, [](uint64_t x) -> uint64_t { return x; }); break; } - case Opcode::AArch64_BRKAS_PPzP: { - return executionNYI(); + case Opcode::AArch64_CSINCWr: { // csinc wd, wn, wm, cc + results[0] = {conditionalHelp::cs_4ops( + operands, metadata, + [](uint32_t x) -> uint32_t { return x + 1; }), + 8}; break; } - case Opcode::AArch64_BRKA_PPmP: { - return executionNYI(); + case Opcode::AArch64_CSINCXr: { // csinc xd, xn, xm, cc + results[0] = conditionalHelp::cs_4ops( + operands, metadata, [](uint64_t x) -> uint64_t { return x + 1; }); break; } - case Opcode::AArch64_BRKA_PPzP: { - return executionNYI(); + case Opcode::AArch64_CSINVWr: { // csinv wd, wn, wm, cc + results[0] = { + conditionalHelp::cs_4ops( + operands, metadata, [](uint32_t x) -> uint32_t { return ~x; }), + 8}; break; } - case Opcode::AArch64_BRKBS_PPzP: { - return executionNYI(); + case Opcode::AArch64_CSINVXr: { // csinv xd, xn, xm, cc + results[0] = conditionalHelp::cs_4ops( + operands, metadata, [](uint64_t x) -> uint64_t { return ~x; }); break; } - case Opcode::AArch64_BRKB_PPmP: { - return executionNYI(); + case Opcode::AArch64_CSNEGWr: { // csneg wd, wn, wm, cc + results[0] = { + conditionalHelp::cs_4ops( + operands, metadata, [](int32_t x) -> int32_t { return -x; }), + 8}; break; } - case Opcode::AArch64_BRKB_PPzP: { - return executionNYI(); + case Opcode::AArch64_CSNEGXr: { // csneg xd, xn, xm, cc + results[0] = conditionalHelp::cs_4ops( + operands, metadata, [](uint64_t x) -> uint64_t { return -x; }); break; } - case Opcode::AArch64_BRKNS_PPzP: { - return executionNYI(); + case Opcode::AArch64_DECB_XPiI: { // decb xdn{, pattern{, MUL #imm}} + results[0] = + sveHelp::sveDec_scalar(operands, metadata, VL_bits); break; } - case Opcode::AArch64_BRKN_PPzP: { - return executionNYI(); + case Opcode::AArch64_DECD_XPiI: { // decd xdn{, pattern{, MUL #imm}} + results[0] = + sveHelp::sveDec_scalar(operands, metadata, VL_bits); break; } - case Opcode::AArch64_BRKPAS_PPzPP: { - return executionNYI(); + case Opcode::AArch64_DMB: { // dmb option|#imm + // TODO: Respect memory barriers break; } - case Opcode::AArch64_BRKPA_PPzPP: { - return executionNYI(); + case Opcode::AArch64_DUPM_ZI: { // dupm zd.t, #imm + const uint64_t imm = static_cast(metadata.operands[1].imm); + uint64_t out[32] = {0}; + for (int i = 0; i < (VL_bits / 64); i++) { + out[i] = imm; + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_BRKPBS_PPzPP: { - return executionNYI(); + case Opcode::AArch64_DUP_ZI_B: { // dup zd.b, #imm{, shift} + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_BRKPB_PPzPP: { - return executionNYI(); + case Opcode::AArch64_DUP_ZI_D: { // dup zd.d, #imm{, shift} + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_BSLv16i8: { // bsl vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecBsl<16>(operands); + case Opcode::AArch64_DUP_ZI_H: { // dup zd.h, #imm{, shift} + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_BSLv8i8: { - return executionNYI(); + case Opcode::AArch64_DUP_ZI_S: { // dup zd.s, #imm{, shift} + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_Bcc: { // b.cond label - if (AuxFunc::conditionHolds(metadata.cc, operands[0].get())) { - branchTaken_ = true; - branchAddress_ = instructionAddress_ + metadata.operands[0].imm; - } else { - branchTaken_ = false; - branchAddress_ = instructionAddress_ + 4; - } + case Opcode::AArch64_DUP_ZR_B: { // dup zd.b, wn + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_CASAB: { - return executionNYI(); + case Opcode::AArch64_DUP_ZR_D: { // dup zd.d, xn + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_CASAH: { - return executionNYI(); + case Opcode::AArch64_DUP_ZR_H: { // dup zd.h, wn + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_CASALB: { - return executionNYI(); + case Opcode::AArch64_DUP_ZR_S: { // dup zd.s, wn + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_CASALH: { - return executionNYI(); + case Opcode::AArch64_DUP_ZZI_D: { // dup zd.d, zn.d[#imm] + results[0] = + sveHelp::sveDup_vecIndexed(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CASALW: { // casal ws, wt, [xn|sp] - // LOAD / STORE - const uint32_t s = operands[0].get(); - const uint32_t t = operands[1].get(); - const uint32_t n = memoryData[0].get(); - if (n == s) memoryData[0] = t; + case Opcode::AArch64_DUP_ZZI_Q: { // dup zd.q, zn.q[#imm] + // No data-type for quadwords, but as data is just being moved around we + // can use uint64_t. + const uint16_t index = + 2 * static_cast(metadata.operands[1].vector_index); + const uint64_t* n = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 128; + uint64_t out[32] = {0}; + + if (index < partition_num) { + const uint64_t elementHi = n[index]; + const uint64_t elementLo = n[index + 1]; + for (int i = 0; i < partition_num; i++) { + out[2 * i] = elementHi; // Copy over top half of quadword + out[2 * i + 1] = elementLo; // Copy over lower half of quadword + } + } + results[0] = out; break; } - case Opcode::AArch64_CASALX: { // casal xs, xt, [xn|sp] - // LOAD / STORE - const uint64_t s = operands[0].get(); - const uint64_t t = operands[1].get(); - const uint64_t n = memoryData[0].get(); - if (n == s) memoryData[0] = t; + case Opcode::AArch64_DUP_ZZI_S: { // dup zd.s, zn.s[#imm] + results[0] = + sveHelp::sveDup_vecIndexed(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CASAW: { - return executionNYI(); + case Opcode::AArch64_DUPv16i8gpr: { // dup vd.16b, wn + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, true); break; } - case Opcode::AArch64_CASAX: { - return executionNYI(); + case Opcode::AArch64_DUPv2i32gpr: { // dup vd.2s, wn + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, true); break; } - case Opcode::AArch64_CASB: { - return executionNYI(); + case Opcode::AArch64_DUPv2i32lane: { // dup vd.2s, vn.s[index] + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, false); break; } - case Opcode::AArch64_CASH: { - return executionNYI(); + case Opcode::AArch64_DUPv2i64gpr: { // dup vd.2d, xn + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, true); break; } - case Opcode::AArch64_CASLB: { - return executionNYI(); + case Opcode::AArch64_DUPv2i64lane: { // dup vd.2d, vn.d[index] + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, false); break; } - case Opcode::AArch64_CASLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_CASLW: { - return executionNYI(); + case Opcode::AArch64_DUPv4i16gpr: { // dup vd.4h, wn + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, true); break; } - case Opcode::AArch64_CASLX: { - return executionNYI(); + case Opcode::AArch64_DUPv4i32gpr: { // dup vd.4s, wn + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, true); break; } - case Opcode::AArch64_CASPALW: { - return executionNYI(); + case Opcode::AArch64_DUPv4i32lane: { // dup vd.4s, vn.s[index] + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, false); break; } - case Opcode::AArch64_CASPALX: { - return executionNYI(); + case Opcode::AArch64_DUPv8i16gpr: { // dup vd.8h, wn + results[0] = + neonHelp::vecDup_gprOrIndex(operands, metadata, true); break; } - case Opcode::AArch64_CASPAW: { - return executionNYI(); + case Opcode::AArch64_EORWri: { // eor wd, wn, #imm + auto [result, nzcv] = logicalHelp::logicOp_imm( + operands, metadata, false, + [](uint32_t x, uint32_t y) -> uint32_t { return x ^ y; }); + results[0] = {result, 8}; break; } - case Opcode::AArch64_CASPAX: { - return executionNYI(); + case Opcode::AArch64_EORWrs: { // eor wd, wn, wm{, shift #imm} + auto [result, nzcv] = logicalHelp::logicOpShift_3ops( + operands, metadata, false, + [](uint32_t x, uint32_t y) -> uint32_t { return x ^ y; }); + results[0] = {result, 8}; break; } - case Opcode::AArch64_CASPLW: { - return executionNYI(); + case Opcode::AArch64_EORXri: { // eor xd, xn, #imm + auto [result, nzcv] = logicalHelp::logicOp_imm( + operands, metadata, false, + [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); + results[0] = result; break; } - case Opcode::AArch64_CASPLX: { - return executionNYI(); + case Opcode::AArch64_EORXrs: { // eor xd, xn, xm{, shift #amount} + auto [result, nzcv] = logicalHelp::logicOpShift_3ops( + operands, metadata, false, + [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); + results[0] = result; break; } - case Opcode::AArch64_CASPW: { - return executionNYI(); + case Opcode::AArch64_EOR_PPzPP: { + results[0] = sveHelp::sveLogicOp_preds( + operands, VL_bits, + [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); break; } - case Opcode::AArch64_CASPX: { - return executionNYI(); + case Opcode::AArch64_EOR_ZPmZ_B: { // eor zdn.b, pg/m, zdn.b, zm.b + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); break; } - case Opcode::AArch64_CASW: { - return executionNYI(); + case Opcode::AArch64_EOR_ZPmZ_D: { // eor zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); break; } - case Opcode::AArch64_CASX: { - return executionNYI(); + case Opcode::AArch64_EOR_ZPmZ_H: { // eor zdn.h, pg/m, zdn.h, zm.h + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](uint16_t x, uint16_t y) -> uint16_t { return x ^ y; }); break; } - case Opcode::AArch64_CBNZW: { // cbnz wn, #imm - auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( - operands, metadata, instructionAddress_, - [](uint32_t x) -> bool { return x != 0; }); - branchTaken_ = taken; - branchAddress_ = addr; + case Opcode::AArch64_EOR_ZPmZ_S: { // eor zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](uint32_t x, uint32_t y) -> uint32_t { return x ^ y; }); break; } - case Opcode::AArch64_CBNZX: { // cbnz xn, #imm - auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( - operands, metadata, instructionAddress_, - [](uint64_t x) -> bool { return x != 0; }); - branchTaken_ = taken; - branchAddress_ = addr; + case Opcode::AArch64_EORv16i8: { // eor vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); break; } - case Opcode::AArch64_CBZW: { // cbz wn, #imm - auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( - operands, metadata, instructionAddress_, - [](uint32_t x) -> bool { return x == 0; }); - branchTaken_ = taken; - branchAddress_ = addr; + case Opcode::AArch64_EORv8i8: { // eor vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); break; } - case Opcode::AArch64_CBZX: { // cbz xn, #imm - auto [taken, addr] = conditionalHelp::condBranch_cmpToZero( - operands, metadata, instructionAddress_, - [](uint64_t x) -> bool { return x == 0; }); - branchTaken_ = taken; - branchAddress_ = addr; + case Opcode::AArch64_EXTRWrri: { // extr wd, wn, wm, #lsb + results[0] = { + bitmanipHelp::extrLSB_registers(operands, metadata), 8}; break; } - case Opcode::AArch64_CCMNWi: { // ccmn wn, #imm, #nzcv, cc - results[0] = conditionalHelp::ccmn_imm(operands, metadata); + case Opcode::AArch64_EXTRXrri: { // extr xd, xn, xm, #lsb + results[0] = + bitmanipHelp::extrLSB_registers(operands, metadata); break; } - case Opcode::AArch64_CCMNWr: { - return executionNYI(); + case Opcode::AArch64_EXTv16i8: { // ext vd.16b, vn.16b, vm.16b, #index + results[0] = + neonHelp::vecExtVecs_index(operands, metadata); break; } - case Opcode::AArch64_CCMNXi: { // ccmn xn, #imm, #nzcv, cc - results[0] = conditionalHelp::ccmn_imm(operands, metadata); + case Opcode::AArch64_EXTv8i8: { // ext vd.8b, vn.8b, vm.8b, #index + results[0] = neonHelp::vecExtVecs_index(operands, metadata); break; } - case Opcode::AArch64_CCMNXr: { - return executionNYI(); + case Opcode::AArch64_FABD32: { // fabd sd, sn, sm + results[0] = floatHelp::fabd_3ops(operands); break; } - case Opcode::AArch64_CCMPWi: { // ccmp wn, #imm, #nzcv, cc - results[0] = conditionalHelp::ccmp_imm(operands, metadata); + case Opcode::AArch64_FABD64: { // fabd dd, dn, dm + results[0] = floatHelp::fabd_3ops(operands); break; } - case Opcode::AArch64_CCMPWr: { // ccmp wn, wm, #nzcv, cc - results[0] = conditionalHelp::ccmp_reg(operands, metadata); + case Opcode::AArch64_FABSDr: { // fabs dd, dn + results[0] = floatHelp::fabs_2ops(operands); break; } - case Opcode::AArch64_CCMPXi: { // ccmp xn, #imm, #nzcv, cc - results[0] = conditionalHelp::ccmp_imm(operands, metadata); + case Opcode::AArch64_FABSSr: { // fabs sd, sn + results[0] = floatHelp::fabs_2ops(operands); break; } - case Opcode::AArch64_CCMPXr: { // ccmp xn, xm, #nzcv, cc - results[0] = conditionalHelp::ccmp_reg(operands, metadata); + case Opcode::AArch64_FABS_ZPmZ_D: { // fabs zd.d, pg/m, zn.d + results[0] = sveHelp::sveFabsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CFINV: { - return executionNYI(); + case Opcode::AArch64_FABS_ZPmZ_S: { // fabs zd.s, pg/m, zn.s + results[0] = sveHelp::sveFabsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CLASTA_RPZ_B: { - return executionNYI(); + case Opcode::AArch64_FABSv2f64: { // fabs vd.2d, vn.2d + results[0] = neonHelp::vecFabs_2ops(operands); break; } - case Opcode::AArch64_CLASTA_RPZ_D: { - return executionNYI(); + case Opcode::AArch64_FABSv4f32: { // fabs vd.4s, vn.4s + results[0] = neonHelp::vecFabs_2ops(operands); break; } - case Opcode::AArch64_CLASTA_RPZ_H: { - return executionNYI(); + case Opcode::AArch64_FADDA_VPZ_D: { // fadda dd, pg/m, dn, zm.d + results[0] = sveHelp::sveFaddaPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CLASTA_RPZ_S: { - return executionNYI(); + case Opcode::AArch64_FADDDrr: { // fadd dd, dn, dm + results[0] = {arithmeticHelp::add_3ops(operands), 256}; break; } - case Opcode::AArch64_CLASTA_VPZ_B: { - return executionNYI(); + case Opcode::AArch64_FADDPv2f32: { // faddp vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecAddp_3ops(operands); break; } - case Opcode::AArch64_CLASTA_VPZ_D: { - return executionNYI(); + case Opcode::AArch64_FADDPv2f64: { // faddp vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecAddp_3ops(operands); break; } - case Opcode::AArch64_CLASTA_VPZ_H: { - return executionNYI(); + case Opcode::AArch64_FADDPv2i32p: { // faddp dd, vn.2s + results[0] = neonHelp::vecSumElems_2ops(operands); break; } - case Opcode::AArch64_CLASTA_VPZ_S: { - return executionNYI(); + case Opcode::AArch64_FADDPv2i64p: { // faddp dd, vn.2d + results[0] = neonHelp::vecSumElems_2ops(operands); break; } - case Opcode::AArch64_CLASTA_ZPZ_B: { - return executionNYI(); + case Opcode::AArch64_FADDPv4f32: { // faddp vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecAddp_3ops(operands); break; } - case Opcode::AArch64_CLASTA_ZPZ_D: { - return executionNYI(); + case Opcode::AArch64_FADDSrr: { // fadd sd, sn, sm + results[0] = {arithmeticHelp::add_3ops(operands), 256}; break; } - case Opcode::AArch64_CLASTA_ZPZ_H: { - return executionNYI(); + case Opcode::AArch64_FADD_ZPmI_D: { // fadd zdn.d, pg/m, zdn.d, const + results[0] = sveHelp::sveAddPredicated_const(operands, metadata, + VL_bits); break; } - case Opcode::AArch64_CLASTA_ZPZ_S: { - return executionNYI(); + case Opcode::AArch64_FADD_ZPmI_S: { // fadd zdn.s, pg/m, zdn.s, const + results[0] = + sveHelp::sveAddPredicated_const(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CLASTB_RPZ_B: { - return executionNYI(); + case Opcode::AArch64_FADD_ZPmZ_D: { // fadd zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveAddPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CLASTB_RPZ_D: { - return executionNYI(); + case Opcode::AArch64_FADD_ZPmZ_S: { // fadd zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveAddPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CLASTB_RPZ_H: { - return executionNYI(); + case Opcode::AArch64_FADD_ZZZ_D: { // fadd zd.d, zn.d, zm.d + results[0] = sveHelp::sveAdd_3ops(operands, VL_bits); break; } - case Opcode::AArch64_CLASTB_RPZ_S: { - return executionNYI(); + case Opcode::AArch64_FADD_ZZZ_S: { // fadd zd.s, zn.s, zm.s + results[0] = sveHelp::sveAdd_3ops(operands, VL_bits); break; } - case Opcode::AArch64_CLASTB_VPZ_B: { - return executionNYI(); + case Opcode::AArch64_FADDv2f32: { // fadd vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecAdd_3ops(operands); break; } - case Opcode::AArch64_CLASTB_VPZ_D: { - return executionNYI(); + case Opcode::AArch64_FADDv2f64: { // fadd vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecAdd_3ops(operands); break; } - case Opcode::AArch64_CLASTB_VPZ_H: { - return executionNYI(); + case Opcode::AArch64_FADDv4f32: { // fadd vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecAdd_3ops(operands); break; } - case Opcode::AArch64_CLASTB_VPZ_S: { - return executionNYI(); + case Opcode::AArch64_FCADD_ZPmZ_D: { // fcadd zdn.d, pg/m, zdn.d, zm.d, + // #imm + results[0] = + sveHelp::sveFcaddPredicated(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CLASTB_ZPZ_B: { - return executionNYI(); + case Opcode::AArch64_FCCMPDrr: // fccmp sn, sm, #nzcv, cc + case Opcode::AArch64_FCCMPEDrr: { // fccmpe sn, sm, #nzcv, cc + results[0] = floatHelp::fccmp(operands, metadata); break; } - case Opcode::AArch64_CLASTB_ZPZ_D: { - return executionNYI(); + case Opcode::AArch64_FCCMPESrr: { // fccmpe sn, sm, #nzcv, cc + results[0] = floatHelp::fccmp(operands, metadata); break; } - case Opcode::AArch64_CLASTB_ZPZ_H: { - return executionNYI(); + case Opcode::AArch64_FCCMPSrr: { // fccmp sn, sm, #nzcv, cc + results[0] = floatHelp::fccmp(operands, metadata); break; } - case Opcode::AArch64_CLASTB_ZPZ_S: { - return executionNYI(); + case Opcode::AArch64_FCMEQv2i32rz: { // fcmeq vd.2s, vd.2s, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x == y; }); break; } - case Opcode::AArch64_CLREX: { - return executionNYI(); + case Opcode::AArch64_FCMEQv4i32rz: { // fcmeq vd.4s vn.4s, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x == y; }); break; } - case Opcode::AArch64_CLSWr: { - return executionNYI(); + case Opcode::AArch64_FCMGE_PPzZ0_D: { // fcmge pd.d, pg/z, zn.d, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](double x, double y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLSXr: { - return executionNYI(); + case Opcode::AArch64_FCMGE_PPzZ0_S: { // fcmge pd.s, pg/z, zn.s, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](float x, float y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLS_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_FCMGE_PPzZZ_D: { // fcmge pd.d, pg/z, zn.d, zm.d + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, false, + [](double x, double y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLS_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_FCMGE_PPzZZ_S: { // fcmge pd.s, pg/z, zn.s, zm.s + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, false, + [](float x, float y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLS_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_FCMGEv2f32: { // fcmge vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecFCompare( + operands, false, [](float x, float y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLS_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_FCMGEv2f64: { // fcmge vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecFCompare( + operands, false, [](float x, double y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLSv16i8: { - return executionNYI(); + case Opcode::AArch64_FCMGEv2i64rz: { // fcmge vd.2d, vn.2d, 0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](double x, double y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLSv2i32: { - return executionNYI(); + case Opcode::AArch64_FCMGEv4f32: { // fcmge vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecFCompare( + operands, false, [](float x, float y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLSv4i16: { - return executionNYI(); + case Opcode::AArch64_FCMGEv4i32rz: { // fcmge vd.4s, vn.4s, 0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x >= y; }); break; } - case Opcode::AArch64_CLSv4i32: { - return executionNYI(); + case Opcode::AArch64_FCMGT_PPzZ0_D: { // fcmgt pd.d, pg/z, zn.d, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](double x, double y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLSv8i16: { - return executionNYI(); + case Opcode::AArch64_FCMGT_PPzZ0_S: { // fcmgt pd.s, pg/z, zn.s, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](float x, float y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLSv8i8: { - return executionNYI(); + case Opcode::AArch64_FCMGT_PPzZZ_D: { // fcmgt pd.d, pg/z, zn.d, zm.d + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, false, + [](double x, double y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLZWr: { - return executionNYI(); + case Opcode::AArch64_FCMGT_PPzZZ_S: { // fcmgt pd.s, pg/z, zn.s, zm. + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, false, + [](float x, float y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLZXr: { // clz xd, xn - results[0] = arithmeticHelp::clz_reg(operands); + case Opcode::AArch64_FCMGTv2i32rz: { // fcmgt vd.2s, vn.2s, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLZ_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_FCMGTv2i64rz: { // fcmgt vd.2d, vn.2d, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](double x, double y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLZ_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_FCMGTv4f32: { // fcmgt vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecFCompare( + operands, false, [](float x, float y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLZ_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_FCMGTv4i32rz: { // fcmgt vd.4s, vn.4s, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x > y; }); break; } - case Opcode::AArch64_CLZ_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_FCMLA_ZPmZZ_D: { // fcmla zda, pg/m, zn, zm, #imm + results[0] = + sveHelp::sveFcmlaPredicated(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CLZv16i8: { - return executionNYI(); + case Opcode::AArch64_FCMLE_PPzZ0_D: { // fcmle pd.d, pg/z, zn.d, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](double x, double y) -> bool { return x <= y; }); break; } - case Opcode::AArch64_CLZv2i32: { - return executionNYI(); + case Opcode::AArch64_FCMLE_PPzZ0_S: { // fcmle pd.s, pg/z, zn.s, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](float x, float y) -> bool { return x <= y; }); break; } - case Opcode::AArch64_CLZv4i16: { - return executionNYI(); + case Opcode::AArch64_FCMLT_PPzZ0_S: { // fcmlt pd.s, pg/z, zn.s, #0.0 + results[0] = sveHelp::sveComparePredicated_vecsToPred( + operands, metadata, VL_bits, true, + [](float x, float y) -> bool { return x < y; }); break; } - case Opcode::AArch64_CLZv4i32: { - return executionNYI(); + case Opcode::AArch64_FCMLTv2i32rz: { // fcmlt vd.2s, vn.2s, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x < y; }); break; } - case Opcode::AArch64_CLZv8i16: { - return executionNYI(); + case Opcode::AArch64_FCMLTv2i64rz: { // fcmlt vd.2d, vn.2d, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](double x, double y) -> bool { return x < y; }); break; } - case Opcode::AArch64_CLZv8i8: { - return executionNYI(); + case Opcode::AArch64_FCMLTv4i32rz: { // fcmlt vd.4s, vn.4s, #0.0 + results[0] = neonHelp::vecFCompare( + operands, true, [](float x, float y) -> bool { return x < y; }); break; } - case Opcode::AArch64_CMEQv16i8: { // cmeq vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecCompare( - operands, false, - [](uint8_t x, uint8_t y) -> bool { return (x == y); }); + case Opcode::AArch64_FCMPDri: { // fcmp dn, #imm + results[0] = floatHelp::fcmp(operands, true); break; } - case Opcode::AArch64_CMEQv16i8rz: { // cmeq vd.16b, vn.16b, #0 - results[0] = neonHelp::vecCompare( - operands, true, - [](uint8_t x, uint8_t y) -> bool { return (x == y); }); + case Opcode::AArch64_FCMPDrr: { // fcmp dn, dm + results[0] = floatHelp::fcmp(operands, false); break; } - case Opcode::AArch64_CMEQv1i64: { - return executionNYI(); + case Opcode::AArch64_FCMPEDri: { // fcmpe dn, #imm + results[0] = floatHelp::fcmp(operands, true); break; } - case Opcode::AArch64_CMEQv1i64rz: { - return executionNYI(); + case Opcode::AArch64_FCMPEDrr: { // fcmpe dn, dm + results[0] = floatHelp::fcmp(operands, false); break; } - case Opcode::AArch64_CMEQv2i32: { - return executionNYI(); + case Opcode::AArch64_FCMPESri: { // fcmpe sn, #imm + results[0] = floatHelp::fcmp(operands, true); break; } - case Opcode::AArch64_CMEQv2i32rz: { - return executionNYI(); + case Opcode::AArch64_FCMPESrr: { // fcmpe sn, sm + results[0] = floatHelp::fcmp(operands, false); break; } - case Opcode::AArch64_CMEQv2i64: { - return executionNYI(); + case Opcode::AArch64_FCMPSri: { // fcmp sn, #imm + results[0] = floatHelp::fcmp(operands, true); break; } - case Opcode::AArch64_CMEQv2i64rz: { - return executionNYI(); + case Opcode::AArch64_FCMPSrr: { // fcmp sn, sm + results[0] = floatHelp::fcmp(operands, false); break; } - case Opcode::AArch64_CMEQv4i16: { - return executionNYI(); + case Opcode::AArch64_FCPY_ZPmI_D: { // fcpy zd.d, pg/m, #const + results[0] = sveHelp::sveFcpy_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMEQv4i16rz: { - return executionNYI(); + case Opcode::AArch64_FCPY_ZPmI_S: { // fcpy zd.s, pg/m, #const + results[0] = sveHelp::sveFcpy_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMEQv4i32: { // cmeq vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecCompare( - operands, false, - [](uint32_t x, uint32_t y) -> bool { return (x == y); }); + case Opcode::AArch64_FCSELDrrr: { // fcsel dd, dn, dm, cond + results[0] = { + conditionalHelp::cs_4ops( + operands, metadata, [](double x) -> double { return x; }), + 256}; break; } - case Opcode::AArch64_CMEQv4i32rz: { - return executionNYI(); + case Opcode::AArch64_FCSELSrrr: { // fcsel sd, sn, sm, cond + results[0] = { + conditionalHelp::cs_4ops(operands, metadata, + [](float x) -> float { return x; }), + 256}; break; } - case Opcode::AArch64_CMEQv8i16: { - return executionNYI(); + case Opcode::AArch64_FCVTASUWDr: { // fcvtas wd, dn + results[0] = {static_cast(round(operands[0].get())), + 8}; break; } - case Opcode::AArch64_CMEQv8i16rz: { - return executionNYI(); + case Opcode::AArch64_FCVTASUXDr: { // fcvtas xd, dn + results[0] = static_cast(round(operands[0].get())); break; } - case Opcode::AArch64_CMEQv8i8: { - return executionNYI(); + case Opcode::AArch64_FCVTDSr: { // fcvt dd, sn + // TODO: Handle NaNs, denorms, and saturation? + results[0] = neonHelp::vecFcvtl(operands, false); break; } - case Opcode::AArch64_CMEQv8i8rz: { - return executionNYI(); + case Opcode::AArch64_FCVTLv2i32: { // fcvtl vd.2d, vn.2s + results[0] = neonHelp::vecFcvtl(operands, false); break; } - case Opcode::AArch64_CMGEv16i8: { - return executionNYI(); + case Opcode::AArch64_FCVTLv4i32: { // fcvtl2 vd.2d, vn.4s + results[0] = neonHelp::vecFcvtl(operands, true); break; } - case Opcode::AArch64_CMGEv16i8rz: { - return executionNYI(); + case Opcode::AArch64_FCVTNv2i32: { // fcvtn vd.2s, vn.2d + results[0] = neonHelp::vecFcvtn(operands, false); break; } - case Opcode::AArch64_CMGEv1i64: { - return executionNYI(); + case Opcode::AArch64_FCVTNv4i32: { // fcvtn2 vd.4s, vn.2d + results[0] = neonHelp::vecFcvtn(operands, true); break; } - case Opcode::AArch64_CMGEv1i64rz: { - return executionNYI(); + case Opcode::AArch64_FCVTSDr: { // fcvt sd, dn + // TODO: Handle NaNs, denorms, and saturation? + results[0] = neonHelp::vecFcvtl(operands, false); break; } - case Opcode::AArch64_CMGEv2i32: { - return executionNYI(); + case Opcode::AArch64_FCVTZSUWDr: { // fcvtzs wd, dn + // TODO: Handle NaNs, denorms, and saturation + results[0] = { + static_cast(std::trunc(operands[0].get())), 8}; break; } - case Opcode::AArch64_CMGEv2i32rz: { - return executionNYI(); + case Opcode::AArch64_FCVTZSUWSr: { // fcvtzs wd, sn + // TODO: Handle NaNs, denorms, and saturation + results[0] = { + static_cast(std::trunc(operands[0].get())), 8}; break; } - case Opcode::AArch64_CMGEv2i64: { - return executionNYI(); + case Opcode::AArch64_FCVTZSUXDr: { + // TODO: Handle NaNs, denorms, and saturation + results[0] = { + static_cast(std::trunc(operands[0].get())), 8}; break; } - case Opcode::AArch64_CMGEv2i64rz: { - return executionNYI(); + case Opcode::AArch64_FCVTZS_ZPmZ_DtoD: { // fcvtzs zd.d, pg/m, zn.d + results[0] = + sveHelp::sveFcvtzsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMGEv4i16: { - return executionNYI(); + case Opcode::AArch64_FCVTZS_ZPmZ_DtoS: { // fcvtzs zd.s, pg/m, zn.d + results[0] = + sveHelp::sveFcvtzsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMGEv4i16rz: { - return executionNYI(); + case Opcode::AArch64_FCVTZS_ZPmZ_StoD: { // fcvtzs zd.d, pg/m, zn.s + results[0] = + sveHelp::sveFcvtzsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMGEv4i32: { - return executionNYI(); + case Opcode::AArch64_FCVTZS_ZPmZ_StoS: { // fcvtzs zd.s, pg/m, zn.s + results[0] = + sveHelp::sveFcvtzsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMGEv4i32rz: { - return executionNYI(); + case Opcode::AArch64_FCVTZSv2f64: { // fcvtzs vd.2d, vn.2d + results[0] = neonHelp::vecFcvtzs(operands); break; } - case Opcode::AArch64_CMGEv8i16: { - return executionNYI(); + case Opcode::AArch64_FCVTZUUWDr: { // fcvtzu wd, dn + // TODO: Handle NaNs, denorms, and saturation + results[0] = { + static_cast(std::trunc(operands[0].get())), 8}; break; } - case Opcode::AArch64_CMGEv8i16rz: { - return executionNYI(); + case Opcode::AArch64_FCVTZUUWSr: { // fcvtzu wd, sn + // TODO: Handle NaNs, denorms, and saturation + results[0] = { + static_cast(std::trunc(operands[0].get())), 8}; break; } - case Opcode::AArch64_CMGEv8i8: { - return executionNYI(); + case Opcode::AArch64_FCVTZUUXDr: { // fcvtzu xd, dn + // TODO: Handle NaNs, denorms, and saturation + results[0] = + static_cast(std::trunc(operands[0].get())); break; } - case Opcode::AArch64_CMGEv8i8rz: { - return executionNYI(); + case Opcode::AArch64_FCVTZUUXSr: { // fcvtzu xd, sn + // TODO: Handle NaNs, denorms, and saturation + results[0] = static_cast(std::trunc(operands[0].get())); break; } - case Opcode::AArch64_CMGTv16i8: { - return executionNYI(); + case Opcode::AArch64_FCVT_ZPmZ_DtoS: { // fcvt zd.s, pg/m, zn.d + results[0] = + sveHelp::sveFcvtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMGTv16i8rz: { - return executionNYI(); + case Opcode::AArch64_FCVT_ZPmZ_StoD: { // fcvt zd.d, pg/m, zn.s + results[0] = + sveHelp::sveFcvtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMGTv1i64: { - return executionNYI(); + case Opcode::AArch64_FDIVDrr: { // fdiv dd, dn, dm + results[0] = {divideHelp::div_3ops(operands), 256}; break; } - case Opcode::AArch64_CMGTv1i64rz: { - return executionNYI(); + case Opcode::AArch64_FDIVR_ZPmZ_D: { // fdivr zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](double x, double y) -> double { return (y / x); }); break; } - case Opcode::AArch64_CMGTv2i32: { - return executionNYI(); + case Opcode::AArch64_FDIVR_ZPmZ_S: { // fdivr zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](float x, float y) -> float { return (y / x); }); break; } - case Opcode::AArch64_CMGTv2i32rz: { - return executionNYI(); + case Opcode::AArch64_FDIVSrr: { // fdiv sd, sn, sm + results[0] = {divideHelp::div_3ops(operands), 256}; break; } - case Opcode::AArch64_CMGTv2i64: { - return executionNYI(); + case Opcode::AArch64_FDIV_ZPmZ_D: { // fdiv zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](double x, double y) -> double { return (x / y); }); break; } - case Opcode::AArch64_CMGTv2i64rz: { - return executionNYI(); + case Opcode::AArch64_FDIVv2f64: { // fdiv vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](double x, double y) -> double { return x / y; }); break; } - case Opcode::AArch64_CMGTv4i16: { - return executionNYI(); + case Opcode::AArch64_FDUP_ZI_D: { // fdup zd.d, #imm + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_CMGTv4i16rz: { - return executionNYI(); + case Opcode::AArch64_FDUP_ZI_S: { // fdup zd.s, #imm + results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_CMGTv4i32: { - return executionNYI(); + case Opcode::AArch64_FMADDDrrr: { // fmadd dn, dm, da + results[0] = {multiplyHelp::madd_4ops(operands), 256}; break; } - case Opcode::AArch64_CMGTv4i32rz: { - return executionNYI(); + case Opcode::AArch64_FMADDSrrr: { // fmadd sn, sm, sa + results[0] = {multiplyHelp::madd_4ops(operands), 256}; break; } - case Opcode::AArch64_CMGTv8i16: { - return executionNYI(); + case Opcode::AArch64_FMAD_ZPmZZ_D: { // fmad zd.d, pg/m, zn.d, zm.d + results[0] = sveHelp::sveFmadPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMGTv8i16rz: { - return executionNYI(); + case Opcode::AArch64_FMAD_ZPmZZ_S: { // fmad zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveFmadPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMGTv8i8: { - return executionNYI(); + case Opcode::AArch64_FMAXNMDrr: { // fmaxnm dd, dn, dm + results[0] = floatHelp::fmaxnm_3ops(operands); break; } - case Opcode::AArch64_CMGTv8i8rz: { - return executionNYI(); + case Opcode::AArch64_FMAXNMPv2i64p: { // fmaxnmp dd, vd.2d + results[0] = neonHelp::vecMaxnmp_2ops(operands); break; } - case Opcode::AArch64_CMHIv16i8: { - return executionNYI(); + case Opcode::AArch64_FMAXNMSrr: { // fmaxnm sd, sn, sm + results[0] = floatHelp::fmaxnm_3ops(operands); break; } - case Opcode::AArch64_CMHIv1i64: { - return executionNYI(); + case Opcode::AArch64_FMAXNMv2f64: { // fmaxnm vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecLogicOp_3vecs( + operands, + [](double x, double y) -> double { return std::fmax(x, y); }); break; } - case Opcode::AArch64_CMHIv2i32: { - return executionNYI(); + case Opcode::AArch64_FMINNMDrr: { // fminnm dd, dn, dm + results[0] = floatHelp::fminnm_3ops(operands); break; } - case Opcode::AArch64_CMHIv2i64: { - return executionNYI(); + case Opcode::AArch64_FMINNMPv2i64p: { // fminnmp dd, vd.2d + results[0] = neonHelp::vecMinv_2ops(operands); break; } - case Opcode::AArch64_CMHIv4i16: { - return executionNYI(); + case Opcode::AArch64_FMINNMSrr: { // fminnm sd, sn, sm + results[0] = floatHelp::fminnm_3ops(operands); break; } - case Opcode::AArch64_CMHIv4i32: { // cmhi vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecCompare( - operands, false, - [](uint32_t x, uint32_t y) -> bool { return (x > y); }); + case Opcode::AArch64_FMINNMv2f64: { // fminnm vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecLogicOp_3vecs( + operands, + [](double x, double y) -> double { return std::fmin(x, y); }); break; } - case Opcode::AArch64_CMHIv8i16: { - return executionNYI(); + case Opcode::AArch64_FMLA_ZPmZZ_D: { // fmla zd.d, pg/m, zn.d, zm.d + results[0] = sveHelp::sveMlaPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMHIv8i8: { - return executionNYI(); + case Opcode::AArch64_FMLA_ZPmZZ_S: { // fmla zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveMlaPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMHSv16i8: { - return executionNYI(); + case Opcode::AArch64_FMLAv2f32: { // fmla vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecFmla_3vecs(operands); break; } - case Opcode::AArch64_CMHSv1i64: { - return executionNYI(); + case Opcode::AArch64_FMLAv2f64: { // fmla vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecFmla_3vecs(operands); break; } - case Opcode::AArch64_CMHSv2i32: { - return executionNYI(); + case Opcode::AArch64_FMLAv2i32_indexed: { // fmla vd.2s, vn.2s, + // vm.2s[index] + results[0] = + neonHelp::vecFmlaIndexed_3vecs(operands, metadata); break; } - case Opcode::AArch64_CMHSv2i64: { - return executionNYI(); + case Opcode::AArch64_FMLAv2i64_indexed: { // fmla vd.2d, vn.2d, + // vm.d[index] + results[0] = + neonHelp::vecFmlaIndexed_3vecs(operands, metadata); break; } - case Opcode::AArch64_CMHSv4i16: { - return executionNYI(); + case Opcode::AArch64_FMLAv4f32: { // fmla vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecFmla_3vecs(operands); break; } - case Opcode::AArch64_CMHSv4i32: { - return executionNYI(); + case Opcode::AArch64_FMLAv4i32_indexed: { // fmla vd.4s, vn.4s, + // vm.s[index] + results[0] = + neonHelp::vecFmlaIndexed_3vecs(operands, metadata); break; } - case Opcode::AArch64_CMHSv8i16: { - return executionNYI(); + case Opcode::AArch64_FMLS_ZPmZZ_D: { // fmls zd.d, pg/m, zn.d, zm.d + results[0] = sveHelp::sveFmlsPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMHSv8i8: { - return executionNYI(); + case Opcode::AArch64_FMLS_ZPmZZ_S: { // fmls zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveFmlsPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMLEv16i8rz: { - return executionNYI(); + case Opcode::AArch64_FMLSv2f64: { // fmls vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecFmls_3vecs(operands); break; } - case Opcode::AArch64_CMLEv1i64rz: { - return executionNYI(); + case Opcode::AArch64_FMLSv2i64_indexed: { + results[0] = + neonHelp::vecFmlsIndexed_3vecs(operands, metadata); break; } - case Opcode::AArch64_CMLEv2i32rz: { - return executionNYI(); + case Opcode::AArch64_FMLSv4f32: { // fmls vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecFmls_3vecs(operands); break; } - case Opcode::AArch64_CMLEv2i64rz: { - return executionNYI(); + case Opcode::AArch64_FMLSv4i32_indexed: { // fmls vd.4s, vn.4s, + // vm.s[index] + results[0] = + neonHelp::vecFmlsIndexed_3vecs(operands, metadata); break; } - case Opcode::AArch64_CMLEv4i16rz: { - return executionNYI(); + case Opcode::AArch64_FMOVDXHighr: { // fmov xd, vn.d[1] + results[0] = operands[0].getAsVector()[1]; break; } - case Opcode::AArch64_CMLEv4i32rz: { - return executionNYI(); + case Opcode::AArch64_FMOVDXr: { // fmov xd, dn + results[0] = operands[0].get(); break; } - case Opcode::AArch64_CMLEv8i16rz: { - return executionNYI(); + case Opcode::AArch64_FMOVDi: { // fmov dn, #imm + results[0] = {metadata.operands[1].fp, 256}; break; } - case Opcode::AArch64_CMLEv8i8rz: { - return executionNYI(); + case Opcode::AArch64_FMOVDr: { // fmov dd, dn + results[0] = {operands[0].get(), 256}; break; } - case Opcode::AArch64_CMLTv16i8rz: { - return executionNYI(); + case Opcode::AArch64_FMOVSWr: { // fmov wd, sn + results[0] = {operands[0].get(), 8}; break; } - case Opcode::AArch64_CMLTv1i64rz: { - return executionNYI(); + case Opcode::AArch64_FMOVSi: { // fmov sn, #imm + results[0] = {static_cast(metadata.operands[1].fp), 256}; break; } - case Opcode::AArch64_CMLTv2i32rz: { - return executionNYI(); + case Opcode::AArch64_FMOVSr: { // fmov sd, sn + results[0] = {operands[0].get(), 256}; break; } - case Opcode::AArch64_CMLTv2i64rz: { - return executionNYI(); + case Opcode::AArch64_FMOVWSr: { // fmov sd, wn + results[0] = {operands[0].get(), 256}; break; } - case Opcode::AArch64_CMLTv4i16rz: { - return executionNYI(); + case Opcode::AArch64_FMOVXDHighr: { // fmov vd.d[1], xn + double out[2] = {operands[0].get(), operands[1].get()}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_CMLTv4i32rz: { - return executionNYI(); + case Opcode::AArch64_FMOVXDr: { // fmov dd, xn + results[0] = {operands[0].get(), 256}; break; } - case Opcode::AArch64_CMLTv8i16rz: { - return executionNYI(); + case Opcode::AArch64_FMOVv2f32_ns: { // fmov vd.2s, #imm + results[0] = neonHelp::vecMovi_imm(metadata); break; } - case Opcode::AArch64_CMLTv8i8rz: { - return executionNYI(); + case Opcode::AArch64_FMOVv2f64_ns: { // fmov vd.2d, #imm + results[0] = neonHelp::vecMovi_imm(metadata); break; } - case Opcode::AArch64_CMPEQ_PPzZI_B: { // cmpeq pd.b, pg/z, zn.b, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](uint8_t x, uint8_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMOVv4f32_ns: { // fmov vd.4s, #imm + results[0] = neonHelp::vecMovi_imm(metadata); break; } - case Opcode::AArch64_CMPEQ_PPzZI_D: { // cmpeq pd.d, pg/z, zn.d, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](uint64_t x, uint64_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMSB_ZPmZZ_D: { // fmsb zd.d, pg/m, zn.d, zm.d + results[0] = sveHelp::sveFmsbPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPEQ_PPzZI_H: { // cmpeq pd.h, pg/z, zn.h, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](uint16_t x, uint16_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMSB_ZPmZZ_S: { // fmsb zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveFmsbPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPEQ_PPzZI_S: { // cmpeq pd.s, pg/z, zn.s, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](uint32_t x, uint32_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMSUBDrrr: { // fmsub dn, dm, da + results[0] = {multiplyHelp::msub_4ops(operands), 256}; break; } - case Opcode::AArch64_CMPEQ_PPzZZ_B: { // cmpeq pd.b, pg/z, zn.b, zm.b - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint8_t x, uint8_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMSUBSrrr: { // fmsub sn, sm, sa + results[0] = {multiplyHelp::msub_4ops(operands), 256}; break; } - case Opcode::AArch64_CMPEQ_PPzZZ_D: { // cmpeq pd.d, pg/z, zn.d, zm.d - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint64_t x, uint64_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMULDrr: { // fmul dd, dn, dm + results[0] = {multiplyHelp::mul_3ops(operands), 256}; break; } - case Opcode::AArch64_CMPEQ_PPzZZ_H: { // cmpeq pd.h, pg/z, zn.h, zm.h - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint16_t x, uint16_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMULSrr: { // fmul sd, sn, sm + results[0] = {multiplyHelp::mul_3ops(operands), 256}; break; } - case Opcode::AArch64_CMPEQ_PPzZZ_S: { // cmpeq pd.s, pg/z, zn.s, zm.s - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint32_t x, uint32_t y) -> bool { return x == y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FMUL_ZPmI_D: { // fmul zd.d, pg/m, zn.d, #imm + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, true); break; } - case Opcode::AArch64_CMPEQ_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FMUL_ZPmI_S: { // fmul zd.s, pg/m, zn.s, #imm + results[0] = + sveHelp::sveMulPredicated(operands, metadata, VL_bits, true); break; } - case Opcode::AArch64_CMPEQ_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FMUL_ZPmZ_D: { // fmul zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_CMPEQ_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FMUL_ZPmZ_S: { // fmul zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_CMPGE_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_FMUL_ZZZ_D: { // fmul zd.d, zn.d, zm.d + results[0] = sveHelp::sveFmul_3ops(operands, VL_bits); break; } - case Opcode::AArch64_CMPGE_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_FMUL_ZZZ_S: { // fmul zd.s, zn.s, zm.s + results[0] = sveHelp::sveFmul_3ops(operands, VL_bits); break; } - case Opcode::AArch64_CMPGE_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_FMULv1i32_indexed: { // fmul sd, sn, vm.s[index] + results[0] = + neonHelp::vecFmulIndexed_vecs(operands, metadata); break; } - case Opcode::AArch64_CMPGE_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_FMULv1i64_indexed: { // fmul dd, dn, vm.d[index] + results[0] = + neonHelp::vecFmulIndexed_vecs(operands, metadata); break; } - case Opcode::AArch64_CMPGE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FMULv2f32: { // fmul vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](float x, float y) -> float { return x * y; }); break; } - case Opcode::AArch64_CMPGE_PPzZZ_D: { - return executionNYI(); + case Opcode::AArch64_FMULv2f64: { // fmul vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](double x, double y) -> double { return x * y; }); break; } - case Opcode::AArch64_CMPGE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FMULv2i32_indexed: { // fmul vd.2s, vn.2s, + // vm.s[index] + results[0] = + neonHelp::vecFmulIndexed_vecs(operands, metadata); break; } - case Opcode::AArch64_CMPGE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FMULv2i64_indexed: { // fmul vd.2d, vn.2d, + // vm.d[index] + results[0] = + neonHelp::vecFmulIndexed_vecs(operands, metadata); break; } - case Opcode::AArch64_CMPGE_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FMULv4f32: { // fmul vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](float x, float y) -> float { return x * y; }); break; } - case Opcode::AArch64_CMPGE_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FMULv4i32_indexed: { // fmul vd.4s, vn.4s, + // vm.s[index] + results[0] = + neonHelp::vecFmulIndexed_vecs(operands, metadata); break; } - case Opcode::AArch64_CMPGE_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FNEGDr: { // fneg dd, dn + results[0] = {-operands[0].get(), 256}; break; } - case Opcode::AArch64_CMPGT_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_FNEGSr: { // fneg sd, sn + results[0] = {-operands[0].get(), 256}; break; } - case Opcode::AArch64_CMPGT_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_FNEG_ZPmZ_D: { // fneg zd.d, pg/m, zn.d + results[0] = sveHelp::sveFnegPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPGT_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_FNEG_ZPmZ_S: { // fneg zd.s, pg/m, zn.s + results[0] = sveHelp::sveFnegPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPGT_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_FNEGv2f64: { // fneg vd.2d, vn.2d + results[0] = neonHelp::vecFneg_2ops(operands); break; } - case Opcode::AArch64_CMPGT_PPzZZ_B: { // cmpgt pd.b, pg/z, zn.b, zm.b - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int8_t x, int8_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FNEGv4f32: { // fneg vd.4s, vn.4s + results[0] = neonHelp::vecFneg_2ops(operands); break; } - case Opcode::AArch64_CMPGT_PPzZZ_D: { // cmpgt pd.d, pg/z, zn.d, zm.d - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int64_t x, int64_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FNMADDDrrr: { // fnmadd dd, dn, dm, da + results[0] = floatHelp::fnmadd_4ops(operands); break; } - case Opcode::AArch64_CMPGT_PPzZZ_H: { // cmpgt pd.h, pg/z, zn.h, zm.h - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int16_t x, int16_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FNMADDSrrr: { // fnmadd sd, sn, sm, sa + results[0] = floatHelp::fnmadd_4ops(operands); break; } - case Opcode::AArch64_CMPGT_PPzZZ_S: { // cmpgt pd.s, pg/z, zn.s, zm.s - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int32_t x, int32_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FNMLS_ZPmZZ_D: { // fnmls zd.d, pg/m, zn.d, zm.d + results[0] = sveHelp::sveFnmlsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPGT_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FNMLS_ZPmZZ_S: { // fnmls zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveFnmlsPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPGT_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FNMSB_ZPmZZ_D: { // fnmsb zdn.d, pg/m, zm.d, za.d + results[0] = sveHelp::sveFnmsbPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPGT_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FNMSB_ZPmZZ_S: { // fnmsb zdn.s, pg/m, zm.s, za.s + results[0] = sveHelp::sveFnmsbPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPHI_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_FNMSUBDrrr: { // fnmsub dd, dn, dm, da + results[0] = floatHelp::fnmsub_4ops(operands); break; } - case Opcode::AArch64_CMPHI_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_FNMSUBSrrr: { // fnmsub sd, sn, sm, sa + results[0] = floatHelp::fnmsub_4ops(operands); break; } - case Opcode::AArch64_CMPHI_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_FNMULDrr: { // fnmul dd, dn, dm + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](double x, double y) -> double { return -(x * y); }); break; } - case Opcode::AArch64_CMPHI_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_FNMULSrr: { // fnmul sd, sn, sm + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](float x, float y) -> float { return -(x * y); }); break; } - case Opcode::AArch64_CMPHI_PPzZZ_B: { // cmphi pd.b, pg/z, zn.b, zm.b - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint8_t x, uint8_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FRINTADr: { // frinta dd, dn + results[0] = {round(operands[0].get()), 256}; break; } - case Opcode::AArch64_CMPHI_PPzZZ_D: { // cmphi pd.d, pg/z, zn.d, zm.d - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint64_t x, uint64_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FRINTN_ZPmZ_D: { // frintn zd.d, pg/m, zn.d + results[0] = + sveHelp::sveFrintnPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPHI_PPzZZ_H: { // cmphi pd.h, pg/z, zn.h, zm.h - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint16_t x, uint16_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FRINTN_ZPmZ_S: { // frintn zd.s, pg/m, zn.s + results[0] = + sveHelp::sveFrintnPredicated(operands, VL_bits); break; } - case Opcode::AArch64_CMPHI_PPzZZ_S: { // cmphi pd.s, pg/z, zn.s, zm.s - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](uint32_t x, uint32_t y) -> bool { return x > y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_FRSQRTEv1i32: { // frsqrte sd, sn + results[0] = neonHelp::vecFrsqrte_2ops(operands); break; } - case Opcode::AArch64_CMPHI_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FRSQRTEv1i64: { // frsqrte dd, dn + results[0] = neonHelp::vecFrsqrte_2ops(operands); break; } - case Opcode::AArch64_CMPHI_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FRSQRTEv2f32: { // frsqrte vd.2s, vn.2s + results[0] = neonHelp::vecFrsqrte_2ops(operands); break; } - case Opcode::AArch64_CMPHI_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FRSQRTEv2f64: { // frsqrte vd.2d, vn.2d + results[0] = neonHelp::vecFrsqrte_2ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_FRSQRTEv4f32: { // frsqrte vd.4s, vn.4s + results[0] = neonHelp::vecFrsqrte_2ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_FRSQRTS32: { // frsqrts sd, sn, sm + results[0] = neonHelp::vecFrsqrts_3ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_FRSQRTS64: { // frsqrts dd, dn, dm + results[0] = neonHelp::vecFrsqrts_3ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_FRSQRTSv2f32: { // frsqrts vd.2s, vn.2s, vn.2s + results[0] = neonHelp::vecFrsqrts_3ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FRSQRTSv2f64: { // frsqrts vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecFrsqrts_3ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZZ_D: { - return executionNYI(); + case Opcode::AArch64_FRSQRTSv4f32: { // frsqrts vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecFrsqrts_3ops(operands); break; } - case Opcode::AArch64_CMPHS_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FSQRTDr: { // fsqrt dd, dn + results[0] = {::sqrt(operands[0].get()), 256}; break; } - case Opcode::AArch64_CMPHS_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FSQRTSr: { // fsqrt sd, sn + results[0] = {::sqrtf(operands[0].get()), 256}; break; } - case Opcode::AArch64_CMPHS_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FSQRT_ZPmZ_D: { // fsqrt zd.d, pg/m, zn.d + results[0] = + sveHelp::sveFsqrtPredicated_2vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPHS_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FSQRT_ZPmZ_S: { // fsqrt zd.s, pg/m, zn.s + results[0] = + sveHelp::sveFsqrtPredicated_2vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPHS_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FSQRTv2f64: { // fsqrt vd.2d, vn.2d + results[0] = neonHelp::vecFsqrt_2ops(operands); break; } - case Opcode::AArch64_CMPLE_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_FSQRTv4f32: { // fsqrt vd.4s, vn.4s + results[0] = neonHelp::vecFsqrt_2ops(operands); break; } - case Opcode::AArch64_CMPLE_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_FSUBDrr: { // fsub dd, dn, dm + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](double x, double y) -> double { return x - y; }); break; } - case Opcode::AArch64_CMPLE_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_FSUBR_ZPmZ_D: { // fsubr zdn.d, pg/m, zdn.d, zm.d + results[0] = + sveHelp::sveSubrPredicated_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPLE_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_FSUBR_ZPmZ_S: { // fsubr zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveSubrPredicated_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPLE_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FSUBSrr: { // fsub ss, sn, sm + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](double x, double y) -> double { return x - y; }); break; } - case Opcode::AArch64_CMPLE_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FSUB_ZPmI_D: { // fsub zdn.d, pg/m, zdn.d, #imm + results[0] = + sveHelp::sveSubPredicated_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLE_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FSUB_ZPmI_S: { // fsub zdn.s, pg/m, zdn.s, #imm + results[0] = + sveHelp::sveSubPredicated_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLO_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_FSUB_ZPmZ_D: { // fsub zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](double x, double y) -> double { return x - y; }); break; } - case Opcode::AArch64_CMPLO_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_FSUB_ZPmZ_S: { // fsub zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, [](float x, float y) -> float { return x - y; }); break; } - case Opcode::AArch64_CMPLO_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_FSUB_ZZZ_D: { // fsub zd.d, zn.d, zm.d + results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPLO_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_FSUB_ZZZ_S: { // fsub zd.s, zn.s, zm.s + results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_CMPLO_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_FSUBv2f32: { + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](float x, float y) -> float { return x - y; }); break; } - case Opcode::AArch64_CMPLO_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_FSUBv2f64: { // fsub vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](double x, double y) -> double { return x - y; }); break; } - case Opcode::AArch64_CMPLO_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_FSUBv4f32: { // fsub vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](float x, float y) -> float { return x - y; }); break; } - case Opcode::AArch64_CMPLS_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_GLD1D_IMM_REAL: { // ld1d {zd.d}, pg/z, [zn.d{, + // #imm}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint64_t out[32] = {0}; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_CMPLS_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_GLD1D_REAL: // ld1d {zt.d}, pg/z, [xn, zm.d] + // LOAD + [[fallthrough]]; + case Opcode::AArch64_GLD1D_SCALED_REAL: { // ld1d {zt.d}, pg/z, [xn, + // zm.d, LSL #3] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + uint64_t out[32] = {0}; + + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } + } + + results[0] = {out, 256}; break; } - case Opcode::AArch64_CMPLS_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_GLD1SW_D_IMM_REAL: { // ld1sw {zd.d}, pg/z, [zn.d{, + // #imm}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + int64_t out[32] = {0}; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out[i] = static_cast(memoryData[index].get()); + index++; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_CMPLS_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_HINT: { // nop|yield|wfe|wfi|etc... + // TODO: Observe hints break; } - case Opcode::AArch64_CMPLS_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_INCB_XPiI: { // incb xdn{, pattern{, #imm}} + results[0] = + sveHelp::sveInc_gprImm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLS_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_INCD_XPiI: { // incd xdn{, pattern{, #imm}} + results[0] = + sveHelp::sveInc_gprImm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLS_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_INCD_ZPiI: { // incd zdn.d{, pattern{, #imm}} + results[0] = sveHelp::sveInc_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLT_PPzZI_B: { - return executionNYI(); + case Opcode::AArch64_INCH_XPiI: { // inch xdn{, pattern{, #imm}} + results[0] = + sveHelp::sveInc_gprImm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLT_PPzZI_D: { - return executionNYI(); + case Opcode::AArch64_INCH_ZPiI: { // inch zdn.h{, pattern{, #imm}} + results[0] = sveHelp::sveInc_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPLT_PPzZI_H: { - return executionNYI(); + case Opcode::AArch64_INCP_XP_B: { // incp xdn, pm.b + results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); break; } - case Opcode::AArch64_CMPLT_PPzZI_S: { - return executionNYI(); + case Opcode::AArch64_INCP_XP_D: { // incp xdn, pm.d + results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); break; } - case Opcode::AArch64_CMPLT_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_INCP_XP_H: { // incp xdn, pm.h + results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); break; } - case Opcode::AArch64_CMPLT_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_INCP_XP_S: { // incp xdn, pm.s + results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); break; } - case Opcode::AArch64_CMPLT_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_INCW_XPiI: { // incw xdn{, pattern{, #imm}} + results[0] = + sveHelp::sveInc_gprImm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPNE_PPzZI_B: { // cmpne pd.b, pg/z. zn.b, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](int8_t x, int8_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; - break; - } - case Opcode::AArch64_CMPNE_PPzZI_D: { // cmpne pd.d, pg/z. zn.d, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](int64_t x, int64_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; - break; - } - case Opcode::AArch64_CMPNE_PPzZI_H: { // cmpne pd.h, pg/z. zn.h, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](int16_t x, int16_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; - break; - } - case Opcode::AArch64_CMPNE_PPzZI_S: { // cmpne pd.s, pg/z. zn.s, #imm - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, true, - [](int32_t x, int32_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; - break; - } - case Opcode::AArch64_CMPNE_PPzZZ_B: { // cmpne pd.b, pg/z, zn.b, zm.b - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int8_t x, int8_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; - break; - } - case Opcode::AArch64_CMPNE_PPzZZ_D: { // cmpne pd.d, pg/z, zn.d, zm.d - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int64_t x, int64_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_INCW_ZPiI: { // incw zdn.s{, pattern{, #imm}} + results[0] = sveHelp::sveInc_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_CMPNE_PPzZZ_H: { // cmpne pd.h, pg/z, zn.h, zm.h - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int16_t x, int16_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_INDEX_II_B: { // index zd.b, #imm, #imm + results[0] = + sveHelp::sveIndex(operands, metadata, VL_bits, true, true); break; } - case Opcode::AArch64_CMPNE_PPzZZ_S: { // cmpne pd.s, pg/z, zn.s, zm.s - auto [output, nzcv] = sveHelp::sveCmpPredicated_toPred( - operands, metadata, VL_bits, false, - [](int32_t x, int32_t y) -> bool { return x != y; }); - results[0] = nzcv; - results[1] = output; + case Opcode::AArch64_INDEX_II_D: { // index zd.d, #imm, #imm + results[0] = + sveHelp::sveIndex(operands, metadata, VL_bits, true, true); break; } - case Opcode::AArch64_CMPNE_WIDE_PPzZZ_B: { - return executionNYI(); + case Opcode::AArch64_INDEX_II_H: { // index zd.h, #imm, #imm + results[0] = + sveHelp::sveIndex(operands, metadata, VL_bits, true, true); break; } - case Opcode::AArch64_CMPNE_WIDE_PPzZZ_H: { - return executionNYI(); + case Opcode::AArch64_INDEX_II_S: { // index zd.s, #imm, #imm + results[0] = + sveHelp::sveIndex(operands, metadata, VL_bits, true, true); break; } - case Opcode::AArch64_CMPNE_WIDE_PPzZZ_S: { - return executionNYI(); + case Opcode::AArch64_INDEX_IR_B: { // index zd.b, #imm, wn + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, true, false); break; } - case Opcode::AArch64_CMP_SWAP_128: { - return executionNYI(); + case Opcode::AArch64_INDEX_IR_D: { // index zd.d, #imm, xn + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, true, false); break; } - case Opcode::AArch64_CMP_SWAP_16: { - return executionNYI(); + case Opcode::AArch64_INDEX_IR_H: { // index zd.h, #imm, wn + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, true, false); break; } - case Opcode::AArch64_CMP_SWAP_32: { - return executionNYI(); + case Opcode::AArch64_INDEX_IR_S: { // index zd.s, #imm, wn + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, true, false); break; } - case Opcode::AArch64_CMP_SWAP_64: { - return executionNYI(); + case Opcode::AArch64_INDEX_RI_B: { // index zd.b, wn, #imm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, true); break; } - case Opcode::AArch64_CMP_SWAP_8: { - return executionNYI(); + case Opcode::AArch64_INDEX_RI_D: { // index zd.d, xn, #imm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, true); break; } - case Opcode::AArch64_CMTSTv16i8: { - return executionNYI(); + case Opcode::AArch64_INDEX_RI_H: { // index zd.h, wn, #imm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, true); break; } - case Opcode::AArch64_CMTSTv1i64: { - return executionNYI(); + case Opcode::AArch64_INDEX_RI_S: { // index zd.s, wn, #imm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, true); break; } - case Opcode::AArch64_CMTSTv2i32: { - return executionNYI(); + case Opcode::AArch64_INDEX_RR_B: { // index zd.b, wn, wm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, false); break; } - case Opcode::AArch64_CMTSTv2i64: { - return executionNYI(); + case Opcode::AArch64_INDEX_RR_D: { // index zd.d, xn, xm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, false); break; } - case Opcode::AArch64_CMTSTv4i16: { - return executionNYI(); + case Opcode::AArch64_INDEX_RR_H: { // index zd.h, wn, wm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, false); break; } - case Opcode::AArch64_CMTSTv4i32: { - return executionNYI(); + case Opcode::AArch64_INDEX_RR_S: { // index zd.s, wn, wm + results[0] = sveHelp::sveIndex(operands, metadata, + VL_bits, false, false); break; } - case Opcode::AArch64_CMTSTv8i16: { - return executionNYI(); + case Opcode::AArch64_INSvi16gpr: { // ins vd.h[index], wn + results[0] = neonHelp::vecInsIndex_gpr(operands, + metadata); break; } - case Opcode::AArch64_CMTSTv8i8: { - return executionNYI(); + case Opcode::AArch64_INSvi32gpr: { // ins vd.s[index], wn + results[0] = neonHelp::vecInsIndex_gpr(operands, + metadata); break; } - case Opcode::AArch64_CNOT_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_INSvi32lane: { // ins vd.s[index1], vn.s[index2] + results[0] = neonHelp::vecIns_2Index(operands, metadata); break; } - case Opcode::AArch64_CNOT_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_INSvi64gpr: { // ins vd.d[index], xn + results[0] = neonHelp::vecInsIndex_gpr(operands, + metadata); break; } - case Opcode::AArch64_CNOT_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_INSvi64lane: { // ins vd.d[index1], vn.d[index2] + results[0] = neonHelp::vecIns_2Index(operands, metadata); break; } - case Opcode::AArch64_CNOT_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_INSvi8gpr: { // ins vd.b[index], wn + results[0] = neonHelp::vecInsIndex_gpr(operands, + metadata); break; } - case Opcode::AArch64_CNTB_XPiI: { // cntb xd{, pattern{, #imm}} - results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); + case Opcode::AArch64_LD1B: { // ld1b {zt.b}, pg/z, [xn, xm] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 8; + uint16_t index = 0; + uint8_t out[256] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << (i % 64); + if (p[i / 64] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } else { + out[i] = 0; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_CNTD_XPiI: { // cntd xd{, pattern{, #imm}} - results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); + case Opcode::AArch64_LD1D: { // ld1d {zt.d}, pg/z, [xn, xm, lsl #3] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + uint64_t out[32] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } else { + out[i] = 0; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_CNTH_XPiI: { // cnth xd{, pattern{, #imm}} - results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); + case Opcode::AArch64_LD1D_IMM_REAL: { // ld1d {zt.d}, pg/z, [xn{, #imm, + // mul vl}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + uint64_t out[32] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } else { + out[i] = 0; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_CNTP_XPP_B: { // cntp xd, pg, pn.b - results[0] = sveHelp::sveCntp(operands, VL_bits); + case Opcode::AArch64_LD1H: { // ld1h {zt.h}, pg/z, [xn, xm, lsl #1] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 16; + uint16_t index = 0; + uint16_t out[128] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 32) * 2); + if (p[i / 32] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } else { + out[i] = 0; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_CNTP_XPP_D: { // cntp xd, pg, pn.d - results[0] = sveHelp::sveCntp(operands, VL_bits); + case Opcode::AArch64_LD1Onev16b: { // ld1 {vt.16b} [xn] + results[0] = memoryData[0].zeroExtend(memoryData[0].size(), 256); break; } - case Opcode::AArch64_CNTP_XPP_H: { // cntp xd, pg, pn.h - results[0] = sveHelp::sveCntp(operands, VL_bits); + case Opcode::AArch64_LD1Onev16b_POST: { // ld1 {vt.16b}, [xn], #imm + results[0] = memoryData[0].zeroExtend(memoryData[0].size(), 256); + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_CNTP_XPP_S: { // cntp xd, pg, pn.s - results[0] = sveHelp::sveCntp(operands, VL_bits); + case Opcode::AArch64_LD1RD_IMM: { // ld1rd {zt.d}, pg/z, [xn, #imm] + // LOAD + const uint16_t partition_num = VL_bits / 64; + uint64_t out[32] = {0}; + uint16_t index = 0; + // Check if any lanes are active, otherwise set all to 0 and break early + bool active = false; + const uint64_t* p = operands[0].getAsVector(); + for (int i = 0; i < 4; i++) { + if (p[i] != 0) { + active = true; + break; + } + } + + if (active) { + uint64_t data = memoryData[0].get(); + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = p[index / 8] & 1ull << ((index % 8) * 8); + out[i] = shifted_active ? data : 0; + index++; + } + } + + results[0] = {out, 256}; break; } - case Opcode::AArch64_CNTW_XPiI: { // cntw xd{, pattern{, #imm}} - results[0] = sveHelp::sveCnt_gpr(metadata, VL_bits); - break; - } - case Opcode::AArch64_CNT_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_CNT_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_CNT_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_CNT_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_CNTv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_CNTv8i8: { // cnt vd.8b, vn.8b - results[0] = neonHelp::vecCountPerByte(operands); - break; - } - case Opcode::AArch64_COMPACT_ZPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_COMPACT_ZPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmR_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmR_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmR_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmR_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmV_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmV_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmV_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPmV_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPY_ZPzI_B: { // cpy zd.b, pg/z, #imm{, shift} - results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_CPY_ZPzI_D: { // cpy zd.d, pg/z, #imm{, shift} - results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_CPY_ZPzI_H: { // cpy zd.h, pg/z, #imm{, shift} - results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_CPY_ZPzI_S: { // cpy zd.s, pg/z, #imm{, shift} - results[0] = sveHelp::sveCpy_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_CPYi16: { - return executionNYI(); - break; - } - case Opcode::AArch64_CPYi32: { - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, false); - break; - } - case Opcode::AArch64_CPYi64: { - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, false); - break; - } - case Opcode::AArch64_CPYi8: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32Brr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32CBrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32CHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32CWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32CXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32Hrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32Wrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CRC32Xrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_CSELWr: { // csel wd, wn, wm, cc - results[0] = { - conditionalHelp::cs_4ops( - operands, metadata, [](uint32_t x) -> uint32_t { return x; }), - 8}; - break; - } - case Opcode::AArch64_CSELXr: { // csel xd, xn, xm, cc - results[0] = conditionalHelp::cs_4ops( - operands, metadata, [](uint64_t x) -> uint64_t { return x; }); - break; - } - case Opcode::AArch64_CSINCWr: { // csinc wd, wn, wm, cc - results[0] = {conditionalHelp::cs_4ops( - operands, metadata, - [](uint32_t x) -> uint32_t { return x + 1; }), - 8}; - break; - } - case Opcode::AArch64_CSINCXr: { // csinc xd, xn, xm, cc - results[0] = conditionalHelp::cs_4ops( - operands, metadata, [](uint64_t x) -> uint64_t { return x + 1; }); - break; - } - case Opcode::AArch64_CSINVWr: { // csinv wd, wn, wm, cc - results[0] = { - conditionalHelp::cs_4ops( - operands, metadata, [](uint32_t x) -> uint32_t { return ~x; }), - 8}; - break; - } - case Opcode::AArch64_CSINVXr: { // csinv xd, xn, xm, cc - results[0] = conditionalHelp::cs_4ops( - operands, metadata, [](uint64_t x) -> uint64_t { return ~x; }); - break; - } - case Opcode::AArch64_CSNEGWr: { // csneg wd, wn, wm, cc - results[0] = { - conditionalHelp::cs_4ops( - operands, metadata, [](int32_t x) -> int32_t { return -x; }), - 8}; - break; - } - case Opcode::AArch64_CSNEGXr: { // csneg xd, xn, xm, cc - results[0] = conditionalHelp::cs_4ops( - operands, metadata, [](uint64_t x) -> uint64_t { return -x; }); - break; - } - case Opcode::AArch64_CTERMEQ_WW: { - return executionNYI(); - break; - } - case Opcode::AArch64_CTERMEQ_XX: { - return executionNYI(); - break; - } - case Opcode::AArch64_CTERMNE_WW: { - return executionNYI(); - break; - } - case Opcode::AArch64_CTERMNE_XX: { - return executionNYI(); - break; - } - case Opcode::AArch64_CompilerBarrier: { - return executionNYI(); - break; - } - case Opcode::AArch64_DCPS1: { - return executionNYI(); - break; - } - case Opcode::AArch64_DCPS2: { - return executionNYI(); - break; - } - case Opcode::AArch64_DCPS3: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECB_XPiI: { // decb xdn{, pattern{, MUL #imm}} - results[0] = - sveHelp::sveDec_scalar(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_DECD_XPiI: { // decd xdn{, pattern{, MUL #imm}} - results[0] = - sveHelp::sveDec_scalar(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_DECD_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECH_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECH_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_XP_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_XP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_XP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_XP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_ZP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_ZP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECP_ZP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECW_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_DECW_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_DMB: { // dmb option|#imm - // TODO: Respect memory barriers - break; - } - case Opcode::AArch64_DRPS: { - return executionNYI(); - break; - } - case Opcode::AArch64_DSB: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUPM_ZI: { // dupm zd.t, #imm - const uint64_t imm = static_cast(metadata.operands[1].imm); - uint64_t out[32] = {0}; - for (int i = 0; i < (VL_bits / 64); i++) { - out[i] = imm; - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_DUP_ZI_B: { // dup zd.b, #imm{, shift} - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_DUP_ZI_D: { // dup zd.d, #imm{, shift} - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_DUP_ZI_H: { // dup zd.h, #imm{, shift} - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_DUP_ZI_S: { // dup zd.s, #imm{, shift} - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_DUP_ZR_B: { // dup zd.b, wn - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_DUP_ZR_D: { // dup zd.d, xn - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_DUP_ZR_H: { // dup zd.h, wn - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_DUP_ZR_S: { // dup zd.s, wn - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_DUP_ZZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUP_ZZI_D: { // dup zd.d, zn.d[#imm] - results[0] = - sveHelp::sveDup_vecIndexed(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_DUP_ZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUP_ZZI_Q: { // dup zd.q, zn.q[#imm] - // No data-type for quadwords, but as data is just being moved around we - // can use uint64_t. - const uint16_t index = - 2 * static_cast(metadata.operands[1].vector_index); - const uint64_t* n = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 128; - uint64_t out[32] = {0}; - - if (index < partition_num) { - const uint64_t elementHi = n[index]; - const uint64_t elementLo = n[index + 1]; - for (int i = 0; i < partition_num; i++) { - out[2 * i] = elementHi; // Copy over top half of quadword - out[2 * i + 1] = elementLo; // Copy over lower half of quadword - } - } - results[0] = out; - break; - } - case Opcode::AArch64_DUP_ZZI_S: { // dup zd.s, zn.s[#imm] - results[0] = - sveHelp::sveDup_vecIndexed(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_DUPv16i8gpr: { // dup vd.16b, wn - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, true); - break; - } - case Opcode::AArch64_DUPv16i8lane: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUPv2i32gpr: { // dup vd.2s, wn - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, true); - break; - } - case Opcode::AArch64_DUPv2i32lane: { // dup vd.2s, vn.s[index] - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, false); - break; - } - case Opcode::AArch64_DUPv2i64gpr: { // dup vd.2d, xn - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, true); - break; - } - case Opcode::AArch64_DUPv2i64lane: { // dup vd.2d, vn.d[index] - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, false); - break; - } - case Opcode::AArch64_DUPv4i16gpr: { // dup vd.4h, wn - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, true); - break; - } - case Opcode::AArch64_DUPv4i16lane: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUPv4i32gpr: { // dup vd.4s, wn - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, true); - break; - } - case Opcode::AArch64_DUPv4i32lane: { // dup vd.4s, vn.s[index] - results[0] = - neonHelp::vecDup_gprOrIndex(operands, metadata, false); - break; - } - case Opcode::AArch64_DUPv8i16gpr: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUPv8i16lane: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUPv8i8gpr: { - return executionNYI(); - break; - } - case Opcode::AArch64_DUPv8i8lane: { - return executionNYI(); - break; - } - case Opcode::AArch64_EONWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_EONWrs: { - return executionNYI(); - break; - } - case Opcode::AArch64_EONXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_EONXrs: { - return executionNYI(); - break; - } - case Opcode::AArch64_EOR3: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORS_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORV_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORWri: { // eor wd, wn, #imm - auto [result, nzcv] = logicalHelp::logicOp_imm( - operands, metadata, false, - [](uint32_t x, uint32_t y) -> uint32_t { return x ^ y; }); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_EORWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORWrs: { // eor wd, wn, wm{, shift #imm} - auto [result, nzcv] = logicalHelp::logicOpShift_3ops( - operands, metadata, false, - [](uint32_t x, uint32_t y) -> uint32_t { return x ^ y; }); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_EORXri: { // eor xd, xn, #imm - auto [result, nzcv] = logicalHelp::logicOp_imm( - operands, metadata, false, - [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); - results[0] = result; - break; - } - case Opcode::AArch64_EORXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORXrs: { // eor xd, xn, xm{, shift #amount} - auto [result, nzcv] = logicalHelp::logicOpShift_3ops( - operands, metadata, false, - [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); - results[0] = result; - break; - } - case Opcode::AArch64_EOR_PPzPP: { - results[0] = sveHelp::sveLogicOp_preds( - operands, VL_bits, - [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); - break; - } - case Opcode::AArch64_EOR_ZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_EOR_ZPmZ_B: { // eor zdn.b, pg/m, zdn.b, zm.b - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); - break; - } - case Opcode::AArch64_EOR_ZPmZ_D: { // eor zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](uint64_t x, uint64_t y) -> uint64_t { return x ^ y; }); - break; - } - case Opcode::AArch64_EOR_ZPmZ_H: { // eor zdn.h, pg/m, zdn.h, zm.h - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](uint16_t x, uint16_t y) -> uint16_t { return x ^ y; }); - break; - } - case Opcode::AArch64_EOR_ZPmZ_S: { // eor zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](uint32_t x, uint32_t y) -> uint32_t { return x ^ y; }); - break; - } - case Opcode::AArch64_EOR_ZZZ: { - return executionNYI(); - break; - } - case Opcode::AArch64_EORv16i8: { // eor vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); - break; - } - case Opcode::AArch64_EORv8i8: { // eor vd.8b, vn.8b, vm.8b - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint8_t x, uint8_t y) -> uint8_t { return x ^ y; }); - break; - } - case Opcode::AArch64_ERET: { - return executionNYI(); - break; - } - case Opcode::AArch64_ERETAA: { - return executionNYI(); - break; - } - case Opcode::AArch64_ERETAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_EXTRWrri: { // extr wd, wn, wm, #lsb - results[0] = { - bitmanipHelp::extrLSB_registers(operands, metadata), 8}; - break; - } - case Opcode::AArch64_EXTRXrri: { // extr xd, xn, xm, #lsb - results[0] = - bitmanipHelp::extrLSB_registers(operands, metadata); - break; - } - case Opcode::AArch64_EXT_ZZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_EXTv16i8: { // ext vd.16b, vn.16b, vm.16b, #index - results[0] = - neonHelp::vecExtVecs_index(operands, metadata); - break; - } - case Opcode::AArch64_EXTv8i8: { // ext vd.8b, vn.8b, vm.8b, #index - results[0] = neonHelp::vecExtVecs_index(operands, metadata); - break; - } - case Opcode::AArch64_F128CSEL: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABD16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABD32: { // fabd sd, sn, sm - results[0] = floatHelp::fabd_3ops(operands); - break; - } - case Opcode::AArch64_FABD64: { // fabd dd, dn, dm - results[0] = floatHelp::fabd_3ops(operands); - break; - } - case Opcode::AArch64_FABD_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABD_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABD_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABDv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABDv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABDv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABDv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABDv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABSDr: { // fabs dd, dn - results[0] = floatHelp::fabs_2ops(operands); - break; - } - case Opcode::AArch64_FABSHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABSSr: { // fabs sd, sn - results[0] = floatHelp::fabs_2ops(operands); - break; - } - case Opcode::AArch64_FABS_ZPmZ_D: { // fabs zd.d, pg/m, zn.d - results[0] = sveHelp::sveFabsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FABS_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABS_ZPmZ_S: { // fabs zd.s, pg/m, zn.s - results[0] = sveHelp::sveFabsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FABSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABSv2f64: { // fabs vd.2d, vn.2d - results[0] = neonHelp::vecFabs_2ops(operands); - break; - } - case Opcode::AArch64_FABSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FABSv4f32: { // fabs vd.4s, vn.4s - results[0] = neonHelp::vecFabs_2ops(operands); - break; - } - case Opcode::AArch64_FABSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGE16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGE32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGE64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGE_PPzZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGE_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGE_PPzZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGEv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGEv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGEv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGEv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGEv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGT16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGT32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGT64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGT_PPzZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGT_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGT_PPzZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGTv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGTv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGTv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGTv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FACGTv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDA_VPZ_D: { // fadda dd, pg/m, dn, zm.d - results[0] = sveHelp::sveFaddaPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FADDA_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDA_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDDrr: { // fadd dd, dn, dm - results[0] = {arithmeticHelp::add_3ops(operands), 256}; - break; - } - case Opcode::AArch64_FADDHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDPv2f32: { // faddp vd.2s, vn.2s, vm.2s - results[0] = neonHelp::vecAddp_3ops(operands); - break; - } - case Opcode::AArch64_FADDPv2f64: { // faddp vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecAddp_3ops(operands); - break; - } - case Opcode::AArch64_FADDPv2i16p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDPv2i32p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDPv2i64p: { // faddp dd, vn.2d - results[0] = neonHelp::vecSumElems_2ops(operands); - break; - } - case Opcode::AArch64_FADDPv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDPv4f32: { // faddp vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecAddp_3ops(operands); - break; - } - case Opcode::AArch64_FADDPv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDSrr: { // fadd sd, sn, sm - results[0] = {arithmeticHelp::add_3ops(operands), 256}; - break; - } - case Opcode::AArch64_FADDV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADD_ZPmI_D: { // fadd zdn.d, pg/m, zdn.d, const - results[0] = sveHelp::sveAddPredicated_const(operands, metadata, - VL_bits); - break; - } - case Opcode::AArch64_FADD_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADD_ZPmI_S: { // fadd zdn.s, pg/m, zdn.s, const - results[0] = - sveHelp::sveAddPredicated_const(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FADD_ZPmZ_D: { // fadd zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveAddPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FADD_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADD_ZPmZ_S: { // fadd zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveAddPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FADD_ZZZ_D: { // fadd zd.d, zn.d, zm.d - results[0] = sveHelp::sveAdd_3ops(operands, VL_bits); - break; - } - case Opcode::AArch64_FADD_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADD_ZZZ_S: { // fadd zd.s, zn.s, zm.s - results[0] = sveHelp::sveAdd_3ops(operands, VL_bits); - break; - } - case Opcode::AArch64_FADDv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDv2f64: { // fadd vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecAdd_3ops(operands); - break; - } - case Opcode::AArch64_FADDv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FADDv4f32: { // fadd vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecAdd_3ops(operands); - break; - } - case Opcode::AArch64_FADDv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADD_ZPmZ_D: { // fcadd zdn.d, pg/m, zdn.d, zm.d, - // #imm - results[0] = - sveHelp::sveFcaddPredicated(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FCADD_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADD_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADDv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADDv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADDv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADDv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCADDv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCCMPDrr: // fccmp sn, sm, #nzcv, cc - case Opcode::AArch64_FCCMPEDrr: { // fccmpe sn, sm, #nzcv, cc - results[0] = floatHelp::fccmp(operands, metadata); - break; - } - case Opcode::AArch64_FCCMPEHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCCMPESrr: { // fccmpe sn, sm, #nzcv, cc - results[0] = floatHelp::fccmp(operands, metadata); - break; - } - case Opcode::AArch64_FCCMPHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCCMPSrr: { // fccmp sn, sm, #nzcv, cc - results[0] = floatHelp::fccmp(operands, metadata); - break; - } - case Opcode::AArch64_FCMEQ16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ_PPzZ0_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ_PPzZ0_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ_PPzZ0_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ_PPzZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQ_PPzZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv1i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv1i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv1i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv2i32rz: { // fcmeq vd.2s, vd.2s, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x == y; }); - break; - } - case Opcode::AArch64_FCMEQv2i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv4i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv4i32rz: { // fcmeq vd.4s vn.4s, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x == y; }); - break; - } - case Opcode::AArch64_FCMEQv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMEQv8i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGE16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGE32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGE64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGE_PPzZ0_D: { // fcmge pd.d, pg/z, zn.d, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](double x, double y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGE_PPzZ0_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGE_PPzZ0_S: { // fcmge pd.s, pg/z, zn.s, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](float x, float y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGE_PPzZZ_D: { // fcmge pd.d, pg/z, zn.d, zm.d - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, false, - [](double x, double y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGE_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGE_PPzZZ_S: { // fcmge pd.s, pg/z, zn.s, zm.s - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, false, - [](float x, float y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGEv1i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv1i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv1i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv2f32: { // fcmge vd.2s, vn.2s, vm.2s - results[0] = neonHelp::vecFCompare( - operands, false, [](float x, float y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGEv2f64: { // fcmge vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecFCompare( - operands, false, [](float x, double y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGEv2i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv2i64rz: { // fcmge vd.2d, vn.2d, 0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](double x, double y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGEv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv4f32: { // fcmge vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecFCompare( - operands, false, [](float x, float y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGEv4i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv4i32rz: { // fcmge vd.4s, vn.4s, 0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x >= y; }); - break; - } - case Opcode::AArch64_FCMGEv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGEv8i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGT16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGT32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGT64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGT_PPzZ0_D: { // fcmgt pd.d, pg/z, zn.d, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](double x, double y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGT_PPzZ0_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGT_PPzZ0_S: { // fcmgt pd.s, pg/z, zn.s, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](float x, float y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGT_PPzZZ_D: { // fcmgt pd.d, pg/z, zn.d, zm.d - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, false, - [](double x, double y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGT_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGT_PPzZZ_S: { // fcmgt pd.s, pg/z, zn.s, zm. - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, false, - [](float x, float y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGTv1i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv1i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv1i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv2i32rz: { // fcmgt vd.2s, vn.2s, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGTv2i64rz: { // fcmgt vd.2d, vn.2d, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](double x, double y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGTv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv4f32: { // fcmgt vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecFCompare( - operands, false, [](float x, float y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGTv4i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv4i32rz: { // fcmgt vd.4s, vn.4s, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x > y; }); - break; - } - case Opcode::AArch64_FCMGTv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMGTv8i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLA_ZPmZZ_D: { // fcmla zda, pg/m, zn, zm, #imm - results[0] = - sveHelp::sveFcmlaPredicated(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FCMLA_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLA_ZPmZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLA_ZZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLA_ZZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv4f16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv4f32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLAv8f16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLE_PPzZ0_D: { // fcmle pd.d, pg/z, zn.d, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](double x, double y) -> bool { return x <= y; }); - break; - } - case Opcode::AArch64_FCMLE_PPzZ0_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLE_PPzZ0_S: { // fcmle pd.s, pg/z, zn.s, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](float x, float y) -> bool { return x <= y; }); - break; - } - case Opcode::AArch64_FCMLEv1i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv1i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv1i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv2i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv2i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv4i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv4i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLEv8i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLT_PPzZ0_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLT_PPzZ0_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLT_PPzZ0_S: { // fcmlt pd.s, pg/z, zn.s, #0.0 - results[0] = sveHelp::sveComparePredicated_vecsToPred( - operands, metadata, VL_bits, true, - [](float x, float y) -> bool { return x < y; }); - break; - } - case Opcode::AArch64_FCMLTv1i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLTv1i32rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLTv1i64rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLTv2i32rz: { // fcmlt vd.2s, vn.2s, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x < y; }); - break; - } - case Opcode::AArch64_FCMLTv2i64rz: { // fcmlt vd.2d, vn.2d, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](double x, double y) -> bool { return x < y; }); - break; - } - case Opcode::AArch64_FCMLTv4i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMLTv4i32rz: { // fcmlt vd.4s, vn.4s, #0.0 - results[0] = neonHelp::vecFCompare( - operands, true, [](float x, float y) -> bool { return x < y; }); - break; - } - case Opcode::AArch64_FCMLTv8i16rz: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMNE_PPzZ0_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMNE_PPzZ0_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMNE_PPzZ0_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMNE_PPzZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMNE_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMNE_PPzZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMPDri: { // fcmp dn, #imm - results[0] = floatHelp::fcmp(operands, true); - break; - } - case Opcode::AArch64_FCMPDrr: { // fcmp dn, dm - results[0] = floatHelp::fcmp(operands, false); - break; - } - case Opcode::AArch64_FCMPEDri: { // fcmpe dn, #imm - results[0] = floatHelp::fcmp(operands, true); - break; - } - case Opcode::AArch64_FCMPEDrr: { // fcmpe dn, dm - results[0] = floatHelp::fcmp(operands, false); - break; - } - case Opcode::AArch64_FCMPEHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMPEHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMPESri: { // fcmpe sn, #imm - results[0] = floatHelp::fcmp(operands, true); - break; - } - case Opcode::AArch64_FCMPESrr: { // fcmpe sn, sm - results[0] = floatHelp::fcmp(operands, false); - break; - } - case Opcode::AArch64_FCMPHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMPHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMPSri: { // fcmp sn, #imm - results[0] = floatHelp::fcmp(operands, true); - break; - } - case Opcode::AArch64_FCMPSrr: { // fcmp sn, sm - results[0] = floatHelp::fcmp(operands, false); - break; - } - case Opcode::AArch64_FCMUO_PPzZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMUO_PPzZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCMUO_PPzZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCPY_ZPmI_D: { // fcpy zd.d, pg/m, #const - results[0] = sveHelp::sveFcpy_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FCPY_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCPY_ZPmI_S: { // fcpy zd.s, pg/m, #const - results[0] = sveHelp::sveFcpy_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FCSELDrrr: { // fcsel dd, dn, dm, cond - results[0] = { - conditionalHelp::cs_4ops( - operands, metadata, [](double x) -> double { return x; }), - 256}; - break; - } - case Opcode::AArch64_FCSELHrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCSELSrrr: { // fcsel sd, sn, sm, cond - results[0] = { - conditionalHelp::cs_4ops(operands, metadata, - [](float x) -> float { return x; }), - 256}; - break; - } - case Opcode::AArch64_FCVTASUWDr: { // fcvtas wd, dn - results[0] = {static_cast(round(operands[0].get())), - 8}; - break; - } - case Opcode::AArch64_FCVTASUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASUXDr: { // fcvtas xd, dn - results[0] = static_cast(round(operands[0].get())); - break; - } - case Opcode::AArch64_FCVTASUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTASv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTAUv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTDHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTDSr: { // fcvt dd, sn - // TODO: Handle NaNs, denorms, and saturation? - results[0] = neonHelp::vecFcvtl(operands, false); - break; - } - case Opcode::AArch64_FCVTHDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTHSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTLv2i32: { // fcvtl vd.2d, vn.2s - results[0] = neonHelp::vecFcvtl(operands, false); - break; - } - case Opcode::AArch64_FCVTLv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTLv4i32: { // fcvtl2 vd.2d, vn.4s - results[0] = neonHelp::vecFcvtl(operands, true); - break; - } - case Opcode::AArch64_FCVTLv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTMUv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNUv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNv2i32: { // fcvtn vd.2s, vn.2d - results[0] = neonHelp::vecFcvtn(operands, false); - break; - } - case Opcode::AArch64_FCVTNv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTNv4i32: { // fcvtn2 vd.4s, vn.2d - results[0] = neonHelp::vecFcvtn(operands, true); - break; - } - case Opcode::AArch64_FCVTNv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUUWDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUUWSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUUXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTPUv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTSDr: { // fcvt sd, dn - // TODO: Handle NaNs, denorms, and saturation? - results[0] = neonHelp::vecFcvtl(operands, false); - break; - } - case Opcode::AArch64_FCVTSHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTXNv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTXNv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTXNv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSSWDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSSWHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSSWSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSSXDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSSXHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSSXSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSUWDr: { // fcvtzs wd, dn - // TODO: Handle NaNs, denorms, and saturation - results[0] = { - static_cast(std::trunc(operands[0].get())), 8}; - break; - } - case Opcode::AArch64_FCVTZSUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSUWSr: { // fcvtzs wd, sn - // TODO: Handle NaNs, denorms, and saturation - results[0] = { - static_cast(std::trunc(operands[0].get())), 8}; - break; - } - case Opcode::AArch64_FCVTZSUXDr: { - // TODO: Handle NaNs, denorms, and saturation - results[0] = { - static_cast(std::trunc(operands[0].get())), 8}; - break; - } - case Opcode::AArch64_FCVTZSUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSUXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_DtoD: { // fcvtzs zd.d, pg/m, zn.d - results[0] = - sveHelp::sveFcvtzsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_DtoS: { // fcvtzs zd.s, pg/m, zn.d - results[0] = - sveHelp::sveFcvtzsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_HtoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_HtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_HtoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_StoD: { // fcvtzs zd.d, pg/m, zn.s - results[0] = - sveHelp::sveFcvtzsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FCVTZS_ZPmZ_StoS: { // fcvtzs zd.s, pg/m, zn.s - results[0] = - sveHelp::sveFcvtzsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FCVTZSd: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSh: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSs: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv2f64: { // fcvtzs vd.2d, vn.2d - results[0] = neonHelp::vecFcvtzs(operands); - break; - } - case Opcode::AArch64_FCVTZSv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZSv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUSWDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUSWHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUSWSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUSXDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUSXHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUSXSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUUWDr: { // fcvtzu wd, dn - // TODO: Handle NaNs, denorms, and saturation - results[0] = { - static_cast(std::trunc(operands[0].get())), 8}; - break; - } - case Opcode::AArch64_FCVTZUUWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUUWSr: { // fcvtzu wd, sn - // TODO: Handle NaNs, denorms, and saturation - results[0] = { - static_cast(std::trunc(operands[0].get())), 8}; - break; - } - case Opcode::AArch64_FCVTZUUXDr: { // fcvtzu xd, dn - // TODO: Handle NaNs, denorms, and saturation - results[0] = - static_cast(std::trunc(operands[0].get())); - break; - } - case Opcode::AArch64_FCVTZUUXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUUXSr: { // fcvtzu xd, sn - // TODO: Handle NaNs, denorms, and saturation - results[0] = static_cast(std::trunc(operands[0].get())); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_DtoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_DtoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_HtoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_HtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_HtoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_StoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZU_ZPmZ_StoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUd: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUh: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUs: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVTZUv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVT_ZPmZ_DtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVT_ZPmZ_DtoS: { // fcvt zd.s, pg/m, zn.d - results[0] = - sveHelp::sveFcvtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FCVT_ZPmZ_HtoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVT_ZPmZ_HtoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_FCVT_ZPmZ_StoD: { // fcvt zd.d, pg/m, zn.s - results[0] = - sveHelp::sveFcvtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FCVT_ZPmZ_StoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVDrr: { // fdiv dd, dn, dm - results[0] = {divideHelp::div_3ops(operands), 256}; - break; - } - case Opcode::AArch64_FDIVHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVR_ZPmZ_D: { // fdivr zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](double x, double y) -> double { return (y / x); }); - break; - } - case Opcode::AArch64_FDIVR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVR_ZPmZ_S: { // fdivr zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](float x, float y) -> float { return (y / x); }); - break; - } - case Opcode::AArch64_FDIVSrr: { // fdiv sd, sn, sm - results[0] = {divideHelp::div_3ops(operands), 256}; - break; - } - case Opcode::AArch64_FDIV_ZPmZ_D: { // fdiv zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](double x, double y) -> double { return (x / y); }); - break; - } - case Opcode::AArch64_FDIV_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIV_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVv2f64: { // fdiv vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](double x, double y) -> double { return x / y; }); - break; - } - case Opcode::AArch64_FDIVv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDIVv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDUP_ZI_D: { // fdup zd.d, #imm - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_FDUP_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FDUP_ZI_S: { // fdup zd.s, #imm - results[0] = sveHelp::sveDup_immOrScalar(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_FEXPA_ZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FEXPA_ZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FEXPA_ZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FJCVTZS: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMADDDrrr: { // fmadd dn, dm, da - results[0] = {multiplyHelp::madd_4ops(operands), 256}; - break; - } - case Opcode::AArch64_FMADDHrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMADDSrrr: { // fmadd sn, sm, sa - results[0] = {multiplyHelp::madd_4ops(operands), 256}; - break; - } - case Opcode::AArch64_FMAD_ZPmZZ_D: { // fmad zd.d, pg/m, zn.d, zm.d - results[0] = sveHelp::sveFmadPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMAD_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAD_ZPmZZ_S: { // fmad zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveFmadPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMAXDrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMDrr: { // fmaxnm dd, dn, dm - results[0] = floatHelp::fmaxnm_3ops(operands); - break; - } - case Opcode::AArch64_FMAXNMHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv2i16p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv2i32p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv2i64p: { // fmaxnmp dd, vd.2d - results[0] = neonHelp::vecMaxnmp_2ops(operands); - break; - } - case Opcode::AArch64_FMAXNMPv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMPv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMSrr: { // fmaxnm sd, sn, sm - results[0] = floatHelp::fmaxnm_3ops(operands); - break; - } - case Opcode::AArch64_FMAXNMV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNM_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNM_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNM_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNM_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNM_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNM_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMv2f64: { // fmaxnm vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecLogicOp_3vecs( - operands, - [](double x, double y) -> double { return std::fmax(x, y); }); - break; - } - case Opcode::AArch64_FMAXNMv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXNMv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv2i16p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv2i32p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv2i64p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXPv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXSrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAX_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAX_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAX_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAX_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAX_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAX_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMAXv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINDrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMDrr: { // fminnm dd, dn, dm - results[0] = floatHelp::fminnm_3ops(operands); - break; - } - case Opcode::AArch64_FMINNMHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv2i16p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv2i32p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv2i64p: { // fminnmp dd, vd.2d - results[0] = neonHelp::vecMinv_2ops(operands); - break; - } - case Opcode::AArch64_FMINNMPv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMPv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMSrr: { // fminnm sd, sn, sm - results[0] = floatHelp::fminnm_3ops(operands); - break; - } - case Opcode::AArch64_FMINNMV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNM_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNM_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNM_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNM_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNM_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNM_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMv2f64: { // fminnm vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecLogicOp_3vecs( - operands, - [](double x, double y) -> double { return std::fmin(x, y); }); - break; - } - case Opcode::AArch64_FMINNMv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINNMv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv2i16p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv2i32p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv2i64p: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINPv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINSrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMIN_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMIN_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMIN_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMIN_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMIN_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMIN_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMINv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLA_ZPmZZ_D: { // fmla zd.d, pg/m, zn.d, zm.d - results[0] = sveHelp::sveMlaPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMLA_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLA_ZPmZZ_S: { // fmla zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveMlaPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMLA_ZZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLA_ZZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLA_ZZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv1i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv1i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv2f64: { // fmla vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecFmla_3vecs(operands); - break; - } - case Opcode::AArch64_FMLAv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv2i64_indexed: { // fmla vd.2d, vn.2d, - // vm.d[index] - results[0] = - neonHelp::vecFmlaIndexed_3vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMLAv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv4f32: { // fmla vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecFmla_3vecs(operands); - break; - } - case Opcode::AArch64_FMLAv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv4i32_indexed: { // fmla vd.4s, vn.4s, - // vm.s[index] - results[0] = - neonHelp::vecFmlaIndexed_3vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMLAv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLAv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLS_ZPmZZ_D: { // fmls zd.d, pg/m, zn.d, zm.d - results[0] = sveHelp::sveFmlsPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMLS_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLS_ZPmZZ_S: { // fmls zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveFmlsPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMLS_ZZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLS_ZZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLS_ZZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv1i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv1i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv2f64: { // fmls vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecFmls_3vecs(operands); - break; - } - case Opcode::AArch64_FMLSv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv2i64_indexed: { - results[0] = - neonHelp::vecFmlsIndexed_3vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMLSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv4f32: { // fmls vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecFmls_3vecs(operands); - break; - } - case Opcode::AArch64_FMLSv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv4i32_indexed: { // fmls vd.4s, vn.4s, - // vm.s[index] - results[0] = - neonHelp::vecFmlsIndexed_3vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMLSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMLSv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVD0: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVDXHighr: { // fmov xd, vn.d[1] - results[0] = operands[0].getAsVector()[1]; - break; - } - case Opcode::AArch64_FMOVDXr: { // fmov xd, dn - results[0] = operands[0].get(); - break; - } - case Opcode::AArch64_FMOVDi: { // fmov dn, #imm - results[0] = {metadata.operands[1].fp, 256}; - break; - } - case Opcode::AArch64_FMOVDr: { // fmov dd, dn - results[0] = {operands[0].get(), 256}; - break; - } - case Opcode::AArch64_FMOVH0: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVHWr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVHXr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVS0: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVSWr: { // fmov wd, sn - results[0] = {operands[0].get(), 8}; - break; - } - case Opcode::AArch64_FMOVSi: { // fmov sn, #imm - results[0] = {static_cast(metadata.operands[1].fp), 256}; - break; - } - case Opcode::AArch64_FMOVSr: { // fmov sd, sn - results[0] = {operands[0].get(), 256}; - break; - } - case Opcode::AArch64_FMOVWHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVWSr: { // fmov sd, wn - results[0] = {operands[0].get(), 256}; - break; - } - case Opcode::AArch64_FMOVXDHighr: { // fmov vd.d[1], xn - double out[2] = {operands[0].get(), operands[1].get()}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_FMOVXDr: { // fmov dd, xn - results[0] = {operands[0].get(), 256}; - break; - } - case Opcode::AArch64_FMOVXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVv2f32_ns: { // fmov vd.2s, #imm - results[0] = neonHelp::vecMovi_imm(metadata); - break; - } - case Opcode::AArch64_FMOVv2f64_ns: { // fmov vd.2d, #imm - results[0] = neonHelp::vecMovi_imm(metadata); - break; - } - case Opcode::AArch64_FMOVv4f16_ns: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMOVv4f32_ns: { // fmov vd.4s, #imm - results[0] = neonHelp::vecMovi_imm(metadata); - break; - } - case Opcode::AArch64_FMOVv8f16_ns: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMSB_ZPmZZ_D: { // fmsb zd.d, pg/m, zn.d, zm.d - results[0] = sveHelp::sveFmsbPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMSB_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMSB_ZPmZZ_S: { // fmsb zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveFmsbPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FMSUBDrrr: { // fmsub dn, dm, da - results[0] = {multiplyHelp::msub_4ops(operands), 256}; - break; - } - case Opcode::AArch64_FMSUBHrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMSUBSrrr: { // fmsub sn, sm, sa - results[0] = {multiplyHelp::msub_4ops(operands), 256}; - break; - } - case Opcode::AArch64_FMULDrr: { // fmul dd, dn, dm - results[0] = {multiplyHelp::mul_3ops(operands), 256}; - break; - } - case Opcode::AArch64_FMULHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULSrr: { // fmul sd, sn, sm - results[0] = {multiplyHelp::mul_3ops(operands), 256}; - break; - } - case Opcode::AArch64_FMULX16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULX32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULX64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULX_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULX_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULX_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv1i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv1i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv2i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULXv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZPmI_D: { // fmul zd.d, pg/m, zn.d, #imm - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, true); - break; - } - case Opcode::AArch64_FMUL_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZPmI_S: { // fmul zd.s, pg/m, zn.s, #imm - results[0] = - sveHelp::sveMulPredicated(operands, metadata, VL_bits, true); - break; - } - case Opcode::AArch64_FMUL_ZPmZ_D: { // fmul zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_FMUL_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZPmZ_S: { // fmul zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_FMUL_ZZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZZZ_D: { // fmul zd.d, zn.d, zm.d - results[0] = sveHelp::sveFmul_3ops(operands, VL_bits); - break; - } - case Opcode::AArch64_FMUL_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMUL_ZZZ_S: { // fmul zd.s, zn.s, zm.s - results[0] = sveHelp::sveFmul_3ops(operands, VL_bits); - break; - } - case Opcode::AArch64_FMULv1i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULv1i32_indexed: { // fmul sd, sn, vm.s[index] - results[0] = - neonHelp::vecFmulIndexed_vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMULv1i64_indexed: { // fmul dd, dn, vm.d[index] - results[0] = - neonHelp::vecFmulIndexed_vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMULv2f32: { // fmul vd.2s, vn.2s, vm.2s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](float x, float y) -> float { return x * y; }); - break; - } - case Opcode::AArch64_FMULv2f64: { // fmul vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](double x, double y) -> double { return x * y; }); - break; - } - case Opcode::AArch64_FMULv2i32_indexed: { // fmul vd.2s, vn.2s, - // vm.s[index] - results[0] = - neonHelp::vecFmulIndexed_vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMULv2i64_indexed: { // fmul vd.2d, vn.2d, - // vm.d[index] - results[0] = - neonHelp::vecFmulIndexed_vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMULv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULv4f32: { // fmul vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](float x, float y) -> float { return x * y; }); - break; - } - case Opcode::AArch64_FMULv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULv4i32_indexed: { // fmul vd.4s, vn.4s, - // vm.s[index] - results[0] = - neonHelp::vecFmulIndexed_vecs(operands, metadata); - break; - } - case Opcode::AArch64_FMULv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FMULv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNEGDr: { // fneg dd, dn - results[0] = {-operands[0].get(), 256}; - break; - } - case Opcode::AArch64_FNEGHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNEGSr: { // fneg sd, sn - results[0] = {-operands[0].get(), 256}; - break; - } - case Opcode::AArch64_FNEG_ZPmZ_D: { // fneg zd.d, pg/m, zn.d - results[0] = sveHelp::sveFnegPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FNEG_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNEG_ZPmZ_S: { // fneg zd.s, pg/m, zn.s - results[0] = sveHelp::sveFnegPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FNEGv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNEGv2f64: { // fneg vd.2d, vn.2d - results[0] = neonHelp::vecFneg_2ops(operands); - break; - } - case Opcode::AArch64_FNEGv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNEGv4f32: { // fneg vd.4s, vn.4s - results[0] = neonHelp::vecFneg_2ops(operands); - break; - } - case Opcode::AArch64_FNEGv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMADDDrrr: { // fnmadd dd, dn, dm, da - results[0] = floatHelp::fnmadd_4ops(operands); - break; - } - case Opcode::AArch64_FNMADDHrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMADDSrrr: { // fnmadd sd, sn, sm, sa - results[0] = floatHelp::fnmadd_4ops(operands); - break; - } - case Opcode::AArch64_FNMAD_ZPmZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMAD_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMAD_ZPmZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMLA_ZPmZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMLA_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMLA_ZPmZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMLS_ZPmZZ_D: { // fnmls zd.d, pg/m, zn.d, zm.d - results[0] = sveHelp::sveFnmlsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FNMLS_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMLS_ZPmZZ_S: { // fnmls zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveFnmlsPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FNMSB_ZPmZZ_D: { // fnmsb zdn.d, pg/m, zm.d, za.d - results[0] = sveHelp::sveFnmsbPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FNMSB_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMSB_ZPmZZ_S: { // fnmsb zdn.s, pg/m, zm.s, za.s - results[0] = sveHelp::sveFnmsbPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FNMSUBDrrr: { // fnmsub dd, dn, dm, da - results[0] = floatHelp::fnmsub_4ops(operands); - break; - } - case Opcode::AArch64_FNMSUBHrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMSUBSrrr: { // fnmsub sd, sn, sm, sa - results[0] = floatHelp::fnmsub_4ops(operands); - break; - } - case Opcode::AArch64_FNMULDrr: { // fnmul dd, dn, dm - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](double x, double y) -> double { return -(x * y); }); - break; - } - case Opcode::AArch64_FNMULHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FNMULSrr: { // fnmul sd, sn, sm - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](float x, float y) -> float { return -(x * y); }); - break; - } - case Opcode::AArch64_FRECPE_ZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPE_ZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPE_ZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPEv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPS16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPS32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPS64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPS_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPS_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPS_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPSv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPSv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPSv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPX_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPX_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPX_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPXv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPXv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRECPXv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTADr: { // frinta dd, dn - results[0] = {round(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_FRINTAHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTASr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTA_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTA_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTA_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTAv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTAv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTAv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTAv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTAv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTISr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTI_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTI_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTI_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTIv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTM_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTM_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTM_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTMv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTN_ZPmZ_D: { // frintn zd.d, pg/m, zn.d - results[0] = - sveHelp::sveFrintnPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FRINTN_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTN_ZPmZ_S: { // frintn zd.s, pg/m, zn.s - results[0] = - sveHelp::sveFrintnPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_FRINTNv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTNv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTP_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTP_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTP_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTPv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTX_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTX_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTX_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTXv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZDr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZSr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZ_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZ_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZ_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRINTZv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTE_ZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTE_ZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTE_ZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTEv1f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTEv1i32: { // frsqrte sd, sn - results[0] = neonHelp::vecFrsqrte_2ops(operands); - break; - } - case Opcode::AArch64_FRSQRTEv1i64: { // frsqrte dd, dn - results[0] = neonHelp::vecFrsqrte_2ops(operands); - break; - } - case Opcode::AArch64_FRSQRTEv2f32: { // frsqrte vd.2s, vn.2s - results[0] = neonHelp::vecFrsqrte_2ops(operands); - break; - } - case Opcode::AArch64_FRSQRTEv2f64: { // frsqrte vd.2d, vn.2d - results[0] = neonHelp::vecFrsqrte_2ops(operands); - break; - } - case Opcode::AArch64_FRSQRTEv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTEv4f32: { // frsqrte vd.4s, vn.4s - results[0] = neonHelp::vecFrsqrte_2ops(operands); - break; - } - case Opcode::AArch64_FRSQRTEv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTS16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTS32: { // frsqrts sd, sn, sm - results[0] = neonHelp::vecFrsqrts_3ops(operands); - break; - } - case Opcode::AArch64_FRSQRTS64: { // frsqrts dd, dn, dm - results[0] = neonHelp::vecFrsqrts_3ops(operands); - break; - } - case Opcode::AArch64_FRSQRTS_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTS_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTS_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTSv2f32: { // frsqrts vd.2s, vn.2s, vn.2s - results[0] = neonHelp::vecFrsqrts_3ops(operands); - break; - } - case Opcode::AArch64_FRSQRTSv2f64: { // frsqrts vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecFrsqrts_3ops(operands); - break; - } - case Opcode::AArch64_FRSQRTSv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FRSQRTSv4f32: { // frsqrts vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecFrsqrts_3ops(operands); - break; - } - case Opcode::AArch64_FRSQRTSv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSCALE_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSCALE_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSCALE_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSQRTDr: { // fsqrt dd, dn - results[0] = {::sqrt(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_FSQRTHr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSQRTSr: { // fsqrt sd, sn - results[0] = {::sqrtf(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_FSQRT_ZPmZ_D: { // fsqrt zd.d, pg/m, zn.d - results[0] = - sveHelp::sveFsqrtPredicated_2vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FSQRT_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSQRT_ZPmZ_S: { // fsqrt zd.s, pg/m, zn.s - results[0] = - sveHelp::sveFsqrtPredicated_2vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FSQRTv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSQRTv2f64: { // fsqrt vd.2d, vn.2d - results[0] = neonHelp::vecFsqrt_2ops(operands); - break; - } - case Opcode::AArch64_FSQRTv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSQRTv4f32: { // fsqrt vd.4s, vn.4s - results[0] = neonHelp::vecFsqrt_2ops(operands); - break; - } - case Opcode::AArch64_FSQRTv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBDrr: { // fsub dd, dn, dm - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](double x, double y) -> double { return x - y; }); - break; - } - case Opcode::AArch64_FSUBHrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBR_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBR_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBR_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBR_ZPmZ_D: { // fsubr zdn.d, pg/m, zdn.d, zm.d - results[0] = - sveHelp::sveSubrPredicated_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FSUBR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBR_ZPmZ_S: { // fsubr zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveSubrPredicated_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FSUBSrr: { // fsub ss, sn, sm - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](double x, double y) -> double { return x - y; }); - break; - } - case Opcode::AArch64_FSUB_ZPmI_D: { // fsub zdn.d, pg/m, zdn.d, #imm - results[0] = - sveHelp::sveSubPredicated_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FSUB_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUB_ZPmI_S: { // fsub zdn.s, pg/m, zdn.s, #imm - results[0] = - sveHelp::sveSubPredicated_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_FSUB_ZPmZ_D: { // fsub zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](double x, double y) -> double { return x - y; }); - break; - } - case Opcode::AArch64_FSUB_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUB_ZPmZ_S: { // fsub zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, [](float x, float y) -> float { return x - y; }); - break; - } - case Opcode::AArch64_FSUB_ZZZ_D: { // fsub zd.d, zn.d, zm.d - results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FSUB_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUB_ZZZ_S: { // fsub zd.s, zn.s, zm.s - results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_FSUBv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBv2f64: { // fsub vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](double x, double y) -> double { return x - y; }); - break; - } - case Opcode::AArch64_FSUBv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FSUBv4f32: { // fsub vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](float x, float y) -> float { return x - y; }); - break; - } - case Opcode::AArch64_FSUBv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTMAD_ZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTMAD_ZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTMAD_ZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTSMUL_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTSMUL_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTSMUL_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTSSEL_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTSSEL_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_FTSSEL_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1B_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1D_IMM_REAL: { // ld1d {zd.d}, pg/z, [zn.d{, - // #imm}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint64_t out[32] = {0}; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_GLD1D_REAL: // ld1d {zt.d}, pg/z, [xn, zm.d] - // LOAD - [[fallthrough]]; - case Opcode::AArch64_GLD1D_SCALED_REAL: { // ld1d {zt.d}, pg/z, [xn, - // zm.d, LSL #3] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - uint64_t out[32] = {0}; - - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } - } - - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_GLD1D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_S_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1H_S_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SB_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_S_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SH_S_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SW_D_IMM_REAL: { // ld1sw {zd.d}, pg/z, [zn.d{, - // #imm}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - int64_t out[32] = {0}; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out[i] = static_cast(memoryData[index].get()); - index++; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_GLD1SW_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SW_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SW_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SW_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SW_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1SW_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLD1W_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1B_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_S_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1H_S_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SB_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_S_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_S_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_S_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SH_S_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1SW_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_D_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_SXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_SXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_UXTW_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_GLDFF1W_UXTW_SCALED_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_HINT: { // nop|yield|wfe|wfi|etc... - // TODO: Observe hints - break; - } - case Opcode::AArch64_HLT: { - return executionNYI(); - break; - } - case Opcode::AArch64_HVC: { - return executionNYI(); - break; - } - case Opcode::AArch64_INCB_XPiI: { // incb xdn{, pattern{, #imm}} - results[0] = - sveHelp::sveInc_gprImm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INCD_XPiI: { // incd xdn{, pattern{, #imm}} - results[0] = - sveHelp::sveInc_gprImm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INCD_ZPiI: { // incd zdn.d{, pattern{, #imm}} - results[0] = sveHelp::sveInc_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INCH_XPiI: { // inch xdn{, pattern{, #imm}} - results[0] = - sveHelp::sveInc_gprImm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INCH_ZPiI: { // inch zdn.h{, pattern{, #imm}} - results[0] = sveHelp::sveInc_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INCP_XP_B: { // incp xdn, pm.b - results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); - break; - } - case Opcode::AArch64_INCP_XP_D: { // incp xdn, pm.d - results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); - break; - } - case Opcode::AArch64_INCP_XP_H: { // incp xdn, pm.h - results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); - break; - } - case Opcode::AArch64_INCP_XP_S: { // incp xdn, pm.s - results[0] = sveHelp::sveIncp_gpr(operands, VL_bits); - break; - } - case Opcode::AArch64_INCP_ZP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_INCP_ZP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_INCP_ZP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_INCW_XPiI: { // incw xdn{, pattern{, #imm}} - results[0] = - sveHelp::sveInc_gprImm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INCW_ZPiI: { // incw zdn.s{, pattern{, #imm}} - results[0] = sveHelp::sveInc_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_INDEX_II_B: { // index zd.b, #imm, #imm - results[0] = - sveHelp::sveIndex(operands, metadata, VL_bits, true, true); - break; - } - case Opcode::AArch64_INDEX_II_D: { // index zd.d, #imm, #imm - results[0] = - sveHelp::sveIndex(operands, metadata, VL_bits, true, true); - break; - } - case Opcode::AArch64_INDEX_II_H: { // index zd.h, #imm, #imm - results[0] = - sveHelp::sveIndex(operands, metadata, VL_bits, true, true); - break; - } - case Opcode::AArch64_INDEX_II_S: { // index zd.s, #imm, #imm - results[0] = - sveHelp::sveIndex(operands, metadata, VL_bits, true, true); - break; - } - case Opcode::AArch64_INDEX_IR_B: { // index zd.b, #imm, wn - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, true, false); - break; - } - case Opcode::AArch64_INDEX_IR_D: { // index zd.d, #imm, xn - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, true, false); - break; - } - case Opcode::AArch64_INDEX_IR_H: { // index zd.h, #imm, wn - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, true, false); - break; - } - case Opcode::AArch64_INDEX_IR_S: { // index zd.s, #imm, wn - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, true, false); - break; - } - case Opcode::AArch64_INDEX_RI_B: { // index zd.b, wn, #imm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, true); - break; - } - case Opcode::AArch64_INDEX_RI_D: { // index zd.d, xn, #imm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, true); - break; - } - case Opcode::AArch64_INDEX_RI_H: { // index zd.h, wn, #imm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, true); - break; - } - case Opcode::AArch64_INDEX_RI_S: { // index zd.s, wn, #imm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, true); - break; - } - case Opcode::AArch64_INDEX_RR_B: { // index zd.b, wn, wm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, false); - break; - } - case Opcode::AArch64_INDEX_RR_D: { // index zd.d, xn, xm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, false); - break; - } - case Opcode::AArch64_INDEX_RR_H: { // index zd.h, wn, wm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, false); - break; - } - case Opcode::AArch64_INDEX_RR_S: { // index zd.s, wn, wm - results[0] = sveHelp::sveIndex(operands, metadata, - VL_bits, false, false); - break; - } - case Opcode::AArch64_INSR_ZR_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZR_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZR_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZR_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZV_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZV_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZV_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSR_ZV_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSvi16gpr: { // ins vd.h[index], wn - results[0] = neonHelp::vecInsIndex_gpr(operands, - metadata); - break; - } - case Opcode::AArch64_INSvi16lane: { - return executionNYI(); - break; - } - case Opcode::AArch64_INSvi32gpr: { // ins vd.s[index], wn - results[0] = neonHelp::vecInsIndex_gpr(operands, - metadata); - break; - } - case Opcode::AArch64_INSvi32lane: { // ins vd.s[index1], vn.s[index2] - results[0] = neonHelp::vecIns_2Index(operands, metadata); - break; - } - case Opcode::AArch64_INSvi64gpr: { // ins vd.d[index], xn - results[0] = neonHelp::vecInsIndex_gpr(operands, - metadata); - break; - } - case Opcode::AArch64_INSvi64lane: { // ins vd.d[index1], vn.d[index2] - results[0] = neonHelp::vecIns_2Index(operands, metadata); - break; - } - case Opcode::AArch64_INSvi8gpr: { // ins vd.b[index], wn - results[0] = neonHelp::vecInsIndex_gpr(operands, - metadata); - break; - } - case Opcode::AArch64_INSvi8lane: { - return executionNYI(); - break; - } - case Opcode::AArch64_ISB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_RPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_RPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_RPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_RPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTA_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_RPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_RPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_RPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_RPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LASTB_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B: { // ld1b {zt.b}, pg/z, [xn, xm] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 8; - uint16_t index = 0; - uint8_t out[256] = {0}; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << (i % 64); - if (p[i / 64] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } else { - out[i] = 0; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1B_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B_H_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1B_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1D: { // ld1d {zt.d}, pg/z, [xn, xm, lsl #3] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - uint64_t out[32] = {0}; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } else { - out[i] = 0; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1D_IMM_REAL: { // ld1d {zt.d}, pg/z, [xn{, #imm, - // mul vl}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - uint64_t out[32] = {0}; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } else { - out[i] = 0; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Fourv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Fourv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1H: { // ld1h {zt.h}, pg/z, [xn, xm, lsl #1] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 16; - uint16_t index = 0; - uint16_t out[128] = {0}; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 32) * 2); - if (p[i / 32] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } else { - out[i] = 0; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1H_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1H_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1H_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1H_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1H_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Onev8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RB_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RB_H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RB_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RB_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RD_IMM: { // ld1rd {zt.d}, pg/z, [xn, #imm] - // LOAD - const uint16_t partition_num = VL_bits / 64; - uint64_t out[32] = {0}; - uint16_t index = 0; - // Check if any lanes are active, otherwise set all to 0 and break early - bool active = false; - const uint64_t* p = operands[0].getAsVector(); - for (int i = 0; i < 4; i++) { - if (p[i] != 0) { - active = true; - break; - } - } - - if (active) { - uint64_t data = memoryData[0].get(); - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = p[index / 8] & 1ull << ((index % 8) * 8); - out[i] = shifted_active ? data : 0; - index++; - } - } - - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1RH_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RH_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RH_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_D_IMM: { // ld1rqd {zd.d}, pg/z, [xn{, #imm}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - const uint16_t partition_num = VL_bits / 64; - uint64_t out[32] = {0}; - uint16_t index = 0; - - // Get mini-vector (quadword) - uint64_t mini[2] = {0}; - for (int i = 0; i < 2; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) - mini[i] = memoryData[index].get(); - index++; - } - - // Duplicate mini-vector into output vector - for (int i = 0; i < (partition_num / 2); i++) { - out[2 * i] = mini[0]; - out[(2 * i) + 1] = mini[1]; - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1RQ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_W: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RQ_W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RSB_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RSB_H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RSB_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RSH_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RSH_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RSW_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RW_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1RW_IMM: { // ld1rw {zt.s}, pg/z, [xn, #imm] - // LOAD - const uint16_t partition_num = VL_bits / 32; - uint32_t out[64] = {0}; - uint16_t index = 0; - // Check if any lanes are active, otherwise set all to 0 and break early - bool active = false; - const uint64_t* p = operands[0].getAsVector(); - for (int i = 0; i < 4; i++) { - if (p[i] != 0) { - active = true; - break; - } - } - if (active) { - uint32_t data = memoryData[0].get(); - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = p[index / 16] & 1ull - << ((index % 16) * 4); - out[i] = shifted_active ? data : 0; - index++; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv16b: { // ld1r {vt.16b}, [xn] - // LOAD - 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}; - break; - } - case Opcode::AArch64_LD1Rv16b_POST: { // ld1r {vt.16b}, [xn], #imm - // LOAD - 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] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv1d: { // ld1r {vt.1d}, [xn] - // LOAD - uint64_t val = memoryData[0].get(); - uint64_t out[2] = {val, 0}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv1d_POST: { // ld1r {vt.1d}, [xn], #imm - // LOAD - uint64_t val = memoryData[0].get(); - uint64_t out[2] = {val, 0}; - results[0] = {out, 256}; - results[1] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv2d: { // ld1r {vt.2d}, [xn] - // LOAD - uint64_t val = memoryData[0].get(); - uint64_t out[2] = {val, val}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv2d_POST: { // ld1r {vt.2d}, [xn], #imm - // LOAD - uint64_t val = memoryData[0].get(); - uint64_t out[2] = {val, val}; - results[0] = {out, 256}; - results[1] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv2s: { // ld1r {vt.2s}, [xn] - // LOAD - uint32_t val = memoryData[0].get(); - uint32_t out[4] = {val, val, 0, 0}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv2s_POST: { // ld1r {vt.2s}, [xn], #imm - // LOAD - uint32_t val = memoryData[0].get(); - uint32_t out[4] = {val, val, 0, 0}; - results[0] = {out, 256}; - results[1] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv4h: { // ld1r {vt.4h}, [xn] - // LOAD - uint16_t val = memoryData[0].get(); - uint16_t out[8] = {val, val, val, val, 0, 0, 0, 0}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv4h_POST: { // ld1r {vt.4h}, [xn], #imm - // 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] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv4s: { // ld1r {vt.4s}, [xn] - // LOAD - uint32_t val = memoryData[0].get(); - uint32_t out[4] = {val, val, val, val}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv4s_POST: { // ld1r {vt.4s}, [xn], #imm - // LOAD - uint32_t val = memoryData[0].get(); - uint32_t out[4] = {val, val, val, val}; - results[0] = {out, 256}; - results[1] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv8b: { // ld1r {vt.8b}, [xn] - // LOAD - 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}; - break; - } - case Opcode::AArch64_LD1Rv8b_POST: { // ld1r {vt.8b}, [xn], #imm - // LOAD - 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] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1Rv8h: { // ld1r {vt.8h}, [xn] - // LOAD - uint16_t val = memoryData[0].get(); - uint16_t out[8] = {val, val, val, val, val, val, val, val}; - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1Rv8h_POST: { // ld1r {vt.8h}, [xn], #imm - // 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] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1SB_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SB_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SB_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SB_H_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SB_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SB_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SH_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SH_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SH_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SH_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SW_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1SW_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Threev8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov16b: { // ld1 {vt1.16b, vt2.16b}, [xn] - // LOAD - results[0] = memoryData[0].zeroExtend(memoryData[0].size(), 256); - results[1] = memoryData[1].zeroExtend(memoryData[1].size(), 256); - break; - } - case Opcode::AArch64_LD1Twov16b_POST: { // ld1 {vt1.16b, vt2.16b}, [xn], - // #imm - // LOAD - results[0] = memoryData[0].zeroExtend(memoryData[0].size(), 256); - results[1] = memoryData[1].zeroExtend(memoryData[1].size(), 256); - results[2] = operands[0].get() + metadata.operands[3].imm; - break; - } - case Opcode::AArch64_LD1Twov1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1Twov8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1W: { // ld1w {zt.s}, pg/z, [xn, xm, lsl #2] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 32; - uint16_t index = 0; - uint32_t out[64] = {0}; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 16) * 4); - if (p[i / 16] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } else { - out[i] = 0; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1W_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1W_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1W_IMM_REAL: { // ld1w {zt.s}, pg/z, [xn{, #imm, - // mul vl}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - - const uint16_t partition_num = VL_bits / 32; - uint16_t index = 0; - uint32_t out[64] = {0}; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 16) * 4); - if (p[i / 16] & shifted_active) { - out[i] = memoryData[index].get(); - index++; - } else { - out[i] = 0; - } - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1i32: { // ld1 {vt.s}[index], [xn] - // LOAD - const int index = metadata.operands[0].vector_index; - const uint32_t* vt = operands[0].getAsVector(); - uint32_t out[4]; - for (int i = 0; i < 4; i++) { - out[i] = (i == index) ? memoryData[0].get() : vt[i]; - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1i64: { // ld1 {vt.d}[index], [xn] - // LOAD - const int index = metadata.operands[0].vector_index; - const uint64_t* vt = operands[0].getAsVector(); - uint64_t out[2]; - for (int i = 0; i < 2; i++) { - out[i] = (i == index) ? memoryData[0].get() : vt[i]; - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LD1i64_POST: { // ld1 {vt.d}[index], [xn], #8 - // LOAD - const int index = metadata.operands[0].vector_index; - const uint64_t* vt = operands[0].getAsVector(); - uint64_t out[2]; - for (int i = 0; i < 2; i++) { - out[i] = (i == index) ? memoryData[0].get() : vt[i]; - } - results[0] = {out, 256}; - results[1] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LD1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD1i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2D: // ld2d {zt1.d, zt2.d}, pg/z, [, xm, - // lsl #3] - case Opcode::AArch64_LD2D_IMM: { // ld2d {zt1.d, zt2.d}, pg/z, [{, - // #imm, mul vl}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - uint64_t out1[32] = {0}; - uint64_t out2[32] = {0}; - - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out1[i] = memoryData[index].get(); - index++; - out2[i] = memoryData[index].get(); - index++; - } else { - out1[i] = 0; - out2[i] = 0; - } - } - results[0] = {out1, 256}; - results[1] = {out2, 256}; - break; - } - case Opcode::AArch64_LD2H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Rv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov4s: { - return executionNYI(); - 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 = operands[3].get(); - } - results[2] = operands[2].get() + offset; - break; - } - case Opcode::AArch64_LD2Twov8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2Twov8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2W: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i64_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD2i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3D_IMM: { // ld3d {zt1.d, zt2.d, zt3.d}, pg/z, - // [xn|sp{, #imm, MUL VL}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - uint64_t out1[32] = {0}; - uint64_t out2[32] = {0}; - uint64_t out3[32] = {0}; - - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out1[i] = memoryData[index].get(); - index++; - out2[i] = memoryData[index].get(); - index++; - out3[i] = memoryData[index].get(); - index++; - } else { - out1[i] = 0; - out2[i] = 0; - out3[i] = 0; - } - } - results[0] = {out1, 256}; - results[1] = {out2, 256}; - results[2] = {out3, 256}; - break; - } - case Opcode::AArch64_LD3H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Rv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3Threev8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3W: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i64_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD3i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4D_IMM: { // ld4d {zt1.d, zt2.d, zt3.d, zt4.d}, - // pg/z, [xn|sp{, #imm, MUL VL}] - // LOAD - const uint64_t* p = operands[0].getAsVector(); - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - uint64_t out1[32] = {0}; - uint64_t out2[32] = {0}; - uint64_t out3[32] = {0}; - uint64_t out4[32] = {0}; - - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - out1[i] = memoryData[index].get(); - index++; - out2[i] = memoryData[index].get(); - index++; - out3[i] = memoryData[index].get(); - index++; - out4[i] = memoryData[index].get(); - index++; - } else { - out1[i] = 0; - out2[i] = 0; - out3[i] = 0; - out4[i] = 0; - } - } - - results[0] = {out1, 256}; - results[1] = {out2, 256}; - results[2] = {out3, 256}; - results[3] = {out4, 256}; - break; - } - case Opcode::AArch64_LD4Fourv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Fourv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4Rv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4W: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i64_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_LD4i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDLW: // ldaddl ws, wt, [xn] - // LOAD - [[fallthrough]]; - case Opcode::AArch64_LDADDW: { // ldadd ws, wt, [xn] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - memoryData[0] = RegisterValue( - memoryData[0].get() + operands[0].get(), 4); - break; - } - case Opcode::AArch64_LDADDLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDADDX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPRW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPRX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURBi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURSBWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURSBXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURSHWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURSHXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURSWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAPURi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDARB: { // ldarb wt, [xn] - // LOAD - results[0] = memoryData[0].zeroExtend(1, 8); - break; - } - case Opcode::AArch64_LDARH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDARW: { // ldar wt, [xn] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDARX: { // ldar xt, [xn] - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LDAXPW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAXPX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAXRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAXRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDAXRW: { // ldaxr wd, [xn] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDAXRX: { // ldaxr xd, [xn] - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LDCLRAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDCLRX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDEORX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1B_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1B_H_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1B_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1B_S_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1H_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1H_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1H_S_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1SB_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1SB_H_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1SB_S_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1SH_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1SH_S_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1SW_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1W_D_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDFF1W_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDLARB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDLARH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDLARW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDLARX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1B_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1B_H_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1B_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1B_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1H_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1H_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1H_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1SB_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1SB_H_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1SB_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1SH_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1SH_S_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1SW_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1W_D_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNF1W_IMM_REAL: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNPDi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNPQi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNPSi: { // ldnp st1, st2, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 256); - results[1] = memoryData[1].zeroExtend(4, 256); - break; - } - case Opcode::AArch64_LDNPWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNPXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1B_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1B_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1D_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1D_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1H_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1H_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1W_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDNT1W_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDPDi: // ldp dt1, dt2, [xn, #imm] - case Opcode::AArch64_LDPQi: // ldp qt1, qt2, [xn, #imm] - case Opcode::AArch64_LDPSi: // ldp st1, st2, [xn, #imm] - case Opcode::AArch64_LDPWi: // ldp wt1, wt2, [xn, #imm] - case Opcode::AArch64_LDPXi: { // ldp xt1, xt2, [xn, #imm] - uint16_t regSize = - (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; - results[0] = memoryData[0].zeroExtend(dataSize_, regSize); - results[1] = memoryData[1].zeroExtend(dataSize_, regSize); - break; - } - case Opcode::AArch64_LDPDpost: // ldp dt1, dt2, [xn], #imm - case Opcode::AArch64_LDPQpost: // ldp qt1, qt2, [xn], #imm - case Opcode::AArch64_LDPSpost: // ldp st1, st2, [xn], #imm - case Opcode::AArch64_LDPWpost: // ldp wt1, wt2, [xn], #imm - case Opcode::AArch64_LDPXpost: { // ldp xt1, xt2, [xn], #imm - uint16_t regSize = - (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; - results[0] = memoryData[0].zeroExtend(dataSize_, regSize); - results[1] = memoryData[1].zeroExtend(dataSize_, regSize); - results[2] = operands[0].get() + metadata.operands[3].imm; - break; - } - case Opcode::AArch64_LDPDpre: // ldp dt1, dt2, [xn, #imm]! - case Opcode::AArch64_LDPQpre: // ldp qt1, qt2, [xn, #imm]! - case Opcode::AArch64_LDPSpre: // ldp st1, st2, [xn, #imm]! - case Opcode::AArch64_LDPWpre: // ldp wt1, wt2, [xn, #imm]! - case Opcode::AArch64_LDPXpre: { // ldp xt1, xt2, [xn, #imm]! - uint16_t regSize = - (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; - results[0] = memoryData[0].zeroExtend(dataSize_, regSize); - results[1] = memoryData[1].zeroExtend(dataSize_, regSize); - results[2] = - operands[0].get() + metadata.operands[2].mem.disp; - break; - } - case Opcode::AArch64_LDPSWi: { // ldpsw xt1, xt2, [xn {, #imm}] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - results[1] = memoryData[1].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDPSWpost: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDPSWpre: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRAAindexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRAAwriteback: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRABindexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRABwriteback: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRBBpost: { // ldrb wt, [xn], #imm - // LOAD - results[0] = memoryData[0].zeroExtend(1, 8); - results[1] = operands[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] = - operands[0].get() + metadata.operands[1].mem.disp; - break; - } - case Opcode::AArch64_LDRBBroW: { // ldrb wt, - // [xn, wm{, extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(1, 8); - break; - } - case Opcode::AArch64_LDRBBroX: { // ldrb wt, - // [xn, xm{, extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(1, 8); - break; - } - case Opcode::AArch64_LDRBBui: { // ldrb wt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(1, 8); - break; - } - case Opcode::AArch64_LDRBroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRBroX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRBui: // ldr bt, [xn, #imm] - case Opcode::AArch64_LDRDui: // ldr dt, [xn, #imm] - case Opcode::AArch64_LDRHui: // ldr ht, [xn, #imm] - case Opcode::AArch64_LDRQui: // ldr qt, [xn, #imm] - case Opcode::AArch64_LDRSui: // ldr st, [xn, #imm] - case Opcode::AArch64_LDRWui: // ldr wt, [xn, #imm] - case Opcode::AArch64_LDRXui: { // ldr xt, [xn, #imm] - uint16_t regSize = - (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; - results[0] = memoryData[0].zeroExtend(dataSize_, regSize); - break; - } - case Opcode::AArch64_LDRBpost: // ldr bt, [xn], #imm - case Opcode::AArch64_LDRDpost: // ldr dt, [xn], #imm - case Opcode::AArch64_LDRHpost: // ldr ht, [xn], #imm - case Opcode::AArch64_LDRQpost: // ldr qt, [xn], #imm - case Opcode::AArch64_LDRSpost: // ldr st, [xn], #imm - case Opcode::AArch64_LDRWpost: // ldr wt, [xn], #imm - case Opcode::AArch64_LDRXpost: { // ldr xt, [xn], #imm - uint16_t regSize = - (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; - results[0] = memoryData[0].zeroExtend(dataSize_, regSize); - results[1] = operands[0].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LDRBpre: // ldr bt, [xn, #imm]! - case Opcode::AArch64_LDRDpre: // ldr dt, [xn, #imm]! - case Opcode::AArch64_LDRHpre: // ldr ht, [xn, #imm]! - case Opcode::AArch64_LDRQpre: // ldr qt, [xn, #imm]! - case Opcode::AArch64_LDRSpre: // ldr st, [xn, #imm]! - case Opcode::AArch64_LDRWpre: // ldr wt, [xn, #imm]! - case Opcode::AArch64_LDRXpre: { // ldr xt, [xn, #imm]! - uint16_t regSize = - (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; - results[0] = memoryData[0].zeroExtend(dataSize_, regSize); - results[1] = - operands[0].get() + metadata.operands[1].mem.disp; - break; - } - case Opcode::AArch64_LDRDl: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRDroW: { // ldr dt, [xn, wm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(memoryAddresses[0].size, 256); - break; - } - case Opcode::AArch64_LDRDroX: { // ldr dt, [xn, xm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(memoryAddresses[0].size, 256); - break; - } - case Opcode::AArch64_LDRHHpost: { // ldrh wt, [xn], #imm - // LOAD - results[0] = memoryData[0].zeroExtend(2, 8); - results[1] = operands[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] = - operands[0].get() + metadata.operands[1].mem.disp; - break; - } - case Opcode::AArch64_LDRHHroW: { // ldrh wt, [xn, wm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(2, 8); - break; - } - case Opcode::AArch64_LDRHHroX: { // ldrh wt, [xn, xm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(2, 8); - break; - } - case Opcode::AArch64_LDRHHui: { // ldrh wt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(2, 8); - break; - } - case Opcode::AArch64_LDRHroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRHroX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRQl: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRQroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRQroX: { // ldr qt, [xn, xm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(16, 256); - break; - } - case Opcode::AArch64_LDRSBWpost: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBWpre: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBWroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBWroX: { // ldrsb wt, [xn, xm{, extend - // {#amount}}] - // LOAD - results[0] = - RegisterValue(static_cast(memoryData[0].get()), 4) - .zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRSBWui: { // ldrsb wt, [xn, #imm] - // LOAD - results[0] = - RegisterValue(static_cast(memoryData[0].get())) - .zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRSBXpost: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBXpre: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBXroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBXroX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSBXui: { // ldrsb xt, [xn, #imm] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDRSHWpost: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSHWpre: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSHWroW: { // ldrsh wt, [xn, wm{, extend - // {#amount}}] - // LOAD - results[0] = - RegisterValue(static_cast(memoryData[0].get()), 4) - .zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRSHWroX: { // ldrsh wt, [xn, xm{, extend - // {#amount}}] - // LOAD - results[0] = - RegisterValue(static_cast(memoryData[0].get()), 4) - .zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRSHWui: { // ldrsh wt, [xn, #imm] - // LOAD - results[0] = - RegisterValue(static_cast(memoryData[0].get()), 4) - .zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRSHXpost: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSHXpre: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSHXroW: { // ldrsh xt, [xn, wm{, extend - // {#amount}}] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDRSHXroX: { // ldrsh xt, [xn, xm{, extend - // {#amount}}] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDRSHXui: { // ldrsh xt, [xn, #imm] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDRSWl: { // ldrsw xt, #imm - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRSWpost: { // ldrsw xt, [xn], #simm - // LOAD - results[0] = static_cast(memoryData[0].get()); - results[1] = operands[0].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_LDRSWpre: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSWroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSWroX: { // ldrsw xt, [xn, xm{, extend - // {#amount}}] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDRSWui: { // ldrsw xt, [xn{, #pimm}] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDRSl: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRSroW: { // ldr st, [xn, wm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 256); - break; - } - case Opcode::AArch64_LDRSroX: { // ldr st, [xn, xm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 256); - break; - } - case Opcode::AArch64_LDRWl: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDRWroW: { // ldr wt, [xn, wm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRWroX: { // ldr wt, [xn, xm, {extend {#amount}}] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDRXl: { // ldr xt, #imm - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LDRXroW: { // ldr xt, [xn, wn{, extend {#amount}}] - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LDRXroX: { // ldr xt, [xn, xn{, extend {#amount}}] - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LDR_PXI: { // ldr pt, [xn{, #imm, mul vl}] - // LOAD - const uint64_t PL_bits = VL_bits / 8; - const uint16_t partition_num = PL_bits / 8; - - uint64_t out[4] = {0}; - for (int i = 0; i < partition_num; i++) { - uint8_t data = memoryData[i].get(); - for (int j = 0; j < 8; j++) { - out[i / 8] |= (data & (1 << j)) ? 1ull << ((j + (i * 8)) % 64) : 0; - } - } - results[0] = out; - break; - } - case Opcode::AArch64_LDR_ZXI: { // ldr zt, [xn{, #imm, mul vl}] - // LOAD - const uint16_t partition_num = VL_bits / 8; - uint8_t out[256] = {0}; - - for (int i = 0; i < partition_num; i++) { - out[i] = memoryData[i].get(); - } - results[0] = {out, 256}; - break; - } - case Opcode::AArch64_LDSETAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSETX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMAXX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDSMINX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRBi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRSBWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRSBXi: { // ldtrsb xt, [xn, #imm] - // LOAD - // TODO: implement - results[0] = RegisterValue(0, 8); - break; - } - case Opcode::AArch64_LDTRSHWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRSHXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRSWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDTRXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMAXX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDUMINX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURBBi: { // ldurb wt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(1, 8); - break; - } - case Opcode::AArch64_LDURBi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURDi: { // ldur dt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(8, 256); - break; - } - case Opcode::AArch64_LDURHHi: { // ldurh wt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(2, 8); - break; - } - case Opcode::AArch64_LDURHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURQi: { // ldur qt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(16, 256); - break; - } - case Opcode::AArch64_LDURSBWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURSBXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURSHWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURSHXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDURSWi: { // ldursw xt, [xn, #imm] - // LOAD - results[0] = static_cast(memoryData[0].get()); - break; - } - case Opcode::AArch64_LDURSi: { // ldur sd, [{, #imm}] - // LOAD - results[0] = {memoryData[0].get(), 256}; - break; - } - case Opcode::AArch64_LDURWi: { // ldur wt, [xn, #imm] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDURXi: { // ldur xt, [xn, #imm] - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LDXPW: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDXPX: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDXRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDXRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_LDXRW: { // ldxr wt, [xn] - // LOAD - results[0] = memoryData[0].zeroExtend(4, 8); - break; - } - case Opcode::AArch64_LDXRX: { // ldxr xt, [xn] - // LOAD - results[0] = memoryData[0]; - break; - } - case Opcode::AArch64_LOADgot: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSLR_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSLR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSLR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSLR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSLVWr: { // lslv wd, wn, wm - results[0] = { - logicalHelp::logicalShiftLR_3ops(operands, true), 8}; - break; - } - case Opcode::AArch64_LSLVXr: { // lslv xd, xn, xm - results[0] = logicalHelp::logicalShiftLR_3ops(operands, true); - break; - } - case Opcode::AArch64_LSL_WIDE_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_WIDE_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_WIDE_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_WIDE_ZZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_WIDE_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_WIDE_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSL_ZZI_S: { // lsl zd.s, zn.s, #imm - results[0] = sveHelp::sveLsl_imm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_LSRR_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSRR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSRR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSRR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSRVWr: { // lsrv wd, wn, wm - results[0] = { - logicalHelp::logicalShiftLR_3ops(operands, false), 8}; - break; - } - case Opcode::AArch64_LSRVXr: { // lsrv xd, xn, xm - results[0] = - logicalHelp::logicalShiftLR_3ops(operands, false); - break; - } - case Opcode::AArch64_LSR_WIDE_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_WIDE_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_WIDE_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_WIDE_ZZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_WIDE_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_WIDE_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_LSR_ZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_MADDWrrr: { // madd wd, wn, wm, wa - results[0] = {multiplyHelp::madd_4ops(operands), 8}; - break; - } - case Opcode::AArch64_MADDXrrr: { // madd xd, xn, xm, xa - results[0] = multiplyHelp::madd_4ops(operands); - break; - } - case Opcode::AArch64_MAD_ZPmZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_MAD_ZPmZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_MAD_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_MAD_ZPmZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLA_ZPmZZ_B: { // mla zda.b, pg/m, zn.b, zm.b - results[0] = sveHelp::sveMlaPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_MLA_ZPmZZ_D: { // mla zda.d, pg/m, zn.d, zm.d - results[0] = - sveHelp::sveMlaPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_MLA_ZPmZZ_H: { // mla zda.h, pg/m, zn.h, zm.h - results[0] = - sveHelp::sveMlaPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_MLA_ZPmZZ_S: { // mla zda.s, pg/m, zn.s, zm.s - results[0] = - sveHelp::sveMlaPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_MLAv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLAv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLS_ZPmZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLS_ZPmZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLS_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLS_ZPmZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MLSv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVID: { // movi dd, #imm - results[0] = {static_cast(metadata.operands[1].imm), 256}; - break; - } - case Opcode::AArch64_MOVIv16b_ns: { // movi vd.16b, #imm - results[0] = neonHelp::vecMovi_imm(metadata); - break; - } - case Opcode::AArch64_MOVIv2d_ns: { // movi vd.2d, #imm - results[0] = neonHelp::vecMovi_imm(metadata); - break; - } - case Opcode::AArch64_MOVIv2i32: { // movi vd.2s, #imm{, lsl #shift} - results[0] = neonHelp::vecMoviShift_imm(metadata, false); - break; - } - case Opcode::AArch64_MOVIv2s_msl: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVIv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVIv4i32: { // movi vd.4s, #imm{, LSL #shift} - results[0] = neonHelp::vecMoviShift_imm(metadata, false); - break; - } - case Opcode::AArch64_MOVIv4s_msl: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVIv8b_ns: { // movi vd.8b, #imm - results[0] = neonHelp::vecMovi_imm(metadata); - break; - } - case Opcode::AArch64_MOVIv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVKWi: { // movk wd, #imm - results[0] = { - arithmeticHelp::movkShift_imm(operands, metadata), 8}; - break; - } - case Opcode::AArch64_MOVKXi: { // movk xd, #imm - results[0] = - arithmeticHelp::movkShift_imm(operands, metadata); - break; - } - case Opcode::AArch64_MOVNWi: { // movn wd, #imm{, LSL #shift} - results[0] = {arithmeticHelp::movnShift_imm( - metadata, [](uint64_t x) -> uint32_t { return ~x; }), - 8}; - break; - } - case Opcode::AArch64_MOVNXi: { // movn xd, #imm{, LSL #shift} - results[0] = arithmeticHelp::movnShift_imm( - metadata, [](uint64_t x) -> uint64_t { return ~x; }); - break; - } - case Opcode::AArch64_MOVPRFX_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVPRFX_ZPmZ_D: { // movprfx zd.d, pg/m, zn.d - results[0] = sveHelp::sveMovprfxPredicated_destUnchanged( - operands, VL_bits); - break; - } - case Opcode::AArch64_MOVPRFX_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVPRFX_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVPRFX_ZPzZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVPRFX_ZPzZ_D: { // movprfx zd.d, pg/z, zn.d - results[0] = sveHelp::sveMovprfxPredicated_destToZero( - operands, VL_bits); - break; - } - case Opcode::AArch64_MOVPRFX_ZPzZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVPRFX_ZPzZ_S: { // movprfx zd.s, pg/z, zn.s - results[0] = sveHelp::sveMovprfxPredicated_destToZero( - operands, VL_bits); - break; - } - case Opcode::AArch64_MOVPRFX_ZZ: { // movprfx zd, zn - // TODO: Adopt hint logic of the MOVPRFX instruction - results[0] = operands[0]; - break; - } - case Opcode::AArch64_MOVZWi: { // movz wd, #imm - results[0] = {arithmeticHelp::movnShift_imm( - metadata, [](uint64_t x) -> uint32_t { return x; }), - 8}; - break; - } - case Opcode::AArch64_MOVZXi: { // movz xd, #imm - results[0] = arithmeticHelp::movnShift_imm( - metadata, [](uint64_t x) -> uint64_t { return x; }); - break; - } - case Opcode::AArch64_MOVaddr: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVaddrBA: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVaddrCP: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVaddrEXT: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVaddrJT: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVaddrTLS: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVbaseTLS: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVi32imm: { - return executionNYI(); - break; - } - case Opcode::AArch64_MOVi64imm: { - return executionNYI(); - break; - } - case Opcode::AArch64_MRS: { // mrs xt, (systemreg|Sop0_op1_Cn_Cm_op2) - results[0] = operands[0]; - break; - } - case Opcode::AArch64_MSB_ZPmZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_MSB_ZPmZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_MSB_ZPmZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_MSB_ZPmZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_MSR: { // mrs (systemreg|Sop0_op1_Cn_Cm_op2), xt - results[0] = operands[0]; - break; - } - case Opcode::AArch64_MSRpstateImm1: { - return executionNYI(); - break; - } - case Opcode::AArch64_MSRpstateImm4: { - return executionNYI(); - break; - } - case Opcode::AArch64_MSUBWrrr: { // msub wd, wn, wm, wa - results[0] = {multiplyHelp::msub_4ops(operands), 8}; - break; - } - case Opcode::AArch64_MSUBXrrr: { // msub xd, xn, xm, xa - results[0] = multiplyHelp::msub_4ops(operands); - break; - } - case Opcode::AArch64_MUL_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_MUL_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_MUL_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_MUL_ZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_MUL_ZPmZ_B: { // mul zdn.b, pg/m, zdn.b, zm.b - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_MUL_ZPmZ_D: { // mul zdn.d, pg/m, zdn.d, zm.d - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_MUL_ZPmZ_H: { // mul zdn.h, pg/m, zdn.h, zm.h - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_MUL_ZPmZ_S: { // mul zdn.s, pg/m, zdn.s, zm.s - results[0] = sveHelp::sveMulPredicated(operands, metadata, - VL_bits, false); - break; - } - case Opcode::AArch64_MULv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_MULv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_MVNIv2i32: { // mvni vd.2s, #imm{, lsl #shift} - results[0] = neonHelp::vecMoviShift_imm(metadata, true); - break; - } - case Opcode::AArch64_MVNIv2s_msl: { - return executionNYI(); - break; - } - case Opcode::AArch64_MVNIv4i16: { // mvni vd.4h, #imm{, lsl #shift} - results[0] = neonHelp::vecMoviShift_imm(metadata, true); - break; - } - case Opcode::AArch64_MVNIv4i32: { // mvni vd.4s, #imm{, lsl #shift} - results[0] = neonHelp::vecMoviShift_imm(metadata, true); - break; - } - case Opcode::AArch64_MVNIv4s_msl: { - return executionNYI(); - break; - } - case Opcode::AArch64_MVNIv8i16: { // mvni vd.8h, #imm{, lsl #shift} - results[0] = neonHelp::vecMoviShift_imm(metadata, true); - break; - } - case Opcode::AArch64_NANDS_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_NAND_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEG_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEG_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEG_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEG_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv2i64: { // neg vd.2d, vn.2d - results[0] = neonHelp::vecFneg_2ops(operands); - break; - } - case Opcode::AArch64_NEGv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_NEGv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_NORS_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_NOR_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_NOT_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_NOT_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_NOT_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_NOT_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_NOTv16i8: { // not vd.16b, vn.16b - results[0] = neonHelp::vecLogicOp_2vecs( - operands, [](uint8_t x) -> uint8_t { return ~x; }); - break; - } - case Opcode::AArch64_NOTv8i8: { // not vd.8b, vn.8b - results[0] = neonHelp::vecLogicOp_2vecs( - operands, [](uint8_t x) -> uint8_t { return ~x; }); - break; - } - case Opcode::AArch64_ORNS_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORNWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORNWrs: { // orn wd, wn, wm{, shift{ #amount}} - auto [result, nzcv] = logicalHelp::logicOpShift_3ops( - operands, metadata, false, - [](uint32_t x, uint32_t y) -> uint32_t { return x | (~y); }); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_ORNXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORNXrs: { // orn xd, xn, xm{, shift{ #amount}} - auto [result, nzcv] = logicalHelp::logicOpShift_3ops( - operands, metadata, false, - [](uint64_t x, uint64_t y) -> uint64_t { return x | (~y); }); - results[0] = result; - break; - } - case Opcode::AArch64_ORN_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORNv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORNv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRS_PPzPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRWri: { // orr wd, wn, #imm - auto [result, nzcv] = logicalHelp::logicOp_imm( - operands, metadata, false, - [](uint32_t x, uint32_t y) -> uint32_t { return x | y; }); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_ORRWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRWrs: { // orr wd, wn, wm{, shift{ #amount}} - results[0] = { - comparisonHelp::orrShift_3ops(operands, metadata), 8}; - break; - } - case Opcode::AArch64_ORRXri: { // orr xd, xn, #imm - auto [result, nzcv] = logicalHelp::logicOp_imm( - operands, metadata, false, - [](uint64_t x, uint64_t y) -> uint64_t { return x | y; }); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_ORRXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRXrs: { // orr xd, xn, xm{, shift{ #amount}} - results[0] = - comparisonHelp::orrShift_3ops(operands, metadata); - break; - } - case Opcode::AArch64_ORR_PPzPP: { // orr pd.b, pg/z, pn.b, pm.b - results[0] = sveHelp::sveLogicOp_preds( - operands, VL_bits, - [](uint64_t x, uint64_t y) -> uint64_t { return x | y; }); - break; - } - case Opcode::AArch64_ORR_ZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORR_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORR_ZZZ: { // orr zd.d, zn.d, zm.d - results[0] = sveHelp::sveOrr_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_ORRv16i8: { // orr vd.16b, Vn.16b, Vm.16b - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint8_t x, uint8_t y) -> uint8_t { return x | y; }); - break; - } - case Opcode::AArch64_ORRv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORRv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORV_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ORV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACDA: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACDB: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACDZA: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACDZB: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACGA: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIA: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIA1716: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIASP: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIAZ: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIB: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIB1716: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIBSP: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIBZ: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIZA: { - return executionNYI(); - break; - } - case Opcode::AArch64_PACIZB: { - return executionNYI(); - break; - } - case Opcode::AArch64_PFALSE: { // pfalse pd.b - uint64_t out[4] = {0, 0, 0, 0}; - results[0] = out; - break; - } - case Opcode::AArch64_PMULLv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_PMULLv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_PMULLv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_PMULLv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_PMULv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_PMULv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_PNEXT_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_PNEXT_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_PNEXT_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_PNEXT_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_D_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_D_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_PRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_PRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_S_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_S_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFB_S_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_D_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_D_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_PRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_PRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_S_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_S_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFD_S_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_D_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_D_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_PRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_PRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_S_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_S_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFH_S_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFMl: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFMroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFMroX: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFMui: { // prfm op, [xn, xm{, extend{, #amount}}] - break; - } - case Opcode::AArch64_PRFS_PRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFUMi: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_D_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_D_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_PRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_S_PZI: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_S_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PRFW_S_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_PTEST_PP: { // ptest pg, pn.b - const uint64_t* g = operands[0].getAsVector(); - const uint64_t* s = operands[1].getAsVector(); - std::array masked_n = {(g[0] & s[0]), (g[1] & s[1]), - (g[2] & s[2]), (g[3] & s[3])}; - // Byte count = 1 as destination predicate is regarding single bytes. - results[0] = AuxFunc::getNZCVfromPred(masked_n, VL_bits, 1); - break; - } - case Opcode::AArch64_PTRUES_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_PTRUES_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_PTRUES_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_PTRUES_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_PTRUE_B: { // ptrue pd.b{, pattern} - results[0] = sveHelp::svePtrue(metadata, VL_bits); - break; - } - case Opcode::AArch64_PTRUE_D: { // ptrue pd.d{, pattern} - results[0] = sveHelp::svePtrue(metadata, VL_bits); - break; - } - case Opcode::AArch64_PTRUE_H: { // ptrue pd.h{, pattern} - results[0] = sveHelp::svePtrue(metadata, VL_bits); - break; - } - case Opcode::AArch64_PTRUE_S: { // ptrue pd.s{, pattern} - results[0] = sveHelp::svePtrue(metadata, VL_bits); - break; - } - case Opcode::AArch64_PUNPKHI_PP: { // punpkhi pd.h, pn.b - results[0] = sveHelp::svePunpk(operands, VL_bits, true); - break; - } - case Opcode::AArch64_PUNPKLO_PP: { // punpklo pd.h, pn.b - results[0] = sveHelp::svePunpk(operands, VL_bits, false); - break; - } - case Opcode::AArch64_RADDHNv2i64_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_RADDHNv2i64_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_RADDHNv4i32_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_RADDHNv4i32_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_RADDHNv8i16_v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_RADDHNv8i16_v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_RAX1: { - return executionNYI(); - break; - } - case Opcode::AArch64_RBITWr: { // rbit wd, wn - results[0] = {bitmanipHelp::rbit(operands, metadata), 8}; - break; - } - case Opcode::AArch64_RBITXr: { // rbit xd, xn - results[0] = bitmanipHelp::rbit(operands, metadata); - break; - } - case Opcode::AArch64_RBIT_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_RBIT_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_RBIT_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_RBIT_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_RBITv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_RBITv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_RDFFRS_PPz: { - return executionNYI(); - break; - } - case Opcode::AArch64_RDFFR_P: { - return executionNYI(); - break; - } - case Opcode::AArch64_RDFFR_PPz: { - return executionNYI(); - break; - } - case Opcode::AArch64_RDVLI_XI: { // rdvl xd, #imm - int8_t imm = static_cast(metadata.operands[1].imm); - results[0] = (uint64_t)(imm * (VL_bits / 8)); - break; - } - case Opcode::AArch64_RET: { // ret {xr} - branchTaken_ = true; - branchAddress_ = operands[0].get(); - break; - } - case Opcode::AArch64_RETAA: { - return executionNYI(); - break; - } - case Opcode::AArch64_RETAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_RET_ReallyLR: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV16Wr: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV16Xr: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV16v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV16v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV32Xr: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV32v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV32v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV32v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV32v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV64v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV64v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV64v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV64v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV64v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_REV64v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVB_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVB_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVB_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVH_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVH_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVW_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVWr: { - return executionNYI(); - break; - } - case Opcode::AArch64_REVXr: { // rev xd, xn - results[0] = bitmanipHelp::rev(operands); - break; - } - case Opcode::AArch64_REV_PP_B: { // rev pd.b, pn.b - results[0] = sveHelp::sveRev_predicates(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_PP_D: { // rev pd.d, pn.d - results[0] = sveHelp::sveRev_predicates(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_PP_H: { // rev pd.h, pn.h - results[0] = sveHelp::sveRev_predicates(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_PP_S: { // rev pd.s, pn.s - results[0] = sveHelp::sveRev_predicates(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_ZZ_B: { // rev zd.b, zn.b - results[0] = sveHelp::sveRev_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_ZZ_D: { // rev zd.d, zn.d - results[0] = sveHelp::sveRev_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_ZZ_H: { // rev zd.h, zn.h - results[0] = sveHelp::sveRev_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_REV_ZZ_S: { // rev zd.s, zn.s - results[0] = sveHelp::sveRev_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_RMIF: { - return executionNYI(); - break; - } - case Opcode::AArch64_RORVWr: { // rorv wd, wn, wm - results[0] = {logicalHelp::rorv_3ops(operands), 8}; - break; - } - case Opcode::AArch64_RORVXr: { // rorv xd, xn, xm - results[0] = logicalHelp::rorv_3ops(operands); - break; - } - case Opcode::AArch64_RSHRNv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSHRNv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSHRNv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSHRNv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSHRNv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSHRNv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSUBHNv2i64_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSUBHNv2i64_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSUBHNv4i32_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSUBHNv4i32_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSUBHNv8i16_v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_RSUBHNv8i16_v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABALv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABALv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABALv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABALv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABALv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABALv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABAv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABAv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABAv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABAv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABAv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABAv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABD_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABD_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABD_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABD_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SABDv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADALPv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADALPv2i32_v1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADALPv4i16_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADALPv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADALPv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADALPv8i8_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLPv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLPv2i32_v1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLPv4i16_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLPv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLPv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLPv8i8_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLVv16i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLVv8i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDV_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDWv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDWv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDWv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDWv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDWv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SADDWv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SBCSWr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SBCSXr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SBCWr: { // sbc wd, wn, wm - results[0] = {arithmeticHelp::sbc(operands), 8}; - break; - } - case Opcode::AArch64_SBCXr: { // sbc xd, xn, xm - results[0] = arithmeticHelp::sbc(operands); - break; - } - case Opcode::AArch64_SBFMWri: { // sbfm wd, wn, #immr, #imms - results[0] = { - bitmanipHelp::bfm_2imms(operands, metadata, true, true), - 8}; - break; - } - case Opcode::AArch64_SBFMXri: { // sbfm xd, xn, #immr, #imms - results[0] = - bitmanipHelp::bfm_2imms(operands, metadata, true, true); - break; - } - case Opcode::AArch64_SCVTFSWDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFSWHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFSWSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFSXDri: { // scvtf dd, xn, #fbits - results[0] = - floatHelp::scvtf_FixedPoint(operands, metadata); - break; - } - case Opcode::AArch64_SCVTFSXHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFSXSri: { // scvtf sd, xn, #fbits - results[0] = - floatHelp::scvtf_FixedPoint(operands, metadata); - break; - } - case Opcode::AArch64_SCVTFUWDri: { // scvtf dd, wn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_SCVTFUWHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFUWSri: { // scvtf sd, wn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_SCVTFUXDri: { // scvtf dd, xn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_SCVTFUXHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFUXSri: { // scvtf sd, xn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_DtoD: { // scvtf zd.d, pg/m, zn.d - results[0] = - sveHelp::sveFcvtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_DtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_DtoS: { // scvtf zd.s, pg/m, zn.d - results[0] = - sveHelp::sveFcvtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_HtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_StoD: { // scvtf zd.d, pg/m, zn.s - results[0] = - sveHelp::sveFcvtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_StoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTF_ZPmZ_StoS: { // scvtf zd.s, pg/m, zn.s - results[0] = - sveHelp::sveFcvtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SCVTFd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv1i32: { // scvtf sd, sn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_SCVTFv1i64: { // scvtf dd, dn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_SCVTFv2f32: { // scvtf vd.2s, vn.2s - results[0] = neonHelp::vecScvtf_2vecs( - operands, [](int32_t x) -> float { return static_cast(x); }); - break; - } - case Opcode::AArch64_SCVTFv2f64: { // scvtf vd.2d, vn.2d - results[0] = neonHelp::vecScvtf_2vecs( - operands, - [](int64_t x) -> double { return static_cast(x); }); - break; - } - case Opcode::AArch64_SCVTFv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv4f32: { // scvtf vd.4s, vn.4s - results[0] = neonHelp::vecScvtf_2vecs( - operands, [](int32_t x) -> float { return static_cast(x); }); - break; - } - case Opcode::AArch64_SCVTFv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SCVTFv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDIVR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDIVR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDIVWr: { // sdiv wd, wn, wm - results[0] = {divideHelp::div_3ops(operands), 8}; - break; - } - case Opcode::AArch64_SDIVXr: { // sdiv xd, xn, xm - results[0] = {divideHelp::div_3ops(operands), 8}; - break; - } - case Opcode::AArch64_SDIV_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDIV_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOT_ZZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOT_ZZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOT_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOT_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOTlanev16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOTlanev8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOTv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SDOTv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SEL_PPPP: { - return executionNYI(); - break; - } - case Opcode::AArch64_SEL_ZPZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SEL_ZPZZ_D: { // sel zd.d, pg, zn.d, zm.d - results[0] = sveHelp::sveSel_zpzz(operands, VL_bits); - break; - } - case Opcode::AArch64_SEL_ZPZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SEL_ZPZZ_S: { // sel zd.s, pg, zn.s, zm.s - results[0] = sveHelp::sveSel_zpzz(operands, VL_bits); - break; - } - case Opcode::AArch64_SETF16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SETF8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SETFFR: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA1Crrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA1Hrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA1Mrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA1Prrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA1SU0rrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA1SU1rr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA256H2rrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA256Hrrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA256SU0rr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA256SU1rrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA512H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA512H2: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA512SU0: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHA512SU1: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHADDv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHADDv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHADDv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHADDv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHADDv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHADDv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLLv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLLv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLLv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLLv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLLv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLLv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLd: { // shl dd, dn #imm - results[0] = - neonHelp::vecShlShift_vecImm(operands, metadata); - break; - } - case Opcode::AArch64_SHLv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLv4i32_shift: { // shl vd.4s, vn.4s, #imm - results[0] = - neonHelp::vecShlShift_vecImm(operands, metadata); - break; - } - case Opcode::AArch64_SHLv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHLv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHRNv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHRNv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHRNv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHRNv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHRNv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHRNv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHSUBv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHSUBv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHSUBv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHSUBv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHSUBv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SHSUBv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLId: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SLIv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3PARTW1: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3PARTW2: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3SS1: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3TT1A: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3TT1B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3TT2A: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM3TT2B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM4E: { - return executionNYI(); - break; - } - case Opcode::AArch64_SM4ENCKEY: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMADDLrrr: { // smaddl xd, wn, wm, xa - results[0] = multiplyHelp::maddl_4ops(operands); - break; - } - case Opcode::AArch64_SMAXPv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXPv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXPv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXPv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXPv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXPv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXV_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXV_VPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXVv16i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXVv8i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZI_S: { // smax zdn.s, zdn.s, #imm - results[0] = - sveHelp::sveMax_vecImm(operands, metadata, VL_bits); - break; - } - case Opcode::AArch64_SMAX_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAX_ZPmZ_S: { // smax zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveMaxPredicated_vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_SMAXv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXv4i32: { // smax vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, - [](int32_t x, int32_t y) -> int32_t { return std::max(x, y); }); - break; - } - case Opcode::AArch64_SMAXv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMAXv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMC: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINPv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINPv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINPv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINPv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINPv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINPv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINV_VPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINV_VPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINV_VPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINV_VPZ_S: { // sminv sd, pg, zn.s - results[0] = sveHelp::sveSminv(operands, VL_bits); - break; - } - case Opcode::AArch64_SMINVv16i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINVv4i32v: { // sminv sd, vn.4s - results[0] = neonHelp::vecMinv_2ops(operands); - break; - } - case Opcode::AArch64_SMINVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINVv8i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMIN_ZPmZ_S: { // smin zd.s, pg/m, zn.s, zm.s - results[0] = sveHelp::sveLogicOpPredicated_3vecs( - operands, VL_bits, - [](int32_t x, int32_t y) -> int32_t { return std::min(x, y); }); - break; - } - case Opcode::AArch64_SMINv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINv4i32: { // smin vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, - [](int32_t x, int32_t y) -> int32_t { return std::min(x, y); }); - break; - } - case Opcode::AArch64_SMINv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMINv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLALv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMLSLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMOVvi16to32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMOVvi16to64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMOVvi32to64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMOVvi8to32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMOVvi8to64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMSUBLrrr: { // smsubl xd, wn, wm, xa - results[0] = arithmeticHelp::msubl_4ops(operands); - break; - } - case Opcode::AArch64_SMULH_ZPmZ_B: { // smulh zdn.b, pg/m, zdn.b, zm.b - results[0] = - sveHelp::sveMulhPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SMULH_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULH_ZPmZ_H: { // smulh zdn.h, pg/m, zdn.h, zm.h - results[0] = - sveHelp::sveMulhPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SMULH_ZPmZ_S: { // smulh zdn.s, pg/m, zdn.s, zm.s - results[0] = - sveHelp::sveMulhPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SMULHrr: { // smulh xd, xn, xm - // TODO: signed - results[0] = AuxFunc::mulhi(operands[0].get(), - operands[1].get()); - break; - } - case Opcode::AArch64_SMULLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SMULLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SPLICE_ZPZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SPLICE_ZPZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SPLICE_ZPZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SPLICE_ZPZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQABSv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADD_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQADDv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECB_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECB_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECD_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECD_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECD_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECH_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECH_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECH_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XPWd_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XPWd_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XPWd_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XPWd_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XP_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_XP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_ZP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_ZP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECP_ZP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECW_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECW_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDECW_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALi16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALi32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv1i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLALv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLi16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLi32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv1i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMLSLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv1i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULHv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLi16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLi32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv1i64_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQDMULLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCB_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCB_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCD_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCD_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCD_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCH_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCH_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCH_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XPWd_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XPWd_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XPWd_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XPWd_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XP_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_XP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_ZP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_ZP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCP_ZP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCW_XPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCW_XPiWdI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQINCW_ZPiI: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQNEGv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHi16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHi32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLAHv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHi16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHi32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMLSHv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv1i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv1i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv2i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv4i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv4i32_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRDMULHv8i16_indexed: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHLv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNb: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRNv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNb: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQRSHRUNv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUb: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLUv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLb: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHLv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNb: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRNv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNb: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNh: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNs: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSHRUNv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUB_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQSUBv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTNv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SQXTUNv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRHADDv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRHADDv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRHADDv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRHADDv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRHADDv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRHADDv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRId: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRIv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHLv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSHRv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SRSRAv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLLv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLLv2i32_shift: { // sshll vd.2d, vn.2s, #imm - results[0] = neonHelp::vecShllShift_vecImm( - operands, metadata, false); - break; - } - case Opcode::AArch64_SSHLLv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLLv4i32_shift: { // sshll2 vd.2d, vn.4s, #imm - results[0] = neonHelp::vecShllShift_vecImm( - operands, metadata, true); - break; - } - case Opcode::AArch64_SSHLLv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLLv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHLv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRv4i32_shift: { // sshr vd.4s, vn.4s, #imm - results[0] = neonHelp::vecSshrShift_imm(operands, metadata); - break; - } - case Opcode::AArch64_SSHRv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSHRv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAd: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv16i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSRAv8i8_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1B_D: { // st1b {zd.d}, pg, [xn, zm.d] - // STORE - const uint64_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = static_cast(d[i]); - index++; - } - } - break; - } - case Opcode::AArch64_SST1B_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1B_D_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1B_D_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1B_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1B_S_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1B_S_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1D: { // st1d {zt.d}, pg, [xn, zm.d] - // STORE - const uint64_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_SST1D_IMM: { // st1d {zd.d}, pg, [zn.d{, #imm}] - // STORE - const uint64_t* t = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = t[i]; - index++; - } - } - break; - } - case Opcode::AArch64_SST1D_SCALED: { // st1d {zt.d}, pg, [xn, zm.d, lsl # - // 3] - // STORE - const uint64_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_SST1D_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1D_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_S_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_S_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_S_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1H_S_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_D_IMM: { // st1w {zt.d}, pg, [zn.d{, #imm}] - // STORE - const uint64_t* t = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = t[i]; - index++; - } - } - break; - } - case Opcode::AArch64_SST1W_D_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_D_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_D_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_D_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_D_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_IMM: { // st1w {zt.s}, pg, [zn.s{, #imm}] - // STORE - const uint32_t* t = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 32; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 16) * 4); - if (p[i / 16] & shifted_active) { - memoryData[index] = t[i]; - index++; - } - } - break; - } - case Opcode::AArch64_SST1W_SXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_SXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_UXTW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SST1W_UXTW_SCALED: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBWv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBWv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBWv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBWv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBWv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SSUBWv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B: { // st1b {zt.b}, pg, [xn, xm] - // STORE - const uint8_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 8; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << (i % 64); - if (p[i / 64] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_ST1B_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B_H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1B_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1D: { // st1d {zt.d}, pg, [xn, xm, lsl #3] - // STORE - const uint64_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_ST1D_IMM: { // st1d {zt.d}, pg, [xn{, #imm, mul vl}] - // STORE - const uint64_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_ST1Fourv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Fourv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1H_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1H_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1H_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1H_S_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Onev8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Threev8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov16b: { // st1v {vt.16b, vt2.16b}, [xn] - // STORE - const uint8_t* t = operands[0].getAsVector(); - const uint8_t* t2 = operands[1].getAsVector(); - for (int i = 0; i < 16; i++) { - memoryData[i] = t[i]; - } - for (int i = 0; i < 16; i++) { - memoryData[i + 16] = t2[i]; - } - break; - } - case Opcode::AArch64_ST1Twov16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov1d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov1d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1Twov8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1W: { // st1w {zt.s}, pg, [xn, xm, lsl #2] - // STORE - const uint32_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 32; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 16) * 4); - if (p[i / 16] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_ST1W_D: { // st1w {zt.d}, pg, [xn, xm, lsl #2] - // STORE - const uint64_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = static_cast(d[i]); - index++; - } - } - break; - } - case Opcode::AArch64_ST1W_D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST1W_IMM: { // st1w {zt.s}, pg, [xn{, #imm, mul vl}] - // STORE - const uint32_t* d = operands[0].getAsVector(); - const uint64_t* p = operands[1].getAsVector(); - - const uint16_t partition_num = VL_bits / 32; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 16) * 4); - if (p[i / 16] & shifted_active) { - memoryData[index] = d[i]; - index++; - } - } - break; - } - case Opcode::AArch64_ST1i16: { // st1 {vt.h}[index], [xn] - // STORE - const uint16_t* t = operands[0].getAsVector(); - 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 - // STORE - const uint16_t* t = operands[0].getAsVector(); - memoryData[0] = t[metadata.operands[0].vector_index]; - uint64_t offset = 2; - if (metadata.operandCount == 3) { - offset = operands[2].get(); - } - results[0] = operands[1].get() + offset; - break; - } - case Opcode::AArch64_ST1i32: { // st1 {vt.s}[index], [xn] - // STORE - const uint32_t* t = operands[0].getAsVector(); - 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 - // STORE - const uint32_t* t = operands[0].getAsVector(); - memoryData[0] = t[metadata.operands[0].vector_index]; - uint64_t offset = 4; - if (metadata.operandCount == 3) { - offset = operands[2].get(); - } - results[0] = operands[1].get() + offset; - break; - } - case Opcode::AArch64_ST1i64: { // st1 {vt.d}[index], [xn] - // STORE - const uint64_t* t = operands[0].getAsVector(); - 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 - // STORE - const uint64_t* t = operands[0].getAsVector(); - memoryData[0] = t[metadata.operands[0].vector_index]; - uint64_t offset = 8; - if (metadata.operandCount == 3) { - offset = operands[2].get(); - } - results[0] = operands[1].get() + offset; - break; - } - case Opcode::AArch64_ST1i8: { // st1 {vt.b}[index], [xn] - // STORE - const uint8_t* t = operands[0].getAsVector(); - 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 - // STORE - const uint8_t* t = operands[0].getAsVector(); - memoryData[0] = t[metadata.operands[0].vector_index]; - uint64_t offset = 1; - if (metadata.operandCount == 3) { - offset = operands[2].get(); - } - results[0] = RegisterValue(operands[1].get() + offset, 8); - break; - } - case Opcode::AArch64_ST2B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2D_IMM: { // st2d {zt1.d, zt2.d}, pg, [{, - // #imm, mul vl}] - // STORE - const uint64_t* d1 = operands[0].getAsVector(); - const uint64_t* d2 = operands[1].getAsVector(); - const uint64_t* p = operands[2].getAsVector(); - - const uint16_t partition_num = VL_bits / 64; - uint16_t index = 0; - for (int i = 0; i < partition_num; i++) { - uint64_t shifted_active = 1ull << ((i % 8) * 8); - if (p[i / 8] & shifted_active) { - memoryData[index] = d1[i]; - index++; - memoryData[index] = d2[i]; - index++; - } - } - break; - } - case Opcode::AArch64_ST2H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov4s_POST: { // st2 {vt1.4s, vt2.4s}, [xn], - // #imm - // STORE - const float* t1 = operands[0].getAsVector(); - const float* t2 = operands[1].getAsVector(); - for (int i = 0; i < 4; i++) { - memoryData[2 * i] = t1[i]; - memoryData[2 * i + 1] = t2[i]; - } - uint64_t offset = 32; - if (metadata.operandCount == 4) { - offset = operands[3].get(); - } - results[0] = operands[2].get() + offset; - break; - } - case Opcode::AArch64_ST2Twov8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2Twov8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2W: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i64_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST2i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3Threev8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3W: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i64_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST3i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4B: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4B_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4D: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4D_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv16b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv16b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv2d: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv2d_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv2s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv2s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv4h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv4h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv4s: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv4s_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv8b: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv8b_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv8h: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4Fourv8h_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4H: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4H_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4W: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4W_IMM: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i16_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i32_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i64_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ST4i8_POST: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLLRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLLRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLLRW: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLLRX: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLRB: { // stlrb wt, [xn] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STLRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLRW: // stlr wt, [xn] - case Opcode::AArch64_STLRX: { // stlr xt, [xn] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STLURBi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLURHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLURWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLURXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLXPW: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLXPX: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLXRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLXRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_STLXRW: // stlxr ws, wt, [xn] - case Opcode::AArch64_STLXRX: { // stlxr ws, xt, [xn] - // STORE - memoryData[0] = operands[0]; - // TODO: Implement atomic memory access - results[0] = static_cast(0); - break; - } - case Opcode::AArch64_STNPDi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNPQi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNPSi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNPWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNPXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1B_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1B_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1D_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1D_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1H_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1H_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1W_ZRI: { - return executionNYI(); - break; - } - case Opcode::AArch64_STNT1W_ZRR: { - return executionNYI(); - break; - } - case Opcode::AArch64_STPDi: // stp dt1, dt2, [xn, #imm] - case Opcode::AArch64_STPQi: // stp qt1, qt2, [xn, #imm] - case Opcode::AArch64_STPSi: // stp st1, st2, [xn, #imm] - case Opcode::AArch64_STPWi: // stp wt1, wt2, [xn, #imm] - case Opcode::AArch64_STPXi: { // stp xt1, xt2, [xn, #imm] - memoryData[0] = operands[0]; - memoryData[1] = operands[1]; - break; - } - case Opcode::AArch64_STPDpost: // stp dt1, dt2, [xn], #imm - case Opcode::AArch64_STPQpost: // stp qt1, qt2, [xn], #imm - case Opcode::AArch64_STPSpost: // stp st1, st2, [xn], #imm - case Opcode::AArch64_STPWpost: // stp wt1, wt2, [xn], #imm - case Opcode::AArch64_STPXpost: { // stp xt1, xt2, [xn], #imm - memoryData[0] = operands[0]; - memoryData[1] = operands[1]; - results[0] = operands[2].get() + metadata.operands[3].imm; - break; - } - case Opcode::AArch64_STPDpre: // stp dt1, dt2, [xn, #imm]! - case Opcode::AArch64_STPQpre: // stp qt1, qt2, [xn, #imm]! - case Opcode::AArch64_STPSpre: // stp st1, st2, [xn, #imm]! - case Opcode::AArch64_STPWpre: // stp wt1, wt2, [xn, #imm]! - case Opcode::AArch64_STPXpre: { // stp xt1, xt2, [xn, #imm]! - memoryData[0] = operands[0]; - memoryData[1] = operands[1]; - results[0] = - operands[2].get() + metadata.operands[2].mem.disp; - break; - } - case Opcode::AArch64_STRBBpost: { // strb wd, [xn], #imm - // STORE - memoryData[0] = operands[0]; - results[0] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_STRBBpre: { // strb wd, [xn, #imm]! - // STORE - memoryData[0] = operands[0]; - results[0] = - operands[1].get() + metadata.operands[1].mem.disp; - break; - } - case Opcode::AArch64_STRBBroW: { // strb wd, - // [xn, wm{, extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRBBroX: { // strb wd, - // [xn, xm{, extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRBBui: { // strb wd, [xn, #imm] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRBui: // str bt, [xn, #imm] - case Opcode::AArch64_STRDui: // str dt, [xn, #imm] - case Opcode::AArch64_STRHui: // str ht, [xn, #imm] - case Opcode::AArch64_STRQui: // str qt, [xn, #imm] - case Opcode::AArch64_STRSui: // str st, [xn, #imm] - case Opcode::AArch64_STRWui: // str wt, [xn, #imm] - case Opcode::AArch64_STRXui: { // str xt, [xn, #imm] - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRBpost: // str bt, [xn], #imm - case Opcode::AArch64_STRDpost: // str dt, [xn], #imm - case Opcode::AArch64_STRHpost: // str ht, [xn], #imm - case Opcode::AArch64_STRQpost: // str qt, [xn], #imm - case Opcode::AArch64_STRSpost: // str st, [xn], #imm - case Opcode::AArch64_STRWpost: // str wt, [xn], #imm - case Opcode::AArch64_STRXpost: { // str xt, [xn], #imm - memoryData[0] = operands[0]; - results[0] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_STRBpre: // str bt, [xn, #imm]! - case Opcode::AArch64_STRDpre: // str dt, [xn, #imm]! - case Opcode::AArch64_STRHpre: // str ht, [xn, #imm]! - case Opcode::AArch64_STRQpre: // str qt, [xn, #imm]! - case Opcode::AArch64_STRSpre: // str st, [xn, #imm]! - case Opcode::AArch64_STRWpre: // str wt, [xn, #imm]! - case Opcode::AArch64_STRXpre: { // str xt, [xn, #imm]! - memoryData[0] = operands[0]; - results[0] = - operands[1].get() + metadata.operands[1].mem.disp; - break; - } - case Opcode::AArch64_STRBroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_STRBroX: { - return executionNYI(); - break; - } - case Opcode::AArch64_STRDroW: { // str dt, [xn, wm{, #extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRDroX: { // str dt, [xn, xm{, #extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRHHpost: { // strh wt, [xn], #imm - // STORE - memoryData[0] = operands[0]; - results[0] = operands[1].get() + metadata.operands[2].imm; - break; - } - case Opcode::AArch64_STRHHpre: { // strh wd, [xn, #imm]! - // STORE - memoryData[0] = operands[0]; - results[0] = - operands[1].get() + metadata.operands[1].mem.disp; - break; - } - case Opcode::AArch64_STRHHroW: { // strh wd, - // [xn, wm{, extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRHHroX: { // strh wd, - // [xn, xm{, extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRHHui: { // strh wt, [xn, #imm] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRHroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_STRHroX: { - return executionNYI(); - break; - } - case Opcode::AArch64_STRQroW: { - return executionNYI(); - break; - } - case Opcode::AArch64_STRQroX: { // str qt, [xn, xm{, extend, {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRSroW: { // str st, [xn, wm{, #extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRSroX: { // str st, [xn, xm{, #extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRWroW: { // str wd, [xn, wm{, extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRWroX: { // str wt, [xn, xm{, extend, {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRXroW: { // str xd, [xn, wm{, extend {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STRXroX: { // str xt, [xn, xm{, extend, {#amount}}] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STR_PXI: { // str pt, [xn{, #imm, mul vl}] - // STORE - const uint64_t PL_bits = VL_bits / 8; - const uint16_t partition_num = PL_bits / 8; - const uint8_t* p = operands[0].getAsVector(); - for (int i = 0; i < partition_num; i++) { - memoryData[i] = p[i]; - } - break; - } - case Opcode::AArch64_STR_ZXI: { // str zt, [xn{, #imm, mul vl}] - // STORE - const uint16_t partition_num = VL_bits / 8; - const uint8_t* z = operands[0].getAsVector(); - for (int i = 0; i < partition_num; i++) { - memoryData[i] = z[i]; - } - break; - } - case Opcode::AArch64_STTRBi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STTRHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STTRWi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STTRXi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STURBBi: { // sturb wd, [xn, #imm] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STURBi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STURDi: // stur dt, [xn, #imm] - case Opcode::AArch64_STURHHi: { // sturh wt, [xn, #imm] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STURHi: { - return executionNYI(); - break; - } - case Opcode::AArch64_STURQi: // stur qt, [xn, #imm] - case Opcode::AArch64_STURSi: // stur st, [xn, #imm] - case Opcode::AArch64_STURWi: // stur wt, [xn, #imm] - case Opcode::AArch64_STURXi: { // stur xt, [xn, #imm] - // STORE - memoryData[0] = operands[0]; - break; - } - case Opcode::AArch64_STXPW: { - return executionNYI(); - break; - } - case Opcode::AArch64_STXPX: { - return executionNYI(); - break; - } - case Opcode::AArch64_STXRB: { - return executionNYI(); - break; - } - case Opcode::AArch64_STXRH: { - return executionNYI(); - break; - } - case Opcode::AArch64_STXRW: { // stxr ws, wt, [xn] - // STORE - memoryData[0] = operands[0]; - // TODO: Implement atomic memory access - results[0] = static_cast(0); - break; - } - case Opcode::AArch64_STXRX: { // stxr ws, xt, [xn] - // STORE - memoryData[0] = operands[0]; - // TODO: Implement atomic memory access - results[0] = static_cast(0); - break; - } - case Opcode::AArch64_SUBHNv2i64_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBHNv2i64_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBHNv4i32_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBHNv4i32_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBHNv8i16_v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBHNv8i16_v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBSWri: { // subs wd, wn, #imm - auto [result, nzcv] = - arithmeticHelp::subShift_imm(operands, metadata, true); - results[0] = nzcv; - results[1] = {result, 8}; - break; - } - case Opcode::AArch64_SUBSWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBSWrs: { // subs wd, wn, wm{, shift #amount} - auto [result, nzcv] = - arithmeticHelp::subShift_3ops(operands, metadata, true); - results[0] = nzcv; - results[1] = {result, 8}; - break; - } - case Opcode::AArch64_SUBSWrx: { // subs wd, wn, wm{, extend #amount} - auto [result, nzcv] = - arithmeticHelp::subExtend_3ops(operands, metadata, true); - results[0] = nzcv; - results[1] = {result, 8}; - break; - } - case Opcode::AArch64_SUBSXri: { // subs xd, xn, #imm - auto [result, nzcv] = - arithmeticHelp::subShift_imm(operands, metadata, true); - results[0] = nzcv; - results[1] = result; - break; - } - case Opcode::AArch64_SUBSXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBSXrs: { // subs xd, xn, xm{, shift #amount} - auto [result, nzcv] = - arithmeticHelp::subShift_3ops(operands, metadata, true); - results[0] = nzcv; - results[1] = result; - break; - } - case Opcode::AArch64_SUBSXrx: // subs xd, xn, wm{, extend #amount} - case Opcode::AArch64_SUBSXrx64: { // subs xd, xn, xm{, extend #amount} - auto [result, nzcv] = - arithmeticHelp::subExtend_3ops(operands, metadata, true); - results[0] = nzcv; - results[1] = result; - break; - } - case Opcode::AArch64_SUBWri: { // sub wd, wn, #imm{, } - auto [result, nzcv] = - arithmeticHelp::subShift_imm(operands, metadata, false); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_SUBWrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBWrs: { // sub wd, wn, wm{, shift #amount} - auto [result, nzcv] = - arithmeticHelp::subShift_3ops(operands, metadata, false); - results[0] = {result, 8}; - break; - } - case Opcode::AArch64_SUBWrx: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBXri: { // sub xd, xn, #imm{, } - auto [result, nzcv] = - arithmeticHelp::subShift_imm(operands, metadata, false); - results[0] = result; - break; - } - case Opcode::AArch64_SUBXrr: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUBXrs: { // sub xd, xn, xm{, shift #amount} - auto [result, nzcv] = - arithmeticHelp::subShift_3ops(operands, metadata, false); - results[0] = result; - break; - } - case Opcode::AArch64_SUBXrx: // sub xd, xn, wm{, extend #amount} - case Opcode::AArch64_SUBXrx64: { // sub xd, xn, xm{, extend #amount} - auto [result, nzcv] = - arithmeticHelp::subExtend_3ops(operands, metadata, false); - results[0] = result; - break; - } - case Opcode::AArch64_SUB_ZI_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZI_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUB_ZZZ_B: { // sub zd.b, zn.b, zm.b - results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_SUB_ZZZ_D: { // sub zd.d, zn.d, zm.d - results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_SUB_ZZZ_H: { // sub zd.h, zn.h, zm.h - results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_SUB_ZZZ_S: { // sub zd.s, zn.s, zm.s - results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_SUBv16i8: { // sub vd.16b, vn.16b, vm.16b - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint8_t x, uint8_t y) -> uint8_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv1i64: { // sub dd, dn, dm - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint64_t x, uint64_t y) -> uint64_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv2i32: { // sub vd.2s, vn.2s, vm.2s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint32_t x, uint32_t y) -> uint32_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv2i64: { // sub vd.2d, vn.2d, vm.2d - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint64_t x, uint64_t y) -> uint64_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv4i16: { // sub vd.4h, vn.4h, vm.4h - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint64_t x, uint16_t y) -> uint16_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv4i32: { // sub vd.4s, vn.4s, vm.4s - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint32_t x, uint32_t y) -> uint32_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv8i16: { // sub vd.8h, vn.8h, vm.8h - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint16_t x, uint16_t y) -> uint16_t { return x - y; }); - break; - } - case Opcode::AArch64_SUBv8i8: { // sub vd.8b, vn.8b, vm.8b - results[0] = neonHelp::vecLogicOp_3vecs( - operands, [](uint8_t x, uint8_t y) -> uint8_t { return x - y; }); - break; - } - case Opcode::AArch64_SUNPKHI_ZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUNPKHI_ZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUNPKHI_ZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUNPKLO_ZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUNPKLO_ZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUNPKLO_ZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv1i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv1i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_SUQADDv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_SVC: { // svc #imm - exceptionEncountered_ = true; - exception_ = InstructionException::SupervisorCall; - break; - } - case Opcode::AArch64_SWPAB: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPAH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPALB: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPALH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPALW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPALX: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPAW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPAX: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPB: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPLB: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPLH: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPLW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPLX: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPW: { - return executionNYI(); - break; - } - case Opcode::AArch64_SWPX: { - return executionNYI(); - break; - } - case Opcode::AArch64_SXTB_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SXTB_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_SXTB_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SXTH_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_SXTH_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_SXTW_ZPmZ_D: { // sxtw zd.d, pg/m, zn.d - results[0] = - sveHelp::sveSxtPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_SYSLxt: { - return executionNYI(); - break; - } - case Opcode::AArch64_SYSxt: { // sys #, cn, cm, #{, xt} - // if (metadata.id == ARM64_INS_DC) { - // uint64_t address = operands[0].get(); - // uint8_t dzp = operands[1].get() & 8; - // uint8_t N = std::pow(2, operands[1].get() & 7); - // if (metadata.operands[0].sys == ARM64_DC_ZVA) { - // if (dzp) { - // // TODO - // } - // } - // } - break; - } - case Opcode::AArch64_TBL_ZZZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBL_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBL_ZZZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBL_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv16i8Four: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv16i8One: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv16i8Three: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv16i8Two: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv8i8Four: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv8i8One: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv8i8Three: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBLv8i8Two: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBNZW: { // tbnz wn, #imm, label - auto [taken, addr] = conditionalHelp::tbnz_tbz( - operands, metadata, instructionAddress_, true); - branchTaken_ = taken; - branchAddress_ = addr; - break; - } - case Opcode::AArch64_TBNZX: { // tbnz xn, #imm, label - auto [taken, addr] = conditionalHelp::tbnz_tbz( - operands, metadata, instructionAddress_, true); - branchTaken_ = taken; - branchAddress_ = addr; - break; - } - case Opcode::AArch64_TBXv16i8Four: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv16i8One: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv16i8Three: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv16i8Two: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv8i8Four: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv8i8One: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv8i8Three: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBXv8i8Two: { - return executionNYI(); - break; - } - case Opcode::AArch64_TBZW: { // tbz wn, #imm, label - auto [taken, addr] = conditionalHelp::tbnz_tbz( - operands, metadata, instructionAddress_, false); - branchTaken_ = taken; - branchAddress_ = addr; - break; - } - case Opcode::AArch64_TBZX: { // tbz xn, #imm, label - auto [taken, addr] = conditionalHelp::tbnz_tbz( - operands, metadata, instructionAddress_, false); - branchTaken_ = taken; - branchAddress_ = addr; - break; - } - case Opcode::AArch64_TCRETURNdi: { - return executionNYI(); - break; - } - case Opcode::AArch64_TCRETURNri: { - return executionNYI(); - break; - } - case Opcode::AArch64_TLSDESCCALL: { - return executionNYI(); - break; - } - case Opcode::AArch64_TLSDESC_CALLSEQ: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1_PPP_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1_PPP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1_PPP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1_PPP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1_ZZZ_B: { - results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN1_ZZZ_D: { - results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN1_ZZZ_H: { - results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN1_ZZZ_S: { - results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN1v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN1v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2_PPP_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2_PPP_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2_PPP_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2_PPP_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2_ZZZ_B: { // trn2 zd.b, zn.b, zm.b - results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN2_ZZZ_D: { // trn2 zd.d, zn.d, zm.d - results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN2_ZZZ_H: { // trn2 zd.h, zn.h, zm.h - results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN2_ZZZ_S: { // trn2 zd.s, zn.s, zm.s - results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); - break; - } - case Opcode::AArch64_TRN2v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_TRN2v8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_TSB: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABALv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABALv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABALv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABALv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABALv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABALv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABAv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABAv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABAv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABAv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABAv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABAv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABD_ZPmZ_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABD_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABD_ZPmZ_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABD_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDv2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDv4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDv4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UABDv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADALPv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADALPv2i32_v1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADALPv4i16_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADALPv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADALPv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADALPv8i8_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLPv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLPv2i32_v1i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLPv4i16_v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLPv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLPv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLPv8i8_v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLVv16i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLVv4i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLVv4i32v: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLVv8i16v: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLVv8i8v: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDLv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDV_VPZ_B: { // uaddv dd, pg, zn.b - results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_UADDV_VPZ_D: { // uaddv dd, pg, zn.d - results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_UADDV_VPZ_H: { // uaddv dd, pg, zn.h - results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_UADDV_VPZ_S: { // uaddv dd, pg, zn.s - results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); - break; - } - case Opcode::AArch64_UADDWv16i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDWv2i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDWv4i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDWv4i32_v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDWv8i16_v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UADDWv8i8_v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UBFMWri: { // ubfm wd, wn, #immr, #imms - results[0] = { - bitmanipHelp::bfm_2imms(operands, metadata, false, true), - 8}; - break; - } - case Opcode::AArch64_UBFMXri: { // ubfm xd, xn, #immr, #imms - results[0] = - bitmanipHelp::bfm_2imms(operands, metadata, false, true); - break; - } - case Opcode::AArch64_UCVTFSWDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFSWHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFSWSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFSXDri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFSXHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFSXSri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFUWDri: { // ucvtf dd, wn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_UCVTFUWHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFUWSri: { // ucvtf sd, wn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_UCVTFUXDri: { // ucvtf dd, xn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_UCVTFUXHri: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFUXSri: { // ucvtf sd, xn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_DtoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_DtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_DtoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_HtoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_StoD: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_StoH: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTF_ZPmZ_StoS: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFd: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFh: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFs: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv1i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv1i32: { // ucvtf sd, sn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_UCVTFv1i64: { // ucvtf dd, dn - results[0] = {static_cast(operands[0].get()), 256}; - break; - } - case Opcode::AArch64_UCVTFv2f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv2f64: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv2i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv2i64_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv4f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv4f32: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv4i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv4i32_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv8f16: { - return executionNYI(); - break; - } - case Opcode::AArch64_UCVTFv8i16_shift: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDIVR_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDIVR_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDIVWr: { // udiv wd, wn, wm - results[0] = {divideHelp::div_3ops(operands), 8}; - break; - } - case Opcode::AArch64_UDIVXr: { // udiv xd, xn, xm - results[0] = {divideHelp::div_3ops(operands), 8}; - break; - } - case Opcode::AArch64_UDIV_ZPmZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDIV_ZPmZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOT_ZZZI_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOT_ZZZI_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOT_ZZZ_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOT_ZZZ_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOTlanev16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOTlanev8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOTv16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UDOTv8i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_UHADDv16i8: { - return executionNYI(); + case Opcode::AArch64_LD1RQ_D_IMM: { // ld1rqd {zd.d}, pg/z, [xn{, #imm}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + const uint16_t partition_num = VL_bits / 64; + uint64_t out[32] = {0}; + uint16_t index = 0; + + // Get mini-vector (quadword) + uint64_t mini[2] = {0}; + for (int i = 0; i < 2; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + mini[i] = memoryData[index].get(); + index++; + } + } + + // Duplicate mini-vector into output vector + for (int i = 0; i < (partition_num / 2); i++) { + out[2 * i] = mini[0]; + out[(2 * i) + 1] = mini[1]; + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UHADDv2i32: { - return executionNYI(); + case Opcode::AArch64_LD1RW_IMM: { // ld1rw {zt.s}, pg/z, [xn, #imm] + // LOAD + const uint16_t partition_num = VL_bits / 32; + uint32_t out[64] = {0}; + uint16_t index = 0; + // Check if any lanes are active, otherwise set all to 0 and break early + bool active = false; + const uint64_t* p = operands[0].getAsVector(); + for (int i = 0; i < 4; i++) { + if (p[i] != 0) { + active = true; + break; + } + } + if (active) { + uint32_t data = memoryData[0].get(); + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = p[index / 16] & 1ull + << ((index % 16) * 4); + out[i] = shifted_active ? data : 0; + index++; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UHADDv4i16: { - return executionNYI(); + case Opcode::AArch64_LD1Rv16b: { // ld1r {vt.16b}, [xn] + // LOAD + 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}; break; } - case Opcode::AArch64_UHADDv4i32: { - return executionNYI(); + case Opcode::AArch64_LD1Rv16b_POST: { // ld1r {vt.16b}, [xn], #imm + // LOAD + 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] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UHADDv8i16: { - return executionNYI(); + case Opcode::AArch64_LD1Rv1d: { // ld1r {vt.1d}, [xn] + // LOAD + uint64_t val = memoryData[0].get(); + uint64_t out[2] = {val, 0}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_UHADDv8i8: { - return executionNYI(); + case Opcode::AArch64_LD1Rv1d_POST: { // ld1r {vt.1d}, [xn], #imm + // LOAD + uint64_t val = memoryData[0].get(); + uint64_t out[2] = {val, 0}; + results[0] = {out, 256}; + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UHSUBv16i8: { - return executionNYI(); + case Opcode::AArch64_LD1Rv2d: { // ld1r {vt.2d}, [xn] + // LOAD + uint64_t val = memoryData[0].get(); + uint64_t out[2] = {val, val}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_UHSUBv2i32: { - return executionNYI(); + case Opcode::AArch64_LD1Rv2d_POST: { // ld1r {vt.2d}, [xn], #imm + // LOAD + uint64_t val = memoryData[0].get(); + uint64_t out[2] = {val, val}; + results[0] = {out, 256}; + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UHSUBv4i16: { - return executionNYI(); + case Opcode::AArch64_LD1Rv2s: { // ld1r {vt.2s}, [xn] + // LOAD + uint32_t val = memoryData[0].get(); + uint32_t out[4] = {val, val, 0, 0}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_UHSUBv4i32: { - return executionNYI(); + case Opcode::AArch64_LD1Rv2s_POST: { // ld1r {vt.2s}, [xn], #imm + // LOAD + uint32_t val = memoryData[0].get(); + uint32_t out[4] = {val, val, 0, 0}; + results[0] = {out, 256}; + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UHSUBv8i16: { - return executionNYI(); + case Opcode::AArch64_LD1Rv4h: { // ld1r {vt.4h}, [xn] + // LOAD + uint16_t val = memoryData[0].get(); + uint16_t out[8] = {val, val, val, val, 0, 0, 0, 0}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_UHSUBv8i8: { - return executionNYI(); + case Opcode::AArch64_LD1Rv4h_POST: { // ld1r {vt.4h}, [xn], #imm + // 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] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMADDLrrr: { // umaddl xd, wn, wm, xa - results[0] = multiplyHelp::maddl_4ops(operands); + case Opcode::AArch64_LD1Rv4s: { // ld1r {vt.4s}, [xn] + // LOAD + uint32_t val = memoryData[0].get(); + uint32_t out[4] = {val, val, val, val}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMAXPv16i8: { - return executionNYI(); + case Opcode::AArch64_LD1Rv4s_POST: { // ld1r {vt.4s}, [xn], #imm + // LOAD + uint32_t val = memoryData[0].get(); + uint32_t out[4] = {val, val, val, val}; + results[0] = {out, 256}; + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMAXPv2i32: { - return executionNYI(); + case Opcode::AArch64_LD1Rv8b: { // ld1r {vt.8b}, [xn] + // LOAD + 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}; break; } - case Opcode::AArch64_UMAXPv4i16: { - return executionNYI(); + case Opcode::AArch64_LD1Rv8b_POST: { // ld1r {vt.8b}, [xn], #imm + // LOAD + 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] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMAXPv4i32: { - return executionNYI(); + case Opcode::AArch64_LD1Rv8h: { // ld1r {vt.8h}, [xn] + // LOAD + uint16_t val = memoryData[0].get(); + uint16_t out[8] = {val, val, val, val, val, val, val, val}; + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMAXPv8i16: { - return executionNYI(); + case Opcode::AArch64_LD1Rv8h_POST: { // ld1r {vt.8h}, [xn], #imm + // 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] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMAXPv8i8: { - return executionNYI(); + case Opcode::AArch64_LD1Twov16b: { // ld1 {vt1.16b, vt2.16b}, [xn] + // LOAD + results[0] = memoryData[0].zeroExtend(memoryData[0].size(), 256); + results[1] = memoryData[1].zeroExtend(memoryData[1].size(), 256); break; } - case Opcode::AArch64_UMAXV_VPZ_B: { - return executionNYI(); + case Opcode::AArch64_LD1Twov16b_POST: { // ld1 {vt1.16b, vt2.16b}, [xn], + // #imm + // LOAD + results[0] = memoryData[0].zeroExtend(memoryData[0].size(), 256); + results[1] = memoryData[1].zeroExtend(memoryData[1].size(), 256); + results[2] = operands[0].get() + metadata.operands[3].imm; break; } - case Opcode::AArch64_UMAXV_VPZ_D: { - return executionNYI(); + case Opcode::AArch64_LD1W: { // ld1w {zt.s}, pg/z, [xn, xm, lsl #2] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 32; + uint16_t index = 0; + uint32_t out[64] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 16) * 4); + if (p[i / 16] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } else { + out[i] = 0; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMAXV_VPZ_H: { - return executionNYI(); + case Opcode::AArch64_LD1W_IMM_REAL: { // ld1w {zt.s}, pg/z, [xn{, #imm, + // mul vl}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + + const uint16_t partition_num = VL_bits / 32; + uint16_t index = 0; + uint32_t out[64] = {0}; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 16) * 4); + if (p[i / 16] & shifted_active) { + out[i] = memoryData[index].get(); + index++; + } else { + out[i] = 0; + } + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMAXV_VPZ_S: { - return executionNYI(); + case Opcode::AArch64_LD1i32: { // ld1 {vt.s}[index], [xn] + // LOAD + const int index = metadata.operands[0].vector_index; + const uint32_t* vt = operands[0].getAsVector(); + uint32_t out[4]; + for (int i = 0; i < 4; i++) { + out[i] = (i == index) ? memoryData[0].get() : vt[i]; + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMAXVv16i8v: { - return executionNYI(); + case Opcode::AArch64_LD1i64: { // ld1 {vt.d}[index], [xn] + // LOAD + const int index = metadata.operands[0].vector_index; + const uint64_t* vt = operands[0].getAsVector(); + uint64_t out[2]; + for (int i = 0; i < 2; i++) { + out[i] = (i == index) ? memoryData[0].get() : vt[i]; + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMAXVv4i16v: { - return executionNYI(); + case Opcode::AArch64_LD1i64_POST: { // ld1 {vt.d}[index], [xn], #8 + // LOAD + const int index = metadata.operands[0].vector_index; + const uint64_t* vt = operands[0].getAsVector(); + uint64_t out[2]; + for (int i = 0; i < 2; i++) { + out[i] = (i == index) ? memoryData[0].get() : vt[i]; + } + results[0] = {out, 256}; + results[1] = operands[1].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMAXVv4i32v: { - return executionNYI(); + case Opcode::AArch64_LD2D: // ld2d {zt1.d, zt2.d}, pg/z, [, xm, + // lsl #3] + case Opcode::AArch64_LD2D_IMM: { // ld2d {zt1.d, zt2.d}, pg/z, [{, + // #imm, mul vl}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + uint64_t out1[32] = {0}; + uint64_t out2[32] = {0}; + + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out1[i] = memoryData[index].get(); + index++; + out2[i] = memoryData[index].get(); + index++; + } else { + out1[i] = 0; + out2[i] = 0; + } + } + results[0] = {out1, 256}; + results[1] = {out2, 256}; break; } - case Opcode::AArch64_UMAXVv8i16v: { - return executionNYI(); + case Opcode::AArch64_LD2Twov4s: { // ld2 {vt1.4s, vt2.4s} [xn] + const float* region1 = memoryData[0].getAsVector(); + const float* region2 = memoryData[1].getAsVector(); + + // LD2 multistruct uses de-interleaving + 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}; break; } - case Opcode::AArch64_UMAXVv8i8v: { - return executionNYI(); + 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 = operands[3].get(); + } + results[2] = operands[2].get() + offset; break; } - case Opcode::AArch64_UMAX_ZI_B: { - return executionNYI(); + case Opcode::AArch64_LD3D_IMM: { // ld3d {zt1.d, zt2.d, zt3.d}, pg/z, + // [xn|sp{, #imm, MUL VL}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + uint64_t out1[32] = {0}; + uint64_t out2[32] = {0}; + uint64_t out3[32] = {0}; + + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out1[i] = memoryData[index].get(); + index++; + out2[i] = memoryData[index].get(); + index++; + out3[i] = memoryData[index].get(); + index++; + } else { + out1[i] = 0; + out2[i] = 0; + out3[i] = 0; + } + } + results[0] = {out1, 256}; + results[1] = {out2, 256}; + results[2] = {out3, 256}; break; } - case Opcode::AArch64_UMAX_ZI_D: { - return executionNYI(); + case Opcode::AArch64_LD4D_IMM: { // ld4d {zt1.d, zt2.d, zt3.d, zt4.d}, + // pg/z, [xn|sp{, #imm, MUL VL}] + // LOAD + const uint64_t* p = operands[0].getAsVector(); + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + uint64_t out1[32] = {0}; + uint64_t out2[32] = {0}; + uint64_t out3[32] = {0}; + uint64_t out4[32] = {0}; + + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + out1[i] = memoryData[index].get(); + index++; + out2[i] = memoryData[index].get(); + index++; + out3[i] = memoryData[index].get(); + index++; + out4[i] = memoryData[index].get(); + index++; + } else { + out1[i] = 0; + out2[i] = 0; + out3[i] = 0; + out4[i] = 0; + } + } + + results[0] = {out1, 256}; + results[1] = {out2, 256}; + results[2] = {out3, 256}; + results[3] = {out4, 256}; break; } - case Opcode::AArch64_UMAX_ZI_H: { - return executionNYI(); + case Opcode::AArch64_LDADDLW: // ldaddl ws, wt, [xn] + // LOAD + [[fallthrough]]; + case Opcode::AArch64_LDADDW: { // ldadd ws, wt, [xn] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); + memoryData[0] = RegisterValue( + memoryData[0].get() + operands[0].get(), 4); break; } - case Opcode::AArch64_UMAX_ZI_S: { - return executionNYI(); + case Opcode::AArch64_LDARB: { // ldarb wt, [xn] + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); break; } - case Opcode::AArch64_UMAX_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_LDARW: { // ldar wt, [xn] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMAX_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_LDARX: { // ldar xt, [xn] + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMAX_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_LDAXRW: { // ldaxr wd, [xn] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMAX_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_LDAXRX: { // ldaxr xd, [xn] + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMAXv16i8: { - return executionNYI(); + case Opcode::AArch64_LDNPSi: { // ldnp st1, st2, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 256); + results[1] = memoryData[1].zeroExtend(4, 256); break; } - case Opcode::AArch64_UMAXv2i32: { - return executionNYI(); + case Opcode::AArch64_LDPDi: // ldp dt1, dt2, [xn, #imm] + case Opcode::AArch64_LDPQi: // ldp qt1, qt2, [xn, #imm] + case Opcode::AArch64_LDPSi: // ldp st1, st2, [xn, #imm] + case Opcode::AArch64_LDPWi: // ldp wt1, wt2, [xn, #imm] + case Opcode::AArch64_LDPXi: { // ldp xt1, xt2, [xn, #imm] + uint16_t regSize = + (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; + results[0] = memoryData[0].zeroExtend(dataSize_, regSize); + results[1] = memoryData[1].zeroExtend(dataSize_, regSize); break; } - case Opcode::AArch64_UMAXv4i16: { - return executionNYI(); + case Opcode::AArch64_LDPDpost: // ldp dt1, dt2, [xn], #imm + case Opcode::AArch64_LDPQpost: // ldp qt1, qt2, [xn], #imm + case Opcode::AArch64_LDPSpost: // ldp st1, st2, [xn], #imm + case Opcode::AArch64_LDPWpost: // ldp wt1, wt2, [xn], #imm + case Opcode::AArch64_LDPXpost: { // ldp xt1, xt2, [xn], #imm + uint16_t regSize = + (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; + results[0] = memoryData[0].zeroExtend(dataSize_, regSize); + results[1] = memoryData[1].zeroExtend(dataSize_, regSize); + results[2] = operands[0].get() + metadata.operands[3].imm; break; } - case Opcode::AArch64_UMAXv4i32: { - return executionNYI(); + case Opcode::AArch64_LDPDpre: // ldp dt1, dt2, [xn, #imm]! + case Opcode::AArch64_LDPQpre: // ldp qt1, qt2, [xn, #imm]! + case Opcode::AArch64_LDPSpre: // ldp st1, st2, [xn, #imm]! + case Opcode::AArch64_LDPWpre: // ldp wt1, wt2, [xn, #imm]! + case Opcode::AArch64_LDPXpre: { // ldp xt1, xt2, [xn, #imm]! + uint16_t regSize = + (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; + results[0] = memoryData[0].zeroExtend(dataSize_, regSize); + results[1] = memoryData[1].zeroExtend(dataSize_, regSize); + results[2] = + operands[0].get() + metadata.operands[2].mem.disp; break; } - case Opcode::AArch64_UMAXv8i16: { - return executionNYI(); + case Opcode::AArch64_LDPSWi: { // ldpsw xt1, xt2, [xn {, #imm}] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); + results[1] = memoryData[1].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMAXv8i8: { - return executionNYI(); + case Opcode::AArch64_LDRBBpost: { // ldrb wt, [xn], #imm + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMINPv16i8: { - return executionNYI(); + case Opcode::AArch64_LDRBBpre: { // ldrb wt, [xn, #imm]! + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); + results[1] = + operands[0].get() + metadata.operands[1].mem.disp; break; } - case Opcode::AArch64_UMINPv2i32: { - return executionNYI(); + case Opcode::AArch64_LDRBBroW: { // ldrb wt, + // [xn, wm{, extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); break; } - case Opcode::AArch64_UMINPv4i16: { - return executionNYI(); + case Opcode::AArch64_LDRBBroX: { // ldrb wt, + // [xn, xm{, extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); break; } - case Opcode::AArch64_UMINPv4i32: { - return executionNYI(); + case Opcode::AArch64_LDRBBui: { // ldrb wt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); break; } - case Opcode::AArch64_UMINPv8i16: { - return executionNYI(); + case Opcode::AArch64_LDRBui: // ldr bt, [xn, #imm] + case Opcode::AArch64_LDRDui: // ldr dt, [xn, #imm] + case Opcode::AArch64_LDRHui: // ldr ht, [xn, #imm] + case Opcode::AArch64_LDRQui: // ldr qt, [xn, #imm] + case Opcode::AArch64_LDRSui: // ldr st, [xn, #imm] + case Opcode::AArch64_LDRWui: // ldr wt, [xn, #imm] + case Opcode::AArch64_LDRXui: { // ldr xt, [xn, #imm] + uint16_t regSize = + (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; + results[0] = memoryData[0].zeroExtend(dataSize_, regSize); break; } - case Opcode::AArch64_UMINPv8i8: { - return executionNYI(); + case Opcode::AArch64_LDRBpost: // ldr bt, [xn], #imm + case Opcode::AArch64_LDRDpost: // ldr dt, [xn], #imm + case Opcode::AArch64_LDRHpost: // ldr ht, [xn], #imm + case Opcode::AArch64_LDRQpost: // ldr qt, [xn], #imm + case Opcode::AArch64_LDRSpost: // ldr st, [xn], #imm + case Opcode::AArch64_LDRWpost: // ldr wt, [xn], #imm + case Opcode::AArch64_LDRXpost: { // ldr xt, [xn], #imm + uint16_t regSize = + (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; + results[0] = memoryData[0].zeroExtend(dataSize_, regSize); + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMINV_VPZ_B: { - return executionNYI(); + case Opcode::AArch64_LDRBpre: // ldr bt, [xn, #imm]! + case Opcode::AArch64_LDRDpre: // ldr dt, [xn, #imm]! + case Opcode::AArch64_LDRHpre: // ldr ht, [xn, #imm]! + case Opcode::AArch64_LDRQpre: // ldr qt, [xn, #imm]! + case Opcode::AArch64_LDRSpre: // ldr st, [xn, #imm]! + case Opcode::AArch64_LDRWpre: // ldr wt, [xn, #imm]! + case Opcode::AArch64_LDRXpre: { // ldr xt, [xn, #imm]! + uint16_t regSize = + (isScalarData_ || isVectorData_ || isSVEData_) ? 256 : 8; + results[0] = memoryData[0].zeroExtend(dataSize_, regSize); + results[1] = + operands[0].get() + metadata.operands[1].mem.disp; break; } - case Opcode::AArch64_UMINV_VPZ_D: { - return executionNYI(); + case Opcode::AArch64_LDRDroW: { // ldr dt, [xn, wm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(memoryAddresses[0].size, 256); break; } - case Opcode::AArch64_UMINV_VPZ_H: { - return executionNYI(); + case Opcode::AArch64_LDRDroX: { // ldr dt, [xn, xm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(memoryAddresses[0].size, 256); break; } - case Opcode::AArch64_UMINV_VPZ_S: { - return executionNYI(); + case Opcode::AArch64_LDRHHpost: { // ldrh wt, [xn], #imm + // LOAD + results[0] = memoryData[0].zeroExtend(2, 8); + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMINVv16i8v: { - return executionNYI(); + case Opcode::AArch64_LDRHHpre: { // ldrh wt, [xn, #imm]! + // LOAD + results[0] = memoryData[0].zeroExtend(2, 8); + results[1] = + operands[0].get() + metadata.operands[1].mem.disp; break; } - case Opcode::AArch64_UMINVv4i16v: { - return executionNYI(); + case Opcode::AArch64_LDRHHroW: { // ldrh wt, [xn, wm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(2, 8); break; } - case Opcode::AArch64_UMINVv4i32v: { - return executionNYI(); + case Opcode::AArch64_LDRHHroX: { // ldrh wt, [xn, xm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(2, 8); break; } - case Opcode::AArch64_UMINVv8i16v: { - return executionNYI(); + case Opcode::AArch64_LDRHHui: { // ldrh wt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(2, 8); break; } - case Opcode::AArch64_UMINVv8i8v: { - return executionNYI(); + case Opcode::AArch64_LDRQroX: { // ldr qt, [xn, xm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(16, 256); break; } - case Opcode::AArch64_UMIN_ZI_B: { - return executionNYI(); + case Opcode::AArch64_LDRSBWroX: { // ldrsb wt, [xn, xm{, extend + // {#amount}}] + // LOAD + results[0] = + RegisterValue(static_cast(memoryData[0].get()), 4) + .zeroExtend(4, 8); break; } - case Opcode::AArch64_UMIN_ZI_D: { - return executionNYI(); + case Opcode::AArch64_LDRSBWui: { // ldrsb wt, [xn, #imm] + // LOAD + results[0] = + RegisterValue(static_cast(memoryData[0].get())) + .zeroExtend(4, 8); break; } - case Opcode::AArch64_UMIN_ZI_H: { - return executionNYI(); + case Opcode::AArch64_LDRSBXui: { // ldrsb xt, [xn, #imm] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMIN_ZI_S: { - return executionNYI(); + case Opcode::AArch64_LDRSHWroW: { // ldrsh wt, [xn, wm{, extend + // {#amount}}] + // LOAD + results[0] = + RegisterValue(static_cast(memoryData[0].get()), 4) + .zeroExtend(4, 8); break; } - case Opcode::AArch64_UMIN_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_LDRSHWroX: { // ldrsh wt, [xn, xm{, extend + // {#amount}}] + // LOAD + results[0] = + RegisterValue(static_cast(memoryData[0].get()), 4) + .zeroExtend(4, 8); break; } - case Opcode::AArch64_UMIN_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_LDRSHWui: { // ldrsh wt, [xn, #imm] + // LOAD + results[0] = + RegisterValue(static_cast(memoryData[0].get()), 4) + .zeroExtend(4, 8); break; } - case Opcode::AArch64_UMIN_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_LDRSHXroW: { // ldrsh xt, [xn, wm{, extend + // {#amount}}] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMIN_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_LDRSHXroX: { // ldrsh xt, [xn, xm{, extend + // {#amount}}] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMINv16i8: { - return executionNYI(); + case Opcode::AArch64_LDRSHXui: { // ldrsh xt, [xn, #imm] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMINv2i32: { - return executionNYI(); + case Opcode::AArch64_LDRSWl: { // ldrsw xt, #imm + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMINv4i16: { - return executionNYI(); + case Opcode::AArch64_LDRSWpost: { // ldrsw xt, [xn], #simm + // LOAD + results[0] = static_cast(memoryData[0].get()); + results[1] = operands[0].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UMINv4i32: { - return executionNYI(); + case Opcode::AArch64_LDRSWroX: { // ldrsw xt, [xn, xm{, extend + // {#amount}}] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMINv8i16: { - return executionNYI(); + case Opcode::AArch64_LDRSWui: { // ldrsw xt, [xn{, #pimm}] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMINv8i8: { - return executionNYI(); + case Opcode::AArch64_LDRSroW: { // ldr st, [xn, wm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 256); break; } - case Opcode::AArch64_UMLALv16i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_LDRSroX: { // ldr st, [xn, xm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 256); break; } - case Opcode::AArch64_UMLALv2i32_indexed: { - return executionNYI(); + case Opcode::AArch64_LDRWroW: { // ldr wt, [xn, wm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMLALv2i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_LDRWroX: { // ldr wt, [xn, xm, {extend {#amount}}] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMLALv4i16_indexed: { - return executionNYI(); + case Opcode::AArch64_LDRXl: { // ldr xt, #imm + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMLALv4i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_LDRXroW: { // ldr xt, [xn, wn{, extend {#amount}}] + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMLALv4i32_indexed: { - return executionNYI(); + case Opcode::AArch64_LDRXroX: { // ldr xt, [xn, xn{, extend {#amount}}] + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMLALv4i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_LDR_PXI: { // ldr pt, [xn{, #imm, mul vl}] + // LOAD + const uint64_t PL_bits = VL_bits / 8; + const uint16_t partition_num = PL_bits / 8; + + uint64_t out[4] = {0}; + for (int i = 0; i < partition_num; i++) { + uint8_t data = memoryData[i].get(); + for (int j = 0; j < 8; j++) { + out[i / 8] |= (data & (1 << j)) ? 1ull << ((j + (i * 8)) % 64) : 0; + } + } + results[0] = out; break; } - case Opcode::AArch64_UMLALv8i16_indexed: { - return executionNYI(); + case Opcode::AArch64_LDR_ZXI: { // ldr zt, [xn{, #imm, mul vl}] + // LOAD + const uint16_t partition_num = VL_bits / 8; + uint8_t out[256] = {0}; + + for (int i = 0; i < partition_num; i++) { + out[i] = memoryData[i].get(); + } + results[0] = {out, 256}; break; } - case Opcode::AArch64_UMLALv8i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_LDTRSBXi: { // ldtrsb xt, [xn, #imm] + // LOAD + // TODO: implement + results[0] = RegisterValue(0, 8); break; } - case Opcode::AArch64_UMLALv8i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_LDURBBi: { // ldurb wt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(1, 8); break; } - case Opcode::AArch64_UMLSLv16i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_LDURDi: { // ldur dt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(8, 256); break; } - case Opcode::AArch64_UMLSLv2i32_indexed: { - return executionNYI(); + case Opcode::AArch64_LDURHHi: { // ldurh wt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(2, 8); break; } - case Opcode::AArch64_UMLSLv2i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_LDURQi: { // ldur qt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(16, 256); break; } - case Opcode::AArch64_UMLSLv4i16_indexed: { - return executionNYI(); + case Opcode::AArch64_LDURSWi: { // ldursw xt, [xn, #imm] + // LOAD + results[0] = static_cast(memoryData[0].get()); break; } - case Opcode::AArch64_UMLSLv4i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_LDURSi: { // ldur sd, [{, #imm}] + // LOAD + results[0] = {memoryData[0].get(), 256}; break; } - case Opcode::AArch64_UMLSLv4i32_indexed: { - return executionNYI(); + case Opcode::AArch64_LDURWi: { // ldur wt, [xn, #imm] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMLSLv4i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_LDURXi: { // ldur xt, [xn, #imm] + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMLSLv8i16_indexed: { - return executionNYI(); + case Opcode::AArch64_LDXRW: { // ldxr wt, [xn] + // LOAD + results[0] = memoryData[0].zeroExtend(4, 8); break; } - case Opcode::AArch64_UMLSLv8i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_LDXRX: { // ldxr xt, [xn] + // LOAD + results[0] = memoryData[0]; break; } - case Opcode::AArch64_UMLSLv8i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_LSLVWr: { // lslv wd, wn, wm + results[0] = { + logicalHelp::logicalShiftLR_3ops(operands, true), 8}; break; } - case Opcode::AArch64_UMOVvi16: { - return executionNYI(); + case Opcode::AArch64_LSLVXr: { // lslv xd, xn, xm + results[0] = logicalHelp::logicalShiftLR_3ops(operands, true); break; } - case Opcode::AArch64_UMOVvi32: { // umov wd, vn.s[index] - const uint32_t* vec = operands[0].getAsVector(); - results[0] = {vec[metadata.operands[1].vector_index], 8}; + case Opcode::AArch64_LSL_ZZI_S: { // lsl zd.s, zn.s, #imm + results[0] = sveHelp::sveLsl_imm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_UMOVvi64: { // umov xd, vn.d[index] - const uint64_t* vec = operands[0].getAsVector(); - results[0] = vec[metadata.operands[1].vector_index]; + case Opcode::AArch64_LSRVWr: { // lsrv wd, wn, wm + results[0] = { + logicalHelp::logicalShiftLR_3ops(operands, false), 8}; break; } - case Opcode::AArch64_UMOVvi8: { // umov wd, vn.b[index] - const uint8_t* vec = operands[0].getAsVector(); - results[0] = {vec[metadata.operands[1].vector_index], 8}; + case Opcode::AArch64_LSRVXr: { // lsrv xd, xn, xm + results[0] = + logicalHelp::logicalShiftLR_3ops(operands, false); break; } - case Opcode::AArch64_UMSUBLrrr: { // umsubl xd, wn, wm, xa - results[0] = arithmeticHelp::msubl_4ops(operands); + case Opcode::AArch64_MADDWrrr: { // madd wd, wn, wm, wa + results[0] = {multiplyHelp::madd_4ops(operands), 8}; break; } - case Opcode::AArch64_UMULH_ZPmZ_B: { - return executionNYI(); + case Opcode::AArch64_MADDXrrr: { // madd xd, xn, xm, xa + results[0] = multiplyHelp::madd_4ops(operands); break; } - case Opcode::AArch64_UMULH_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_MLA_ZPmZZ_B: { // mla zda.b, pg/m, zn.b, zm.b + results[0] = sveHelp::sveMlaPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UMULH_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_MLA_ZPmZZ_D: { // mla zda.d, pg/m, zn.d, zm.d + results[0] = + sveHelp::sveMlaPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UMULH_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_MLA_ZPmZZ_H: { // mla zda.h, pg/m, zn.h, zm.h + results[0] = + sveHelp::sveMlaPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UMULHrr: { // umulh xd, xn, xm - results[0] = AuxFunc::mulhi(operands[0].get(), - operands[1].get()); + case Opcode::AArch64_MLA_ZPmZZ_S: { // mla zda.s, pg/m, zn.s, zm.s + results[0] = + sveHelp::sveMlaPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UMULLv16i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_MOVID: { // movi dd, #imm + results[0] = {static_cast(metadata.operands[1].imm), 256}; break; } - case Opcode::AArch64_UMULLv2i32_indexed: { - return executionNYI(); + case Opcode::AArch64_MOVIv16b_ns: { // movi vd.16b, #imm + results[0] = neonHelp::vecMovi_imm(metadata); break; } - case Opcode::AArch64_UMULLv2i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_MOVIv2d_ns: { // movi vd.2d, #imm + results[0] = neonHelp::vecMovi_imm(metadata); break; } - case Opcode::AArch64_UMULLv4i16_indexed: { - return executionNYI(); + case Opcode::AArch64_MOVIv2i32: { // movi vd.2s, #imm{, lsl #shift} + results[0] = neonHelp::vecMoviShift_imm(metadata, false); break; } - case Opcode::AArch64_UMULLv4i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_MOVIv4i32: { // movi vd.4s, #imm{, LSL #shift} + results[0] = neonHelp::vecMoviShift_imm(metadata, false); break; } - case Opcode::AArch64_UMULLv4i32_indexed: { - return executionNYI(); + case Opcode::AArch64_MOVIv8b_ns: { // movi vd.8b, #imm + results[0] = neonHelp::vecMovi_imm(metadata); break; } - case Opcode::AArch64_UMULLv4i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_MOVKWi: { // movk wd, #imm + results[0] = { + arithmeticHelp::movkShift_imm(operands, metadata), 8}; break; } - case Opcode::AArch64_UMULLv8i16_indexed: { - return executionNYI(); + case Opcode::AArch64_MOVKXi: { // movk xd, #imm + results[0] = + arithmeticHelp::movkShift_imm(operands, metadata); break; } - case Opcode::AArch64_UMULLv8i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_MOVNWi: { // movn wd, #imm{, LSL #shift} + results[0] = {arithmeticHelp::movnShift_imm( + metadata, [](uint64_t x) -> uint32_t { return ~x; }), + 8}; break; } - case Opcode::AArch64_UMULLv8i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_MOVNXi: { // movn xd, #imm{, LSL #shift} + results[0] = arithmeticHelp::movnShift_imm( + metadata, [](uint64_t x) -> uint64_t { return ~x; }); break; } - case Opcode::AArch64_UQADD_ZI_B: { - return executionNYI(); + case Opcode::AArch64_MOVPRFX_ZPmZ_D: { // movprfx zd.d, pg/m, zn.d + results[0] = sveHelp::sveMovprfxPredicated_destUnchanged( + operands, VL_bits); break; } - case Opcode::AArch64_UQADD_ZI_D: { - return executionNYI(); + case Opcode::AArch64_MOVPRFX_ZPzZ_D: { // movprfx zd.d, pg/z, zn.d + results[0] = sveHelp::sveMovprfxPredicated_destToZero( + operands, VL_bits); break; } - case Opcode::AArch64_UQADD_ZI_H: { - return executionNYI(); + case Opcode::AArch64_MOVPRFX_ZPzZ_S: { // movprfx zd.s, pg/z, zn.s + results[0] = sveHelp::sveMovprfxPredicated_destToZero( + operands, VL_bits); break; } - case Opcode::AArch64_UQADD_ZI_S: { - return executionNYI(); + case Opcode::AArch64_MOVPRFX_ZZ: { // movprfx zd, zn + // TODO: Adopt hint logic of the MOVPRFX instruction + results[0] = operands[0]; break; } - case Opcode::AArch64_UQADD_ZZZ_B: { - return executionNYI(); + case Opcode::AArch64_MOVZWi: { // movz wd, #imm + results[0] = {arithmeticHelp::movnShift_imm( + metadata, [](uint64_t x) -> uint32_t { return x; }), + 8}; break; } - case Opcode::AArch64_UQADD_ZZZ_D: { - return executionNYI(); + case Opcode::AArch64_MOVZXi: { // movz xd, #imm + results[0] = arithmeticHelp::movnShift_imm( + metadata, [](uint64_t x) -> uint64_t { return x; }); break; } - case Opcode::AArch64_UQADD_ZZZ_H: { - return executionNYI(); + case Opcode::AArch64_MRS: { // mrs xt, (systemreg|Sop0_op1_Cn_Cm_op2) + results[0] = operands[0]; break; } - case Opcode::AArch64_UQADD_ZZZ_S: { - return executionNYI(); + case Opcode::AArch64_MSR: { // mrs (systemreg|Sop0_op1_Cn_Cm_op2), xt + results[0] = operands[0]; break; } - case Opcode::AArch64_UQADDv16i8: { - return executionNYI(); + case Opcode::AArch64_MSUBWrrr: { // msub wd, wn, wm, wa + results[0] = {multiplyHelp::msub_4ops(operands), 8}; break; } - case Opcode::AArch64_UQADDv1i16: { - return executionNYI(); + case Opcode::AArch64_MSUBXrrr: { // msub xd, xn, xm, xa + results[0] = multiplyHelp::msub_4ops(operands); break; } - case Opcode::AArch64_UQADDv1i32: { - return executionNYI(); + case Opcode::AArch64_MUL_ZPmZ_B: { // mul zdn.b, pg/m, zdn.b, zm.b + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_UQADDv1i64: { - return executionNYI(); + case Opcode::AArch64_MUL_ZPmZ_D: { // mul zdn.d, pg/m, zdn.d, zm.d + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_UQADDv1i8: { - return executionNYI(); + case Opcode::AArch64_MUL_ZPmZ_H: { // mul zdn.h, pg/m, zdn.h, zm.h + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_UQADDv2i32: { - return executionNYI(); + case Opcode::AArch64_MUL_ZPmZ_S: { // mul zdn.s, pg/m, zdn.s, zm.s + results[0] = sveHelp::sveMulPredicated(operands, metadata, + VL_bits, false); break; } - case Opcode::AArch64_UQADDv2i64: { - return executionNYI(); + case Opcode::AArch64_MVNIv2i32: { // mvni vd.2s, #imm{, lsl #shift} + results[0] = neonHelp::vecMoviShift_imm(metadata, true); break; } - case Opcode::AArch64_UQADDv4i16: { - return executionNYI(); + case Opcode::AArch64_MVNIv2s_msl: { // mvni vd.2s, #imm, msl #amount + results[0] = neonHelp::vecMoviShift_imm(metadata, true); break; } - case Opcode::AArch64_UQADDv4i32: { - return executionNYI(); + case Opcode::AArch64_MVNIv4i16: { // mvni vd.4h, #imm{, lsl #shift} + results[0] = neonHelp::vecMoviShift_imm(metadata, true); break; } - case Opcode::AArch64_UQADDv8i16: { - return executionNYI(); + case Opcode::AArch64_MVNIv4i32: { // mvni vd.4s, #imm{, lsl #shift} + results[0] = neonHelp::vecMoviShift_imm(metadata, true); break; } - case Opcode::AArch64_UQADDv8i8: { - return executionNYI(); + case Opcode::AArch64_MVNIv4s_msl: { // mvni vd.4s #imm, msl #amount + results[0] = neonHelp::vecMoviShift_imm(metadata, true); break; } - case Opcode::AArch64_UQDECB_WPiI: { - return executionNYI(); + case Opcode::AArch64_MVNIv8i16: { // mvni vd.8h, #imm{, lsl #shift} + results[0] = neonHelp::vecMoviShift_imm(metadata, true); break; } - case Opcode::AArch64_UQDECB_XPiI: { - return executionNYI(); + case Opcode::AArch64_NEGv2i64: { // neg vd.2d, vn.2d + results[0] = neonHelp::vecFneg_2ops(operands); break; } - case Opcode::AArch64_UQDECD_WPiI: { // uqdecd wd{, pattern{, MUL #imm}} - results[0] = - sveHelp::sveUqdec(operands, metadata, VL_bits); + case Opcode::AArch64_NOTv16i8: { // not vd.16b, vn.16b + results[0] = neonHelp::vecLogicOp_2vecs( + operands, [](uint8_t x) -> uint8_t { return ~x; }); break; } - case Opcode::AArch64_UQDECD_XPiI: { // uqdecd xd{, pattern{, MUL #imm}} - results[0] = - sveHelp::sveUqdec(operands, metadata, VL_bits); + case Opcode::AArch64_NOTv8i8: { // not vd.8b, vn.8b + results[0] = neonHelp::vecLogicOp_2vecs( + operands, [](uint8_t x) -> uint8_t { return ~x; }); break; } - case Opcode::AArch64_UQDECD_ZPiI: { - return executionNYI(); + case Opcode::AArch64_ORNWrs: { // orn wd, wn, wm{, shift{ #amount}} + auto [result, nzcv] = logicalHelp::logicOpShift_3ops( + operands, metadata, false, + [](uint32_t x, uint32_t y) -> uint32_t { return x | (~y); }); + results[0] = {result, 8}; break; } - case Opcode::AArch64_UQDECH_WPiI: { - return executionNYI(); + case Opcode::AArch64_ORNXrs: { // orn xd, xn, xm{, shift{ #amount}} + auto [result, nzcv] = logicalHelp::logicOpShift_3ops( + operands, metadata, false, + [](uint64_t x, uint64_t y) -> uint64_t { return x | (~y); }); + results[0] = result; break; } - case Opcode::AArch64_UQDECH_XPiI: { // uqdech xd{, pattern{, MUL #imm}} - results[0] = - sveHelp::sveUqdec(operands, metadata, VL_bits); + case Opcode::AArch64_ORRWri: { // orr wd, wn, #imm + auto [result, nzcv] = logicalHelp::logicOp_imm( + operands, metadata, false, + [](uint32_t x, uint32_t y) -> uint32_t { return x | y; }); + results[0] = {result, 8}; break; } - case Opcode::AArch64_UQDECH_ZPiI: { - return executionNYI(); + case Opcode::AArch64_ORRWrs: { // orr wd, wn, wm{, shift{ #amount}} + results[0] = { + comparisonHelp::orrShift_3ops(operands, metadata), 8}; break; } - case Opcode::AArch64_UQDECP_WP_B: { - return executionNYI(); + case Opcode::AArch64_ORRXri: { // orr xd, xn, #imm + auto [result, nzcv] = logicalHelp::logicOp_imm( + operands, metadata, false, + [](uint64_t x, uint64_t y) -> uint64_t { return x | y; }); + results[0] = {result, 8}; break; } - case Opcode::AArch64_UQDECP_WP_D: { - return executionNYI(); + case Opcode::AArch64_ORRXrs: { // orr xd, xn, xm{, shift{ #amount}} + results[0] = + comparisonHelp::orrShift_3ops(operands, metadata); break; } - case Opcode::AArch64_UQDECP_WP_H: { - return executionNYI(); + case Opcode::AArch64_ORR_PPzPP: { // orr pd.b, pg/z, pn.b, pm.b + results[0] = sveHelp::sveLogicOp_preds( + operands, VL_bits, + [](uint64_t x, uint64_t y) -> uint64_t { return x | y; }); break; } - case Opcode::AArch64_UQDECP_WP_S: { - return executionNYI(); + case Opcode::AArch64_ORR_ZZZ: { // orr zd.d, zn.d, zm.d + results[0] = sveHelp::sveOrr_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_UQDECP_XP_B: { - return executionNYI(); + case Opcode::AArch64_ORRv16i8: { // orr vd.16b, Vn.16b, Vm.16b + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint8_t x, uint8_t y) -> uint8_t { return x | y; }); break; } - case Opcode::AArch64_UQDECP_XP_D: { - return executionNYI(); + case Opcode::AArch64_ORRv8i8: { // orr vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint8_t x, uint8_t y) -> uint8_t { return x | y; }); break; } - case Opcode::AArch64_UQDECP_XP_H: { - return executionNYI(); + case Opcode::AArch64_PFALSE: { // pfalse pd.b + uint64_t out[4] = {0, 0, 0, 0}; + results[0] = out; break; } - case Opcode::AArch64_UQDECP_XP_S: { - return executionNYI(); + case Opcode::AArch64_PRFMui: { // prfm op, [xn, xm{, extend{, #amount}}] break; } - case Opcode::AArch64_UQDECP_ZP_D: { - return executionNYI(); + case Opcode::AArch64_PTEST_PP: { // ptest pg, pn.b + const uint64_t* g = operands[0].getAsVector(); + const uint64_t* s = operands[1].getAsVector(); + std::array masked_n = {(g[0] & s[0]), (g[1] & s[1]), + (g[2] & s[2]), (g[3] & s[3])}; + // Byte count = 1 as destination predicate is regarding single bytes. + results[0] = AuxFunc::getNZCVfromPred(masked_n, VL_bits, 1); break; } - case Opcode::AArch64_UQDECP_ZP_H: { - return executionNYI(); + case Opcode::AArch64_PTRUE_B: { // ptrue pd.b{, pattern} + results[0] = sveHelp::svePtrue(metadata, VL_bits); break; } - case Opcode::AArch64_UQDECP_ZP_S: { - return executionNYI(); + case Opcode::AArch64_PTRUE_D: { // ptrue pd.d{, pattern} + results[0] = sveHelp::svePtrue(metadata, VL_bits); break; } - case Opcode::AArch64_UQDECW_WPiI: { - return executionNYI(); + case Opcode::AArch64_PTRUE_H: { // ptrue pd.h{, pattern} + results[0] = sveHelp::svePtrue(metadata, VL_bits); break; } - case Opcode::AArch64_UQDECW_XPiI: { // uqdecw xd{, pattern{, MUL #imm}} - results[0] = - sveHelp::sveUqdec(operands, metadata, VL_bits); + case Opcode::AArch64_PTRUE_S: { // ptrue pd.s{, pattern} + results[0] = sveHelp::svePtrue(metadata, VL_bits); break; } - case Opcode::AArch64_UQDECW_ZPiI: { - return executionNYI(); + case Opcode::AArch64_PUNPKHI_PP: { // punpkhi pd.h, pn.b + results[0] = sveHelp::svePunpk(operands, VL_bits, true); break; } - case Opcode::AArch64_UQINCB_WPiI: { - return executionNYI(); + case Opcode::AArch64_PUNPKLO_PP: { // punpklo pd.h, pn.b + results[0] = sveHelp::svePunpk(operands, VL_bits, false); break; } - case Opcode::AArch64_UQINCB_XPiI: { - return executionNYI(); + case Opcode::AArch64_RBITWr: { // rbit wd, wn + results[0] = {bitmanipHelp::rbit(operands, metadata), 8}; break; } - case Opcode::AArch64_UQINCD_WPiI: { - return executionNYI(); + case Opcode::AArch64_RBITXr: { // rbit xd, xn + results[0] = bitmanipHelp::rbit(operands, metadata); break; } - case Opcode::AArch64_UQINCD_XPiI: { - return executionNYI(); + case Opcode::AArch64_RDVLI_XI: { // rdvl xd, #imm + int8_t imm = static_cast(metadata.operands[1].imm); + results[0] = (uint64_t)(imm * (VL_bits / 8)); break; } - case Opcode::AArch64_UQINCD_ZPiI: { - return executionNYI(); + case Opcode::AArch64_RET: { // ret {xr} + branchTaken_ = true; + branchAddress_ = operands[0].get(); break; } - case Opcode::AArch64_UQINCH_WPiI: { - return executionNYI(); + case Opcode::AArch64_REV16v16i8: { // rev16 Vd.16b, Vn.16b + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCH_XPiI: { - return executionNYI(); + case Opcode::AArch64_REV16v8i8: { // rev16 Vd.8b, Vn.8b + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCH_ZPiI: { - return executionNYI(); + case Opcode::AArch64_REV32v16i8: { // rev32 Vd.16b, Vn.16b + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_WP_B: { - return executionNYI(); + case Opcode::AArch64_REV32v4i16: { // rev32 Vd.4h, Vn.4h + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_WP_D: { - return executionNYI(); + case Opcode::AArch64_REV32v8i16: { // rev32 Vd.8h, Vn.8h + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_WP_H: { - return executionNYI(); + case Opcode::AArch64_REV32v8i8: { // rev32 Vd.8b, Vn.8b + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_WP_S: { - return executionNYI(); + case Opcode::AArch64_REV64v16i8: { // rev64 Vd.16b, Vn.16b + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_XP_B: { - return executionNYI(); + case Opcode::AArch64_REV64v2i32: { // rev64 Vd.2s, Vn.2s + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_XP_D: { - return executionNYI(); + case Opcode::AArch64_REV64v4i16: { // rev64 Vd.4h, Vn.4h + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_XP_H: { - return executionNYI(); + case Opcode::AArch64_REV64v4i32: { // rev64 Vd.4s, Vn.4s + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_XP_S: { - return executionNYI(); + case Opcode::AArch64_REV64v8i16: { // rev64 Vd.8h, Vn.8h + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_ZP_D: { - return executionNYI(); + case Opcode::AArch64_REV64v8i8: { // rev64 Vd.8b Vn.8b + results[0] = neonHelp::vecRev(operands); break; } - case Opcode::AArch64_UQINCP_ZP_H: { - return executionNYI(); + case Opcode::AArch64_REVXr: { // rev xd, xn + results[0] = bitmanipHelp::rev(operands); break; } - case Opcode::AArch64_UQINCP_ZP_S: { - return executionNYI(); + case Opcode::AArch64_REV_PP_B: { // rev pd.b, pn.b + results[0] = sveHelp::sveRev_predicates(operands, VL_bits); break; } - case Opcode::AArch64_UQINCW_WPiI: { - return executionNYI(); + case Opcode::AArch64_REV_PP_D: { // rev pd.d, pn.d + results[0] = sveHelp::sveRev_predicates(operands, VL_bits); break; } - case Opcode::AArch64_UQINCW_XPiI: { - return executionNYI(); + case Opcode::AArch64_REV_PP_H: { // rev pd.h, pn.h + results[0] = sveHelp::sveRev_predicates(operands, VL_bits); break; } - case Opcode::AArch64_UQINCW_ZPiI: { - return executionNYI(); + case Opcode::AArch64_REV_PP_S: { // rev pd.s, pn.s + results[0] = sveHelp::sveRev_predicates(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHLv16i8: { - return executionNYI(); + case Opcode::AArch64_REV_ZZ_B: { // rev zd.b, zn.b + results[0] = sveHelp::sveRev_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHLv1i16: { - return executionNYI(); + case Opcode::AArch64_REV_ZZ_D: { // rev zd.d, zn.d + results[0] = sveHelp::sveRev_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHLv1i32: { - return executionNYI(); + case Opcode::AArch64_REV_ZZ_H: { // rev zd.h, zn.h + results[0] = sveHelp::sveRev_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHLv1i64: { - return executionNYI(); + case Opcode::AArch64_REV_ZZ_S: { // rev zd.s, zn.s + results[0] = sveHelp::sveRev_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHLv1i8: { - return executionNYI(); + case Opcode::AArch64_RORVWr: { // rorv wd, wn, wm + results[0] = {logicalHelp::rorv_3ops(operands), 8}; break; } - case Opcode::AArch64_UQRSHLv2i32: { - return executionNYI(); + case Opcode::AArch64_RORVXr: { // rorv xd, xn, xm + results[0] = logicalHelp::rorv_3ops(operands); break; } - case Opcode::AArch64_UQRSHLv2i64: { - return executionNYI(); + case Opcode::AArch64_SBCWr: { // sbc wd, wn, wm + results[0] = {arithmeticHelp::sbc(operands), 8}; break; } - case Opcode::AArch64_UQRSHLv4i16: { - return executionNYI(); + case Opcode::AArch64_SBCXr: { // sbc xd, xn, xm + results[0] = arithmeticHelp::sbc(operands); break; } - case Opcode::AArch64_UQRSHLv4i32: { - return executionNYI(); + case Opcode::AArch64_SBFMWri: { // sbfm wd, wn, #immr, #imms + results[0] = { + bitmanipHelp::bfm_2imms(operands, metadata, true, true), + 8}; break; } - case Opcode::AArch64_UQRSHLv8i16: { - return executionNYI(); + case Opcode::AArch64_SBFMXri: { // sbfm xd, xn, #immr, #imms + results[0] = + bitmanipHelp::bfm_2imms(operands, metadata, true, true); break; } - case Opcode::AArch64_UQRSHLv8i8: { - return executionNYI(); + case Opcode::AArch64_SCVTFSXDri: { // scvtf dd, xn, #fbits + results[0] = + floatHelp::scvtf_FixedPoint(operands, metadata); break; } - case Opcode::AArch64_UQRSHRNb: { - return executionNYI(); + case Opcode::AArch64_SCVTFSXSri: { // scvtf sd, xn, #fbits + results[0] = + floatHelp::scvtf_FixedPoint(operands, metadata); break; } - case Opcode::AArch64_UQRSHRNh: { - return executionNYI(); + case Opcode::AArch64_SCVTFUWDri: { // scvtf dd, wn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UQRSHRNs: { - return executionNYI(); + case Opcode::AArch64_SCVTFUWSri: { // scvtf sd, wn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UQRSHRNv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_SCVTFUXDri: { // scvtf dd, xn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UQRSHRNv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_SCVTFUXSri: { // scvtf sd, xn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UQRSHRNv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_SCVTF_ZPmZ_DtoD: { // scvtf zd.d, pg/m, zn.d + results[0] = + sveHelp::sveFcvtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHRNv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_SCVTF_ZPmZ_DtoS: { // scvtf zd.s, pg/m, zn.d + results[0] = + sveHelp::sveFcvtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHRNv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_SCVTF_ZPmZ_StoD: { // scvtf zd.d, pg/m, zn.s + results[0] = + sveHelp::sveFcvtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQRSHRNv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_SCVTF_ZPmZ_StoS: { // scvtf zd.s, pg/m, zn.s + results[0] = + sveHelp::sveFcvtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQSHLb: { - return executionNYI(); + case Opcode::AArch64_SCVTFv1i32: { // scvtf sd, sn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UQSHLd: { - return executionNYI(); + case Opcode::AArch64_SCVTFv1i64: { // scvtf dd, dn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UQSHLh: { - return executionNYI(); + case Opcode::AArch64_SCVTFv2f32: { // scvtf vd.2s, vn.2s + results[0] = neonHelp::vecScvtf_2vecs( + operands, [](int32_t x) -> float { return static_cast(x); }); break; } - case Opcode::AArch64_UQSHLs: { - return executionNYI(); + case Opcode::AArch64_SCVTFv2f64: { // scvtf vd.2d, vn.2d + results[0] = neonHelp::vecScvtf_2vecs( + operands, + [](int64_t x) -> double { return static_cast(x); }); break; } - case Opcode::AArch64_UQSHLv16i8: { - return executionNYI(); + case Opcode::AArch64_SCVTFv4f32: { // scvtf vd.4s, vn.4s + results[0] = neonHelp::vecScvtf_2vecs( + operands, [](int32_t x) -> float { return static_cast(x); }); break; } - case Opcode::AArch64_UQSHLv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_SDIVWr: { // sdiv wd, wn, wm + results[0] = {divideHelp::div_3ops(operands), 8}; break; } - case Opcode::AArch64_UQSHLv1i16: { - return executionNYI(); + case Opcode::AArch64_SDIVXr: { // sdiv xd, xn, xm + results[0] = {divideHelp::div_3ops(operands), 8}; break; } - case Opcode::AArch64_UQSHLv1i32: { - return executionNYI(); + case Opcode::AArch64_SEL_ZPZZ_D: { // sel zd.d, pg, zn.d, zm.d + results[0] = sveHelp::sveSel_zpzz(operands, VL_bits); break; } - case Opcode::AArch64_UQSHLv1i64: { - return executionNYI(); + case Opcode::AArch64_SEL_ZPZZ_S: { // sel zd.s, pg, zn.s, zm.s + results[0] = sveHelp::sveSel_zpzz(operands, VL_bits); break; } - case Opcode::AArch64_UQSHLv1i8: { - return executionNYI(); + case Opcode::AArch64_SHLd: { // shl dd, dn #imm + results[0] = + neonHelp::vecShlShift_vecImm(operands, metadata); break; } - case Opcode::AArch64_UQSHLv2i32: { - return executionNYI(); + case Opcode::AArch64_SHLv4i32_shift: { // shl vd.4s, vn.4s, #imm + results[0] = + neonHelp::vecShlShift_vecImm(operands, metadata); break; } - case Opcode::AArch64_UQSHLv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_SMADDLrrr: { // smaddl xd, wn, wm, xa + results[0] = multiplyHelp::maddl_4ops(operands); break; } - case Opcode::AArch64_UQSHLv2i64: { - return executionNYI(); + case Opcode::AArch64_SMAX_ZI_S: { // smax zdn.s, zdn.s, #imm + results[0] = + sveHelp::sveMax_vecImm(operands, metadata, VL_bits); break; } - case Opcode::AArch64_UQSHLv2i64_shift: { - return executionNYI(); + case Opcode::AArch64_SMAX_ZPmZ_S: { // smax zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveMaxPredicated_vecs(operands, VL_bits); break; } - case Opcode::AArch64_UQSHLv4i16: { - return executionNYI(); + case Opcode::AArch64_SMAXv4i32: { // smax vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, + [](int32_t x, int32_t y) -> int32_t { return std::max(x, y); }); break; } - case Opcode::AArch64_UQSHLv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_SMINV_VPZ_S: { // sminv sd, pg, zn.s + results[0] = sveHelp::sveSminv(operands, VL_bits); break; } - case Opcode::AArch64_UQSHLv4i32: { - return executionNYI(); + case Opcode::AArch64_SMINVv4i32v: { // sminv sd, vn.4s + results[0] = neonHelp::vecMinv_2ops(operands); break; } - case Opcode::AArch64_UQSHLv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_SMIN_ZPmZ_S: { // smin zd.s, pg/m, zn.s, zm.s + results[0] = sveHelp::sveLogicOpPredicated_3vecs( + operands, VL_bits, + [](int32_t x, int32_t y) -> int32_t { return std::min(x, y); }); break; } - case Opcode::AArch64_UQSHLv8i16: { - return executionNYI(); + case Opcode::AArch64_SMINv4i32: { // smin vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, + [](int32_t x, int32_t y) -> int32_t { return std::min(x, y); }); break; } - case Opcode::AArch64_UQSHLv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_SMSUBLrrr: { // smsubl xd, wn, wm, xa + results[0] = arithmeticHelp::msubl_4ops(operands); break; } - case Opcode::AArch64_UQSHLv8i8: { - return executionNYI(); + case Opcode::AArch64_SMULH_ZPmZ_B: { // smulh zdn.b, pg/m, zdn.b, zm.b + results[0] = + sveHelp::sveMulhPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQSHLv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_SMULH_ZPmZ_H: { // smulh zdn.h, pg/m, zdn.h, zm.h + results[0] = + sveHelp::sveMulhPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQSHRNb: { - return executionNYI(); + case Opcode::AArch64_SMULH_ZPmZ_S: { // smulh zdn.s, pg/m, zdn.s, zm.s + results[0] = + sveHelp::sveMulhPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UQSHRNh: { - return executionNYI(); + case Opcode::AArch64_SMULHrr: { // smulh xd, xn, xm + // TODO: signed + results[0] = AuxFunc::mulhi(operands[0].get(), + operands[1].get()); break; } - case Opcode::AArch64_UQSHRNs: { - return executionNYI(); + case Opcode::AArch64_SSHLLv2i32_shift: { // sshll vd.2d, vn.2s, #imm + results[0] = neonHelp::vecShllShift_vecImm( + operands, metadata, false); break; } - case Opcode::AArch64_UQSHRNv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_SSHLLv4i32_shift: { // sshll2 vd.2d, vn.4s, #imm + results[0] = neonHelp::vecShllShift_vecImm( + operands, metadata, true); break; } - case Opcode::AArch64_UQSHRNv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_SSHRv4i32_shift: { // sshr vd.4s, vn.4s, #imm + results[0] = neonHelp::vecSshrShift_imm(operands, metadata); break; } - case Opcode::AArch64_UQSHRNv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_SST1B_D_REAL: { // st1b {zd.d}, pg, [xn, zm.d] + // STORE + const uint64_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = static_cast(d[i]); + index++; + } + } break; } - case Opcode::AArch64_UQSHRNv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_SST1D_REAL: { // st1d {zt.d}, pg, [xn, zm.d] + // STORE + const uint64_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSHRNv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_SST1D_IMM: { // st1d {zd.d}, pg, [zn.d{, #imm}] + // STORE + const uint64_t* t = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = t[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSHRNv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_SST1D_SCALED_SCALED_REAL: { // st1d {zt.d}, pg, [xn, + // zm.d, lsl # + // 3] + // STORE + const uint64_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZI_B: { - return executionNYI(); + case Opcode::AArch64_SST1W_D_IMM: { // st1w {zt.d}, pg, [zn.d{, #imm}] + // STORE + const uint64_t* t = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = t[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZI_D: { - return executionNYI(); + case Opcode::AArch64_SST1W_IMM: { // st1w {zt.s}, pg, [zn.s{, #imm}] + // STORE + const uint32_t* t = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 32; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 16) * 4); + if (p[i / 16] & shifted_active) { + memoryData[index] = t[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZI_H: { - return executionNYI(); + case Opcode::AArch64_ST1B: { // st1b {zt.b}, pg, [xn, xm] + // STORE + const uint8_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 8; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << (i % 64); + if (p[i / 64] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZI_S: { - return executionNYI(); + case Opcode::AArch64_ST1D: { // st1d {zt.d}, pg, [xn, xm, lsl #3] + // STORE + const uint64_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZZZ_B: { - return executionNYI(); + case Opcode::AArch64_ST1D_IMM: { // st1d {zt.d}, pg, [xn{, #imm, mul vl}] + // STORE + const uint64_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZZZ_D: { - return executionNYI(); + case Opcode::AArch64_ST1Twov16b: { // st1v {vt.16b, vt2.16b}, [xn] + // STORE + const uint8_t* t = operands[0].getAsVector(); + const uint8_t* t2 = operands[1].getAsVector(); + for (int i = 0; i < 16; i++) { + memoryData[i] = t[i]; + } + for (int i = 0; i < 16; i++) { + memoryData[i + 16] = t2[i]; + } break; } - case Opcode::AArch64_UQSUB_ZZZ_H: { - return executionNYI(); + case Opcode::AArch64_ST1W: { // st1w {zt.s}, pg, [xn, xm, lsl #2] + // STORE + const uint32_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 32; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 16) * 4); + if (p[i / 16] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUB_ZZZ_S: { - return executionNYI(); + case Opcode::AArch64_ST1W_D: { // st1w {zt.d}, pg, [xn, xm, lsl #2] + // STORE + const uint64_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = static_cast(d[i]); + index++; + } + } break; } - case Opcode::AArch64_UQSUBv16i8: { - return executionNYI(); + case Opcode::AArch64_ST1W_IMM: { // st1w {zt.s}, pg, [xn{, #imm, mul vl}] + // STORE + const uint32_t* d = operands[0].getAsVector(); + const uint64_t* p = operands[1].getAsVector(); + + const uint16_t partition_num = VL_bits / 32; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 16) * 4); + if (p[i / 16] & shifted_active) { + memoryData[index] = d[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUBv1i16: { - return executionNYI(); + case Opcode::AArch64_ST1i16: { // st1 {vt.h}[index], [xn] + // STORE + const uint16_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; break; } - case Opcode::AArch64_UQSUBv1i32: { - return executionNYI(); + case Opcode::AArch64_ST1i16_POST: { // st1 {vt.h}[index], [xn], xm + // st1 {vt.h}[index], [xn], #2 + // STORE + const uint16_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; + uint64_t offset = 2; + if (metadata.operandCount == 3) { + offset = operands[2].get(); + } + results[0] = operands[1].get() + offset; break; } - case Opcode::AArch64_UQSUBv1i64: { - return executionNYI(); + case Opcode::AArch64_ST1i32: { // st1 {vt.s}[index], [xn] + // STORE + const uint32_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; break; } - case Opcode::AArch64_UQSUBv1i8: { - return executionNYI(); + case Opcode::AArch64_ST1i32_POST: { // st1 {vt.s}[index], [xn], xm + // st1 {vt.s}[index], [xn], #4 + // STORE + const uint32_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; + uint64_t offset = 4; + if (metadata.operandCount == 3) { + offset = operands[2].get(); + } + results[0] = operands[1].get() + offset; break; } - case Opcode::AArch64_UQSUBv2i32: { - return executionNYI(); + case Opcode::AArch64_ST1i64: { // st1 {vt.d}[index], [xn] + // STORE + const uint64_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; break; } - case Opcode::AArch64_UQSUBv2i64: { - return executionNYI(); + case Opcode::AArch64_ST1i64_POST: { // st1 {vt.d}[index], [xn], xm + // st1 {vt.d}[index], [xn], #8 + // STORE + const uint64_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; + uint64_t offset = 8; + if (metadata.operandCount == 3) { + offset = operands[2].get(); + } + results[0] = operands[1].get() + offset; break; } - case Opcode::AArch64_UQSUBv4i16: { - return executionNYI(); + case Opcode::AArch64_ST1i8: { // st1 {vt.b}[index], [xn] + // STORE + const uint8_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; break; } - case Opcode::AArch64_UQSUBv4i32: { - return executionNYI(); + case Opcode::AArch64_ST1i8_POST: { // st1 {vt.b}[index], [xn], xm + // st1 {vt.b}[index], [xn], #1 + // STORE + const uint8_t* t = operands[0].getAsVector(); + memoryData[0] = t[metadata.operands[0].vector_index]; + uint64_t offset = 1; + if (metadata.operandCount == 3) { + offset = operands[2].get(); + } + results[0] = RegisterValue(operands[1].get() + offset, 8); break; } - case Opcode::AArch64_UQSUBv8i16: { - return executionNYI(); + case Opcode::AArch64_ST2D_IMM: { // st2d {zt1.d, zt2.d}, pg, [{, + // #imm, mul vl}] + // STORE + const uint64_t* d1 = operands[0].getAsVector(); + const uint64_t* d2 = operands[1].getAsVector(); + const uint64_t* p = operands[2].getAsVector(); + + const uint16_t partition_num = VL_bits / 64; + uint16_t index = 0; + for (int i = 0; i < partition_num; i++) { + uint64_t shifted_active = 1ull << ((i % 8) * 8); + if (p[i / 8] & shifted_active) { + memoryData[index] = d1[i]; + index++; + memoryData[index] = d2[i]; + index++; + } + } break; } - case Opcode::AArch64_UQSUBv8i8: { - return executionNYI(); + case Opcode::AArch64_ST2Twov4s_POST: { // st2 {vt1.4s, vt2.4s}, [xn], + // #imm + // STORE + const float* t1 = operands[0].getAsVector(); + const float* t2 = operands[1].getAsVector(); + for (int i = 0; i < 4; i++) { + memoryData[2 * i] = t1[i]; + memoryData[2 * i + 1] = t2[i]; + } + uint64_t offset = 32; + if (metadata.operandCount == 4) { + offset = operands[3].get(); + } + results[0] = operands[2].get() + offset; break; } - case Opcode::AArch64_UQXTNv16i8: { - return executionNYI(); + case Opcode::AArch64_STLRB: { // stlrb wt, [xn] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_UQXTNv1i16: { - return executionNYI(); + case Opcode::AArch64_STLRW: // stlr wt, [xn] + case Opcode::AArch64_STLRX: { // stlr xt, [xn] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_UQXTNv1i32: { - return executionNYI(); + case Opcode::AArch64_STLXRW: // stlxr ws, wt, [xn] + case Opcode::AArch64_STLXRX: { // stlxr ws, xt, [xn] + // STORE + memoryData[0] = operands[0]; + // TODO: Implement atomic memory access + results[0] = static_cast(0); break; } - case Opcode::AArch64_UQXTNv1i8: { - return executionNYI(); + case Opcode::AArch64_STPDi: // stp dt1, dt2, [xn, #imm] + case Opcode::AArch64_STPQi: // stp qt1, qt2, [xn, #imm] + case Opcode::AArch64_STPSi: // stp st1, st2, [xn, #imm] + case Opcode::AArch64_STPWi: // stp wt1, wt2, [xn, #imm] + case Opcode::AArch64_STPXi: { // stp xt1, xt2, [xn, #imm] + memoryData[0] = operands[0]; + memoryData[1] = operands[1]; break; } - case Opcode::AArch64_UQXTNv2i32: { - return executionNYI(); + case Opcode::AArch64_STPDpost: // stp dt1, dt2, [xn], #imm + case Opcode::AArch64_STPQpost: // stp qt1, qt2, [xn], #imm + case Opcode::AArch64_STPSpost: // stp st1, st2, [xn], #imm + case Opcode::AArch64_STPWpost: // stp wt1, wt2, [xn], #imm + case Opcode::AArch64_STPXpost: { // stp xt1, xt2, [xn], #imm + memoryData[0] = operands[0]; + memoryData[1] = operands[1]; + results[0] = operands[2].get() + metadata.operands[3].imm; break; } - case Opcode::AArch64_UQXTNv4i16: { - return executionNYI(); + case Opcode::AArch64_STPDpre: // stp dt1, dt2, [xn, #imm]! + case Opcode::AArch64_STPQpre: // stp qt1, qt2, [xn, #imm]! + case Opcode::AArch64_STPSpre: // stp st1, st2, [xn, #imm]! + case Opcode::AArch64_STPWpre: // stp wt1, wt2, [xn, #imm]! + case Opcode::AArch64_STPXpre: { // stp xt1, xt2, [xn, #imm]! + memoryData[0] = operands[0]; + memoryData[1] = operands[1]; + results[0] = + operands[2].get() + metadata.operands[2].mem.disp; break; } - case Opcode::AArch64_UQXTNv4i32: { - return executionNYI(); + case Opcode::AArch64_STRBBpost: { // strb wd, [xn], #imm + // STORE + memoryData[0] = operands[0]; + results[0] = operands[1].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_UQXTNv8i16: { - return executionNYI(); + case Opcode::AArch64_STRBBpre: { // strb wd, [xn, #imm]! + // STORE + memoryData[0] = operands[0]; + results[0] = + operands[1].get() + metadata.operands[1].mem.disp; break; } - case Opcode::AArch64_UQXTNv8i8: { - return executionNYI(); + case Opcode::AArch64_STRBBroW: { // strb wd, + // [xn, wm{, extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URECPEv2i32: { - return executionNYI(); + case Opcode::AArch64_STRBBroX: { // strb wd, + // [xn, xm{, extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URECPEv4i32: { - return executionNYI(); + case Opcode::AArch64_STRBBui: { // strb wd, [xn, #imm] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URHADDv16i8: { - return executionNYI(); + case Opcode::AArch64_STRBui: // str bt, [xn, #imm] + case Opcode::AArch64_STRDui: // str dt, [xn, #imm] + case Opcode::AArch64_STRHui: // str ht, [xn, #imm] + case Opcode::AArch64_STRQui: // str qt, [xn, #imm] + case Opcode::AArch64_STRSui: // str st, [xn, #imm] + case Opcode::AArch64_STRWui: // str wt, [xn, #imm] + case Opcode::AArch64_STRXui: { // str xt, [xn, #imm] + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URHADDv2i32: { - return executionNYI(); + case Opcode::AArch64_STRBpost: // str bt, [xn], #imm + case Opcode::AArch64_STRDpost: // str dt, [xn], #imm + case Opcode::AArch64_STRHpost: // str ht, [xn], #imm + case Opcode::AArch64_STRQpost: // str qt, [xn], #imm + case Opcode::AArch64_STRSpost: // str st, [xn], #imm + case Opcode::AArch64_STRWpost: // str wt, [xn], #imm + case Opcode::AArch64_STRXpost: { // str xt, [xn], #imm + memoryData[0] = operands[0]; + results[0] = operands[1].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_URHADDv4i16: { - return executionNYI(); + case Opcode::AArch64_STRBpre: // str bt, [xn, #imm]! + case Opcode::AArch64_STRDpre: // str dt, [xn, #imm]! + case Opcode::AArch64_STRHpre: // str ht, [xn, #imm]! + case Opcode::AArch64_STRQpre: // str qt, [xn, #imm]! + case Opcode::AArch64_STRSpre: // str st, [xn, #imm]! + case Opcode::AArch64_STRWpre: // str wt, [xn, #imm]! + case Opcode::AArch64_STRXpre: { // str xt, [xn, #imm]! + memoryData[0] = operands[0]; + results[0] = + operands[1].get() + metadata.operands[1].mem.disp; break; } - case Opcode::AArch64_URHADDv4i32: { - return executionNYI(); + case Opcode::AArch64_STRDroW: { // str dt, [xn, wm{, #extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URHADDv8i16: { - return executionNYI(); + case Opcode::AArch64_STRDroX: { // str dt, [xn, xm{, #extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URHADDv8i8: { - return executionNYI(); + case Opcode::AArch64_STRHHpost: { // strh wt, [xn], #imm + // STORE + memoryData[0] = operands[0]; + results[0] = operands[1].get() + metadata.operands[2].imm; break; } - case Opcode::AArch64_URSHLv16i8: { - return executionNYI(); + case Opcode::AArch64_STRHHpre: { // strh wd, [xn, #imm]! + // STORE + memoryData[0] = operands[0]; + results[0] = + operands[1].get() + metadata.operands[1].mem.disp; break; } - case Opcode::AArch64_URSHLv1i64: { - return executionNYI(); + case Opcode::AArch64_STRHHroW: { // strh wd, + // [xn, wm{, extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHLv2i32: { - return executionNYI(); + case Opcode::AArch64_STRHHroX: { // strh wd, + // [xn, xm{, extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHLv2i64: { - return executionNYI(); + case Opcode::AArch64_STRHHui: { // strh wt, [xn, #imm] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHLv4i16: { - return executionNYI(); + case Opcode::AArch64_STRQroX: { // str qt, [xn, xm{, extend, {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHLv4i32: { - return executionNYI(); + case Opcode::AArch64_STRSroW: { // str st, [xn, wm{, #extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHLv8i16: { - return executionNYI(); + case Opcode::AArch64_STRSroX: { // str st, [xn, xm{, #extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHLv8i8: { - return executionNYI(); + case Opcode::AArch64_STRWroW: { // str wd, [xn, wm{, extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHRd: { - return executionNYI(); + case Opcode::AArch64_STRWroX: { // str wt, [xn, xm{, extend, {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHRv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_STRXroW: { // str xd, [xn, wm{, extend {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHRv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_STRXroX: { // str xt, [xn, xm{, extend, {#amount}}] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHRv2i64_shift: { - return executionNYI(); + case Opcode::AArch64_STR_PXI: { // str pt, [xn{, #imm, mul vl}] + // STORE + const uint64_t PL_bits = VL_bits / 8; + const uint16_t partition_num = PL_bits / 8; + const uint8_t* p = operands[0].getAsVector(); + for (int i = 0; i < partition_num; i++) { + memoryData[i] = p[i]; + } break; } - case Opcode::AArch64_URSHRv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_STR_ZXI: { // str zt, [xn{, #imm, mul vl}] + // STORE + const uint16_t partition_num = VL_bits / 8; + const uint8_t* z = operands[0].getAsVector(); + for (int i = 0; i < partition_num; i++) { + memoryData[i] = z[i]; + } break; } - case Opcode::AArch64_URSHRv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_STURBBi: { // sturb wd, [xn, #imm] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHRv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_STURDi: // stur dt, [xn, #imm] + case Opcode::AArch64_STURHHi: { // sturh wt, [xn, #imm] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSHRv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_STURQi: // stur qt, [xn, #imm] + case Opcode::AArch64_STURSi: // stur st, [xn, #imm] + case Opcode::AArch64_STURWi: // stur wt, [xn, #imm] + case Opcode::AArch64_STURXi: { // stur xt, [xn, #imm] + // STORE + memoryData[0] = operands[0]; break; } - case Opcode::AArch64_URSQRTEv2i32: { - return executionNYI(); + case Opcode::AArch64_STXRW: { // stxr ws, wt, [xn] + // STORE + memoryData[0] = operands[0]; + // TODO: Implement atomic memory access + results[0] = static_cast(0); break; } - case Opcode::AArch64_URSQRTEv4i32: { - return executionNYI(); + case Opcode::AArch64_STXRX: { // stxr ws, xt, [xn] + // STORE + memoryData[0] = operands[0]; + // TODO: Implement atomic memory access + results[0] = static_cast(0); break; } - case Opcode::AArch64_URSRAd: { - return executionNYI(); + case Opcode::AArch64_SUBSWri: { // subs wd, wn, #imm + auto [result, nzcv] = + arithmeticHelp::subShift_imm(operands, metadata, true); + results[0] = nzcv; + results[1] = {result, 8}; break; } - case Opcode::AArch64_URSRAv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_SUBSWrs: { // subs wd, wn, wm{, shift #amount} + auto [result, nzcv] = + arithmeticHelp::subShift_3ops(operands, metadata, true); + results[0] = nzcv; + results[1] = {result, 8}; break; } - case Opcode::AArch64_URSRAv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_SUBSWrx: { // subs wd, wn, wm{, extend #amount} + auto [result, nzcv] = + arithmeticHelp::subExtend_3ops(operands, metadata, true); + results[0] = nzcv; + results[1] = {result, 8}; break; } - case Opcode::AArch64_URSRAv2i64_shift: { - return executionNYI(); + case Opcode::AArch64_SUBSXri: { // subs xd, xn, #imm + auto [result, nzcv] = + arithmeticHelp::subShift_imm(operands, metadata, true); + results[0] = nzcv; + results[1] = result; break; } - case Opcode::AArch64_URSRAv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_SUBSXrs: { // subs xd, xn, xm{, shift #amount} + auto [result, nzcv] = + arithmeticHelp::subShift_3ops(operands, metadata, true); + results[0] = nzcv; + results[1] = result; break; } - case Opcode::AArch64_URSRAv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_SUBSXrx: // subs xd, xn, wm{, extend #amount} + case Opcode::AArch64_SUBSXrx64: { // subs xd, xn, xm{, extend #amount} + auto [result, nzcv] = + arithmeticHelp::subExtend_3ops(operands, metadata, true); + results[0] = nzcv; + results[1] = result; break; } - case Opcode::AArch64_URSRAv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_SUBWri: { // sub wd, wn, #imm{, } + auto [result, nzcv] = + arithmeticHelp::subShift_imm(operands, metadata, false); + results[0] = {result, 8}; break; } - case Opcode::AArch64_URSRAv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_SUBWrs: { // sub wd, wn, wm{, shift #amount} + auto [result, nzcv] = + arithmeticHelp::subShift_3ops(operands, metadata, false); + results[0] = {result, 8}; break; } - case Opcode::AArch64_USHLLv16i8_shift: { // ushll2 vd.8h, vn.16b, #imm - results[0] = neonHelp::vecShllShift_vecImm( - operands, metadata, true); + case Opcode::AArch64_SUBXri: { // sub xd, xn, #imm{, } + auto [result, nzcv] = + arithmeticHelp::subShift_imm(operands, metadata, false); + results[0] = result; break; } - case Opcode::AArch64_USHLLv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_SUBXrs: { // sub xd, xn, xm{, shift #amount} + auto [result, nzcv] = + arithmeticHelp::subShift_3ops(operands, metadata, false); + results[0] = result; break; } - case Opcode::AArch64_USHLLv4i16_shift: { // ushll vd.4s, vn.4h, #imm - results[0] = neonHelp::vecShllShift_vecImm( - operands, metadata, false); + case Opcode::AArch64_SUBXrx: // sub xd, xn, wm{, extend #amount} + case Opcode::AArch64_SUBXrx64: { // sub xd, xn, xm{, extend #amount} + auto [result, nzcv] = + arithmeticHelp::subExtend_3ops(operands, metadata, false); + results[0] = result; break; } - case Opcode::AArch64_USHLLv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_SUB_ZZZ_B: { // sub zd.b, zn.b, zm.b + results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USHLLv8i16_shift: { // ushll2 vd.4s, vn.8h, #imm - results[0] = neonHelp::vecShllShift_vecImm( - operands, metadata, true); + case Opcode::AArch64_SUB_ZZZ_D: { // sub zd.d, zn.d, zm.d + results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USHLLv8i8_shift: { // ushll vd.8h, vn.8b, #imm - results[0] = neonHelp::vecShllShift_vecImm( - operands, metadata, false); + case Opcode::AArch64_SUB_ZZZ_H: { // sub zd.h, zn.h, zm.h + results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USHLv16i8: { - return executionNYI(); + case Opcode::AArch64_SUB_ZZZ_S: { // sub zd.s, zn.s, zm.s + results[0] = sveHelp::sveSub_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USHLv1i64: { - return executionNYI(); + case Opcode::AArch64_SUBv16i8: { // sub vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint8_t x, uint8_t y) -> uint8_t { return x - y; }); break; } - case Opcode::AArch64_USHLv2i32: { - return executionNYI(); + case Opcode::AArch64_SUBv1i64: { // sub dd, dn, dm + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint64_t x, uint64_t y) -> uint64_t { return x - y; }); break; } - case Opcode::AArch64_USHLv2i64: { - return executionNYI(); + case Opcode::AArch64_SUBv2i32: { // sub vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint32_t x, uint32_t y) -> uint32_t { return x - y; }); break; } - case Opcode::AArch64_USHLv4i16: { - return executionNYI(); + case Opcode::AArch64_SUBv2i64: { // sub vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint64_t x, uint64_t y) -> uint64_t { return x - y; }); break; } - case Opcode::AArch64_USHLv4i32: { - return executionNYI(); + case Opcode::AArch64_SUBv4i16: { // sub vd.4h, vn.4h, vm.4h + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint64_t x, uint16_t y) -> uint16_t { return x - y; }); break; } - case Opcode::AArch64_USHLv8i16: { - return executionNYI(); + case Opcode::AArch64_SUBv4i32: { // sub vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint32_t x, uint32_t y) -> uint32_t { return x - y; }); break; } - case Opcode::AArch64_USHLv8i8: { - return executionNYI(); + case Opcode::AArch64_SUBv8i16: { // sub vd.8h, vn.8h, vm.8h + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint16_t x, uint16_t y) -> uint16_t { return x - y; }); break; } - case Opcode::AArch64_USHRd: { - return executionNYI(); + case Opcode::AArch64_SUBv8i8: { // sub vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecLogicOp_3vecs( + operands, [](uint8_t x, uint8_t y) -> uint8_t { return x - y; }); break; } - case Opcode::AArch64_USHRv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_SVC: { // svc #imm + exceptionEncountered_ = true; + exception_ = InstructionException::SupervisorCall; break; } - case Opcode::AArch64_USHRv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_SXTW_ZPmZ_D: { // sxtw zd.d, pg/m, zn.d + results[0] = + sveHelp::sveSxtPredicated(operands, VL_bits); break; } - case Opcode::AArch64_USHRv2i64_shift: { - return executionNYI(); + case Opcode::AArch64_SYSxt: { // sys #, cn, cm, #{, xt} + // if (metadata.id == ARM64_INS_DC) { + // uint64_t address = operands[0].get(); + // uint8_t dzp = operands[1].get() & 8; + // uint8_t N = std::pow(2, operands[1].get() & 7); + // if (metadata.operands[0].sys == ARM64_DC_ZVA) { + // if (dzp) { + // // TODO + // } + // } + // } break; } - case Opcode::AArch64_USHRv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_TBLv16i8Four: { // tbl Vd.16b {Vn.16b, Vn+1.16b, + // Vn+2.16b,Vn+3.16b } Vm.16b + results[0] = neonHelp::vecTbl<16>(operands, metadata); break; } - case Opcode::AArch64_USHRv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_TBLv16i8One: { // tbl Vd.16b {Vn.16b} Vm.16b + results[0] = neonHelp::vecTbl<16>(operands, metadata); break; } - case Opcode::AArch64_USHRv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_TBLv16i8Three: { // tbl Vd.16b {Vn.16b, Vn+1.16b, + // Vn+2.16b } Vm.16b + results[0] = neonHelp::vecTbl<16>(operands, metadata); break; } - case Opcode::AArch64_USHRv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_TBLv16i8Two: { // tbl Vd.16b {Vn.16b, Vn+1.16b } + // Vm.16b + results[0] = neonHelp::vecTbl<16>(operands, metadata); break; } - case Opcode::AArch64_USQADDv16i8: { - return executionNYI(); + case Opcode::AArch64_TBLv8i8Four: { // tbl Vd.8b {Vn.16b, Vn+1.16b, + // Vn+2.16b,Vn+3.16b } Vm.8b + results[0] = neonHelp::vecTbl<8>(operands, metadata); break; } - case Opcode::AArch64_USQADDv1i16: { - return executionNYI(); + case Opcode::AArch64_TBLv8i8One: { // tbl Vd.8b {Vn.16b} Vm.8b + results[0] = neonHelp::vecTbl<8>(operands, metadata); break; } - case Opcode::AArch64_USQADDv1i32: { - return executionNYI(); + case Opcode::AArch64_TBLv8i8Three: { // tbl Vd.8b {Vn.16b, Vn+1.16b, + // Vn+2.16b } Vm.8b + results[0] = neonHelp::vecTbl<8>(operands, metadata); break; } - case Opcode::AArch64_USQADDv1i64: { - return executionNYI(); + case Opcode::AArch64_TBLv8i8Two: { // tbl Vd.8b {Vn.16b, Vn+1.16b } Vm.8b + results[0] = neonHelp::vecTbl<8>(operands, metadata); break; } - case Opcode::AArch64_USQADDv1i8: { - return executionNYI(); + case Opcode::AArch64_TBNZW: { // tbnz wn, #imm, label + auto [taken, addr] = conditionalHelp::tbnz_tbz( + operands, metadata, instructionAddress_, true); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_USQADDv2i32: { - return executionNYI(); + case Opcode::AArch64_TBNZX: { // tbnz xn, #imm, label + auto [taken, addr] = conditionalHelp::tbnz_tbz( + operands, metadata, instructionAddress_, true); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_USQADDv2i64: { - return executionNYI(); + case Opcode::AArch64_TBZW: { // tbz wn, #imm, label + auto [taken, addr] = conditionalHelp::tbnz_tbz( + operands, metadata, instructionAddress_, false); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_USQADDv4i16: { - return executionNYI(); + case Opcode::AArch64_TBZX: { // tbz xn, #imm, label + auto [taken, addr] = conditionalHelp::tbnz_tbz( + operands, metadata, instructionAddress_, false); + branchTaken_ = taken; + branchAddress_ = addr; break; } - case Opcode::AArch64_USQADDv4i32: { - return executionNYI(); + case Opcode::AArch64_TRN1_ZZZ_B: { // trn1 zd.b, zn.b, zm.b + results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USQADDv8i16: { - return executionNYI(); + case Opcode::AArch64_TRN1_ZZZ_D: { // trn1 zd.d, zn.d, zm.d + results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USQADDv8i8: { - return executionNYI(); + case Opcode::AArch64_TRN1_ZZZ_H: { // trn1 zd.h, zn.h, zm.h + results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USRAd: { - return executionNYI(); + case Opcode::AArch64_TRN1_ZZZ_S: { // trn1 zd.s, zn.s, zm.s + results[0] = sveHelp::sveTrn1_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USRAv16i8_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v16i8: { // trn1 vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USRAv2i32_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v2i32: { // trn1 vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USRAv2i64_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v2i64: { // trn1 vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USRAv4i16_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v4i16: { // trn1 vd.4h, vn.4h, vm.4h + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USRAv4i32_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v4i32: { // trn1 vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USRAv8i16_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v8i16: { // trn1 vd.8h, vn.8h, vm.8h + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USRAv8i8_shift: { - return executionNYI(); + case Opcode::AArch64_TRN1v8i8: { // trn1 vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecTrn1(operands); break; } - case Opcode::AArch64_USUBLv16i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_TRN2_ZZZ_B: { // trn2 zd.b, zn.b, zm.b + results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USUBLv2i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_TRN2_ZZZ_D: { // trn2 zd.d, zn.d, zm.d + results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USUBLv4i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_TRN2_ZZZ_H: { // trn2 zd.h, zn.h, zm.h + results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USUBLv4i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_TRN2_ZZZ_S: { // trn2 zd.s, zn.s, zm.s + results[0] = sveHelp::sveTrn2_3vecs(operands, VL_bits); break; } - case Opcode::AArch64_USUBLv8i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_TRN2v16i8: { // trn2 vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBLv8i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_TRN2v2i32: { // trn2 vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBWv16i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_TRN2v2i64: { // trn2 vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBWv2i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_TRN2v4i16: { // trn2 vd.4h, vn.4h, vm.4h + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBWv4i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_TRN2v4i32: { // trn2 vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBWv4i32_v2i64: { - return executionNYI(); + case Opcode::AArch64_TRN2v8i16: { // trn2 vd.8h, vn.8h, vm.8h + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBWv8i16_v4i32: { - return executionNYI(); + case Opcode::AArch64_TRN2v8i8: { // trn2 vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecTrn2(operands); break; } - case Opcode::AArch64_USUBWv8i8_v8i16: { - return executionNYI(); + case Opcode::AArch64_UADDV_VPZ_B: { // uaddv dd, pg, zn.b + results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UUNPKHI_ZZ_D: { // uunpkhi zd.d, zn.s - results[0] = - sveHelp::sveUnpk_vecs(operands, VL_bits, true); + case Opcode::AArch64_UADDV_VPZ_D: { // uaddv dd, pg, zn.d + results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UUNPKHI_ZZ_H: { // uunpkhi zd.h, zn.b - results[0] = - sveHelp::sveUnpk_vecs(operands, VL_bits, true); + case Opcode::AArch64_UADDV_VPZ_H: { // uaddv dd, pg, zn.h + results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UUNPKHI_ZZ_S: { // uunpkhi zd.s, zn.h - results[0] = - sveHelp::sveUnpk_vecs(operands, VL_bits, true); + case Opcode::AArch64_UADDV_VPZ_S: { // uaddv dd, pg, zn.s + results[0] = sveHelp::sveAddvPredicated(operands, VL_bits); break; } - case Opcode::AArch64_UUNPKLO_ZZ_D: { // uunpklo zd.d, zn.s - results[0] = - sveHelp::sveUnpk_vecs(operands, VL_bits, false); + case Opcode::AArch64_UBFMWri: { // ubfm wd, wn, #immr, #imms + results[0] = { + bitmanipHelp::bfm_2imms(operands, metadata, false, true), + 8}; break; } - case Opcode::AArch64_UUNPKLO_ZZ_H: { // uunpklo zd.h, zn.b + case Opcode::AArch64_UBFMXri: { // ubfm xd, xn, #immr, #imms results[0] = - sveHelp::sveUnpk_vecs(operands, VL_bits, false); + bitmanipHelp::bfm_2imms(operands, metadata, false, true); break; } - case Opcode::AArch64_UUNPKLO_ZZ_S: { // uunpklo zd.s, zn.h - results[0] = - sveHelp::sveUnpk_vecs(operands, VL_bits, false); + case Opcode::AArch64_UCVTFUWDri: { // ucvtf dd, wn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UXTB_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_UCVTFUWSri: { // ucvtf sd, wn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UXTB_ZPmZ_H: { - return executionNYI(); + case Opcode::AArch64_UCVTFUXDri: { // ucvtf dd, xn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UXTB_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_UCVTFUXSri: { // ucvtf sd, xn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UXTH_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_UCVTFv1i32: { // ucvtf sd, sn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UXTH_ZPmZ_S: { - return executionNYI(); + case Opcode::AArch64_UCVTFv1i64: { // ucvtf dd, dn + results[0] = {static_cast(operands[0].get()), 256}; break; } - case Opcode::AArch64_UXTW_ZPmZ_D: { - return executionNYI(); + case Opcode::AArch64_UDIVWr: { // udiv wd, wn, wm + results[0] = {divideHelp::div_3ops(operands), 8}; break; } - case Opcode::AArch64_UZP1_PPP_B: { - return executionNYI(); + case Opcode::AArch64_UDIVXr: { // udiv xd, xn, xm + results[0] = {divideHelp::div_3ops(operands), 8}; break; } - case Opcode::AArch64_UZP1_PPP_D: { - return executionNYI(); + case Opcode::AArch64_UMADDLrrr: { // umaddl xd, wn, wm, xa + results[0] = multiplyHelp::maddl_4ops(operands); break; } - case Opcode::AArch64_UZP1_PPP_H: { - return executionNYI(); + case Opcode::AArch64_UMAXPv16i8: { // umaxp vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecUMaxP(operands); break; } - case Opcode::AArch64_UZP1_PPP_S: { - return executionNYI(); + case Opcode::AArch64_UMINPv16i8: { // uminp vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecUMinP(operands); break; } - case Opcode::AArch64_UZP1_ZZZ_B: { - return executionNYI(); + case Opcode::AArch64_UMOVvi32_idx0: // umov wd, vn.s[0] + case Opcode::AArch64_UMOVvi32: { // umov wd, vn.s[index] + const uint32_t* vec = operands[0].getAsVector(); + results[0] = {vec[metadata.operands[1].vector_index], 8}; break; } - case Opcode::AArch64_UZP1_ZZZ_D: { - return executionNYI(); + case Opcode::AArch64_UMOVvi64_idx0: // umov xd, vn.d[0] + case Opcode::AArch64_UMOVvi64: { // umov xd, vn.d[index] + const uint64_t* vec = operands[0].getAsVector(); + results[0] = vec[metadata.operands[1].vector_index]; break; } - case Opcode::AArch64_UZP1_ZZZ_H: { - return executionNYI(); + case Opcode::AArch64_UMOVvi8_idx0: // umov wd, vn.b[0] + case Opcode::AArch64_UMOVvi8: { // umov wd, vn.b[index] + const uint8_t* vec = operands[0].getAsVector(); + results[0] = {vec[metadata.operands[1].vector_index], 8}; break; } - case Opcode::AArch64_UZP1_ZZZ_S: { // uzp1 zd.s, zn.s, zm.s - results[0] = sveHelp::sveUzp_vecs(operands, VL_bits, true); + case Opcode::AArch64_UMSUBLrrr: { // umsubl xd, wn, wm, xa + results[0] = arithmeticHelp::msubl_4ops(operands); break; } - case Opcode::AArch64_UZP1v16i8: { - return executionNYI(); + case Opcode::AArch64_UMULHrr: { // umulh xd, xn, xm + results[0] = AuxFunc::mulhi(operands[0].get(), + operands[1].get()); break; } - case Opcode::AArch64_UZP1v2i32: { - return executionNYI(); + case Opcode::AArch64_UQDECD_WPiI: { // uqdecd wd{, pattern{, MUL #imm}} + results[0] = + sveHelp::sveUqdec(operands, metadata, VL_bits); break; } - case Opcode::AArch64_UZP1v2i64: { - return executionNYI(); + case Opcode::AArch64_UQDECD_XPiI: { // uqdecd xd{, pattern{, MUL #imm}} + results[0] = + sveHelp::sveUqdec(operands, metadata, VL_bits); break; } - case Opcode::AArch64_UZP1v4i16: { - return executionNYI(); + case Opcode::AArch64_UQDECH_XPiI: { // uqdech xd{, pattern{, MUL #imm}} + results[0] = + sveHelp::sveUqdec(operands, metadata, VL_bits); break; } - case Opcode::AArch64_UZP1v4i32: { - return executionNYI(); + case Opcode::AArch64_UQDECW_XPiI: { // uqdecw xd{, pattern{, MUL #imm}} + results[0] = + sveHelp::sveUqdec(operands, metadata, VL_bits); break; } - case Opcode::AArch64_UZP1v8i16: { - return executionNYI(); + case Opcode::AArch64_USHLLv16i8_shift: { // ushll2 vd.8h, vn.16b, #imm + results[0] = neonHelp::vecShllShift_vecImm( + operands, metadata, true); break; } - case Opcode::AArch64_UZP1v8i8: { - return executionNYI(); + case Opcode::AArch64_USHLLv4i16_shift: { // ushll vd.4s, vn.4h, #imm + results[0] = neonHelp::vecShllShift_vecImm( + operands, metadata, false); break; } - case Opcode::AArch64_UZP2_PPP_B: { - return executionNYI(); + case Opcode::AArch64_USHLLv8i16_shift: { // ushll2 vd.4s, vn.8h, #imm + results[0] = neonHelp::vecShllShift_vecImm( + operands, metadata, true); break; } - case Opcode::AArch64_UZP2_PPP_D: { - return executionNYI(); + case Opcode::AArch64_USHLLv8i8_shift: { // ushll vd.8h, vn.8b, #imm + results[0] = neonHelp::vecShllShift_vecImm( + operands, metadata, false); break; } - case Opcode::AArch64_UZP2_PPP_H: { - return executionNYI(); + case Opcode::AArch64_UUNPKHI_ZZ_D: { // uunpkhi zd.d, zn.s + results[0] = + sveHelp::sveUnpk_vecs(operands, VL_bits, true); break; } - case Opcode::AArch64_UZP2_PPP_S: { - return executionNYI(); + case Opcode::AArch64_UUNPKHI_ZZ_H: { // uunpkhi zd.h, zn.b + results[0] = + sveHelp::sveUnpk_vecs(operands, VL_bits, true); break; } - case Opcode::AArch64_UZP2_ZZZ_B: { - return executionNYI(); + case Opcode::AArch64_UUNPKHI_ZZ_S: { // uunpkhi zd.s, zn.h + results[0] = + sveHelp::sveUnpk_vecs(operands, VL_bits, true); break; } - case Opcode::AArch64_UZP2_ZZZ_D: { - return executionNYI(); + case Opcode::AArch64_UUNPKLO_ZZ_D: { // uunpklo zd.d, zn.s + results[0] = + sveHelp::sveUnpk_vecs(operands, VL_bits, false); break; } - case Opcode::AArch64_UZP2_ZZZ_H: { - return executionNYI(); + case Opcode::AArch64_UUNPKLO_ZZ_H: { // uunpklo zd.h, zn.b + results[0] = + sveHelp::sveUnpk_vecs(operands, VL_bits, false); break; } - case Opcode::AArch64_UZP2_ZZZ_S: { - return executionNYI(); + case Opcode::AArch64_UUNPKLO_ZZ_S: { // uunpklo zd.s, zn.h + results[0] = + sveHelp::sveUnpk_vecs(operands, VL_bits, false); break; } - case Opcode::AArch64_UZP2v16i8: { - return executionNYI(); + case Opcode::AArch64_UZP1_ZZZ_S: { // uzp1 zd.s, zn.s, zm.s + results[0] = sveHelp::sveUzp_vecs(operands, VL_bits, true); break; } - case Opcode::AArch64_UZP2v2i32: { - return executionNYI(); + case Opcode::AArch64_UZP1v16i8: { // uzp1 vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_UZP2v2i64: { - return executionNYI(); + case Opcode::AArch64_UZP1v2i32: { // uzp1 vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_UZP2v4i16: { - return executionNYI(); + case Opcode::AArch64_UZP1v2i64: { // uzp1 vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_UZP2v4i32: { - return executionNYI(); + case Opcode::AArch64_UZP1v4i16: { // uzp1 vd.4h, vn.4h, vm.4h + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_UZP2v8i16: { - return executionNYI(); + case Opcode::AArch64_UZP1v4i32: { // uzp1 vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_UZP2v8i8: { - return executionNYI(); + case Opcode::AArch64_UZP1v8i16: { // uzp1 vd.8h, vn.8h, vm.8h + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_WHILELE_PWW_B: { - return executionNYI(); + case Opcode::AArch64_UZP1v8i8: { // uzp1 vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecUzp(operands, true); break; } - case Opcode::AArch64_WHILELE_PWW_D: { - return executionNYI(); + case Opcode::AArch64_UZP2v16i8: { // uzp2 vd.16b, vn.16b, vm.16b + results[0] = neonHelp::vecUzp(operands, false); break; } - case Opcode::AArch64_WHILELE_PWW_H: { - return executionNYI(); + case Opcode::AArch64_UZP2v2i32: { // uzp2 vd.2s, vn.2s, vm.2s + results[0] = neonHelp::vecUzp(operands, false); break; } - case Opcode::AArch64_WHILELE_PWW_S: { - return executionNYI(); + case Opcode::AArch64_UZP2v2i64: { // uzp2 vd.2d, vn.2d, vm.2d + results[0] = neonHelp::vecUzp(operands, false); break; } - case Opcode::AArch64_WHILELE_PXX_B: { - return executionNYI(); + case Opcode::AArch64_UZP2v4i16: { // uzp2 vd.4h, vn.4h, vm.4h + results[0] = neonHelp::vecUzp(operands, false); break; } - case Opcode::AArch64_WHILELE_PXX_D: { - return executionNYI(); + case Opcode::AArch64_UZP2v4i32: { // uzp2 vd.4s, vn.4s, vm.4s + results[0] = neonHelp::vecUzp(operands, false); break; } - case Opcode::AArch64_WHILELE_PXX_H: { - return executionNYI(); + case Opcode::AArch64_UZP2v8i16: { // uzp2 vd.8h, vn.8h, vm.8h + results[0] = neonHelp::vecUzp(operands, false); break; } - case Opcode::AArch64_WHILELE_PXX_S: { - return executionNYI(); + case Opcode::AArch64_UZP2v8i8: { // uzp2 vd.8b, vn.8b, vm.8b + results[0] = neonHelp::vecUzp(operands, false); break; } case Opcode::AArch64_WHILELO_PWW_B: { // whilelo pd.b, wn, wm @@ -18602,94 +4947,10 @@ void Instruction::execute() { results[1] = output; break; } - case Opcode::AArch64_WHILELS_PWW_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PWW_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PWW_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PWW_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PXX_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PXX_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PXX_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELS_PXX_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PWW_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PWW_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PWW_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PWW_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PXX_B: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PXX_D: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PXX_H: { - return executionNYI(); - break; - } - case Opcode::AArch64_WHILELT_PXX_S: { - return executionNYI(); - break; - } - case Opcode::AArch64_WRFFR: { - return executionNYI(); - break; - } - case Opcode::AArch64_XAR: { - return executionNYI(); - break; - } - case Opcode::AArch64_XPACD: { - return executionNYI(); - break; - } - case Opcode::AArch64_XPACI: { - return executionNYI(); - break; - } case Opcode::AArch64_XPACLRI: { // xpaclri // SimEng doesn't support PAC, so do nothing break; } - case Opcode::AArch64_XTNv16i8: { - return executionNYI(); - break; - } case Opcode::AArch64_XTNv2i32: { // xtn vd.2s, vn.2d results[0] = neonHelp::vecXtn(operands, false); break; @@ -18702,14 +4963,6 @@ void Instruction::execute() { results[0] = neonHelp::vecXtn(operands, true); break; } - case Opcode::AArch64_XTNv8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_XTNv8i8: { - return executionNYI(); - break; - } case Opcode::AArch64_ZIP1_PPP_B: { // zip1 pd.b, pn.b, pm.b results[0] = sveHelp::sveZip_preds(operands, VL_bits, false); break; @@ -18726,50 +4979,14 @@ void Instruction::execute() { results[0] = sveHelp::sveZip_preds(operands, VL_bits, false); break; } - case Opcode::AArch64_ZIP1_ZZZ_B: { - return executionNYI(); - break; - } case Opcode::AArch64_ZIP1_ZZZ_D: { // zip1 zd.d, zn.d, zm.d results[0] = sveHelp::sveZip_vecs(operands, VL_bits, false); break; } - case Opcode::AArch64_ZIP1_ZZZ_H: { - return executionNYI(); - break; - } case Opcode::AArch64_ZIP1_ZZZ_S: { // zip1 zd.s, zn.s, zm.s results[0] = sveHelp::sveZip_vecs(operands, VL_bits, false); break; } - case Opcode::AArch64_ZIP1v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP1v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP1v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP1v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP1v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP1v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP1v8i8: { - return executionNYI(); - break; - } case Opcode::AArch64_ZIP2_PPP_B: { // zip2 pd.b, pn.b, pm.b results[0] = sveHelp::sveZip_preds(operands, VL_bits, true); break; @@ -18786,52 +5003,16 @@ void Instruction::execute() { results[0] = sveHelp::sveZip_preds(operands, VL_bits, true); break; } - case Opcode::AArch64_ZIP2_ZZZ_B: { - return executionNYI(); - break; - } case Opcode::AArch64_ZIP2_ZZZ_D: { // zip2 zd.d, zn.d, zm.d results[0] = sveHelp::sveZip_vecs(operands, VL_bits, true); break; } - case Opcode::AArch64_ZIP2_ZZZ_H: { - return executionNYI(); - break; - } case Opcode::AArch64_ZIP2_ZZZ_S: { // zip2 zd.s, zn.s, zm.s results[0] = sveHelp::sveZip_vecs(operands, VL_bits, true); break; } - case Opcode::AArch64_ZIP2v16i8: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP2v2i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP2v2i64: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP2v4i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP2v4i32: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP2v8i16: { - return executionNYI(); - break; - } - case Opcode::AArch64_ZIP2v8i8: { - return executionNYI(); - break; - } default: - return executionINV(); + return executionNYI(); } } @@ -18842,7 +5023,8 @@ void Instruction::execute() { for (int i = 0; i < destinationRegisterCount; i++) { if ((destinationRegisters[i].type == RegisterType::VECTOR) && !isSVEData_) { if (results[i].size() != 256) - std::cerr << metadata.mnemonic << " opcode: " << metadata.opcode + std::cerr << "[SimEng:Instruction_execute] " << metadata.mnemonic + << " opcode: " << metadata.opcode << " has not been zero extended correctly\n"; } } diff --git a/src/lib/arch/aarch64/MicroDecoder.cc b/src/lib/arch/aarch64/MicroDecoder.cc index a04cea2723..9f70e2f249 100644 --- a/src/lib/arch/aarch64/MicroDecoder.cc +++ b/src/lib/arch/aarch64/MicroDecoder.cc @@ -462,8 +462,10 @@ cs_detail MicroDecoder::createDefaultDetail(std::vector opTypes) { 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: break; } } diff --git a/src/lib/kernel/Linux.cc b/src/lib/kernel/Linux.cc index 67c4d778c0..84962042db 100644 --- a/src/lib/kernel/Linux.cc +++ b/src/lib/kernel/Linux.cc @@ -67,14 +67,16 @@ std::string Linux::getSpecialFile(const std::string filename) { if (strncmp(filename.c_str(), prefix, strlen(prefix)) == 0) { for (int i = 0; i < supportedSpecialFiles_.size(); i++) { if (filename.find(supportedSpecialFiles_[i]) != std::string::npos) { - std::cerr << "-- Using Special File: " << filename.c_str() + std::cerr << "[SimEng:Linux] Using Special File: " << filename.c_str() << std::endl; return specialFilesDir_ + filename; } } - std::cerr << "-- WARNING: unable to open unsupported special file: " + std::cerr << "[SimEng:Linux] WARNING: unable to open unsupported " + "special file: " << "'" << filename.c_str() << "'" << std::endl - << "-- allowing simulation to continue" << std::endl; + << "[SimEng:Linux] allowing simulation to continue" + << std::endl; break; } } diff --git a/src/lib/kernel/LinuxProcess.cc b/src/lib/kernel/LinuxProcess.cc index 9601a34f4d..31e36d7f48 100644 --- a/src/lib/kernel/LinuxProcess.cc +++ b/src/lib/kernel/LinuxProcess.cc @@ -2,6 +2,7 @@ #include #include +#include namespace simeng { namespace kernel { @@ -22,7 +23,8 @@ LinuxProcess::LinuxProcess(const std::vector& commandLine, commandLine_(commandLine) { // Parse ELF file assert(commandLine.size() > 0); - Elf elf(commandLine[0]); + char* unwrappedProcImgPtr; + Elf elf(commandLine[0], &unwrappedProcImgPtr); if (!elf.isValid()) { return; } @@ -30,10 +32,8 @@ LinuxProcess::LinuxProcess(const std::vector& commandLine, entryPoint_ = elf.getEntryPoint(); - span elfProcessImage = elf.getProcessImage(); - // Align heap start to a 32-byte boundary - heapStart_ = alignToBoundary(elfProcessImage.size(), 32); + heapStart_ = alignToBoundary(elf.getProcessImageSize(), 32); // Set mmap region start to be an equal distance from the stack and heap // starts. Additionally, align to the page size (4kb) @@ -42,12 +42,20 @@ LinuxProcess::LinuxProcess(const std::vector& commandLine, // Calculate process image size, including heap + stack size_ = heapStart_ + HEAP_SIZE + STACK_SIZE; - processImage_ = new char[size_]; - // Copy ELF process image to process image - std::copy(elfProcessImage.begin(), elfProcessImage.end(), processImage_); + char* temp = (char*)realloc(unwrappedProcImgPtr, size_ * sizeof(char)); + if (temp == NULL) { + free(unwrappedProcImgPtr); + std::cerr << "[SimEng:LinuxProcess] ProcessImage cannot be constructed " + "successfully! " + "Reallocation failed." + << std::endl; + exit(EXIT_FAILURE); + } + unwrappedProcImgPtr = temp; - createStack(); + createStack(&unwrappedProcImgPtr); + processImage_ = std::shared_ptr(unwrappedProcImgPtr, free); } LinuxProcess::LinuxProcess(span instructions, YAML::Node config) @@ -67,18 +75,14 @@ LinuxProcess::LinuxProcess(span instructions, YAML::Node config) alignToBoundary(heapStart_ + (HEAP_SIZE + STACK_SIZE) / 2, pageSize_); size_ = heapStart_ + HEAP_SIZE + STACK_SIZE; - processImage_ = new char[size_]; - - std::copy(instructions.begin(), instructions.end(), processImage_); + char* unwrappedProcImgPtr = (char*)malloc(size_ * sizeof(char)); + std::copy(instructions.begin(), instructions.end(), unwrappedProcImgPtr); - createStack(); + createStack(&unwrappedProcImgPtr); + processImage_ = std::shared_ptr(unwrappedProcImgPtr, free); } -LinuxProcess::~LinuxProcess() { - if (isValid_) { - delete[] processImage_; - } -} +LinuxProcess::~LinuxProcess() {} uint64_t LinuxProcess::getHeapStart() const { return heapStart_; } @@ -92,15 +96,17 @@ std::string LinuxProcess::getPath() const { return commandLine_[0]; } bool LinuxProcess::isValid() const { return isValid_; } -const span LinuxProcess::getProcessImage() const { - return {processImage_, size_}; +std::shared_ptr LinuxProcess::getProcessImage() const { + return std::shared_ptr(processImage_); } +uint64_t LinuxProcess::getProcessImageSize() const { return size_; } + uint64_t LinuxProcess::getEntryPoint() const { return entryPoint_; } uint64_t LinuxProcess::getStackPointer() const { return stackPointer_; } -void LinuxProcess::createStack() { +void LinuxProcess::createStack(char** processImage) { // Decrement the stack pointer and populate with initial stack state // (https://www.win.tue.nl/~aeb/linux/hh/stack-layout.html) // The argv and env strings are added to the top of the stack first and the @@ -147,7 +153,7 @@ void LinuxProcess::createStack() { initialStackFrame.push_back(stackPointer_ + (i)); // argv/env ptr ptrCount++; } - processImage_[stackPointer_ + i] = stringBytes[i]; + (*processImage)[stackPointer_ + i] = stringBytes[i]; } initialStackFrame.push_back(0); // null terminator @@ -169,7 +175,7 @@ void LinuxProcess::createStack() { // Copy initial stack frame to process memory char* stackFrameBytes = reinterpret_cast(initialStackFrame.data()); std::copy(stackFrameBytes, stackFrameBytes + stackFrameSize, - processImage_ + stackPointer_); + (*processImage) + stackPointer_); } } // namespace kernel diff --git a/src/lib/models/emulation/Core.cc b/src/lib/models/emulation/Core.cc index c592482715..1d572ee160 100644 --- a/src/lib/models/emulation/Core.cc +++ b/src/lib/models/emulation/Core.cc @@ -27,14 +27,13 @@ Core::Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, // Query and apply initial state auto state = isa.getInitialState(); applyStateChange(state); - - // Get Virtual Counter Timer system register - VCTreg_ = isa_.getVCTreg(); } void Core::tick() { ticks_++; + if (hasHalted_) return; + if (pc_ >= programByteLength_) { hasHalted_ = true; return; @@ -85,7 +84,7 @@ void Core::tick() { const auto& instructionBytes = fetched[fetchIndex].data; auto bytesRead = isa_.predecode(instructionBytes.getAsVector(), - FETCH_SIZE, pc_, {false, 0}, macroOp_); + FETCH_SIZE, pc_, macroOp_); // Clear the fetched data instructionMemory_.clearCompletedReads(); @@ -160,6 +159,7 @@ void Core::tick() { } execute(uop); + isa_.updateSystemTimerRegisters(®isterFileSet_, ticks_); } void Core::execute(std::shared_ptr& uop) { @@ -212,9 +212,13 @@ void Core::handleException(const std::shared_ptr& instruction) { void Core::processExceptionHandler() { assert(exceptionHandler_ != nullptr && "Attempted to process an exception handler that wasn't present"); + if (dataMemory_.hasPendingRequests()) { + // Must wait for all memory requests to complete before processing the + // exception + return; + } bool success = exceptionHandler_->tick(); - if (!success) { // Handler needs further ticks to complete return; @@ -225,7 +229,7 @@ void Core::processExceptionHandler() { if (result.fatal) { pc_ = programByteLength_; hasHalted_ = true; - std::cout << "Halting due to fatal exception" << std::endl; + std::cout << "[SimEng:Core] Halting due to fatal exception" << std::endl; } else { pc_ = result.instructionAddress; applyStateChange(result.stateChange); @@ -279,11 +283,6 @@ void Core::applyStateChange(const arch::ProcessStateChange& change) { } } -void Core::incVCT(uint64_t iterations) { - registerFileSet_.set(VCTreg_, iterations); - return; -} - bool Core::hasHalted() const { return hasHalted_; } const ArchitecturalRegisterFileSet& Core::getArchitecturalRegisterFileSet() diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 8fa9125ea2..a9604bc085 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -13,10 +13,9 @@ namespace inorder { const unsigned int blockSize = 16; const unsigned int clockFrequency = 2.5 * 1e9; -Core::Core(FlatMemoryInterface& instructionMemory, - FlatMemoryInterface& dataMemory, uint64_t processMemorySize, - uint64_t entryPoint, const arch::Architecture& isa, - BranchPredictor& branchPredictor) +Core::Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, + uint64_t processMemorySize, uint64_t entryPoint, + const arch::Architecture& isa, BranchPredictor& branchPredictor) : dataMemory_(dataMemory), isa_(isa), registerFileSet_(isa.getRegisterFileStructures()), @@ -39,14 +38,13 @@ Core::Core(FlatMemoryInterface& instructionMemory, // Query and apply initial state auto state = isa.getInitialState(); applyStateChange(state); - - // Get Virtual Counter Timer system register - VCTreg_ = isa_.getVCTreg(); }; void Core::tick() { ticks_++; + if (hasHalted_) return; + if (exceptionHandler_ != nullptr) { processExceptionHandler(); return; @@ -89,6 +87,7 @@ void Core::tick() { // Update PC and wipe younger buffers (Fetch/Decode, Decode/Execute) auto targetAddress = executeUnit_.getFlushAddress(); + fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); fetchToDecodeBuffer_.fill({}); decodeToExecuteBuffer_.fill(nullptr); @@ -100,6 +99,7 @@ void Core::tick() { // Update PC and wipe Fetch/Decode buffer. auto targetAddress = decodeUnit_.getFlushAddress(); + fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); fetchToDecodeBuffer_.fill({}); @@ -107,6 +107,7 @@ void Core::tick() { } fetchUnit_.requestFromPC(); + isa_.updateSystemTimerRegisters(®isterFileSet_, ticks_); } bool Core::hasHalted() const { @@ -114,14 +115,15 @@ bool Core::hasHalted() const { return true; } - // Core is considered to have halted when the fetch unit has halted, and there - // are no uops at the head of any buffer. + // Core is considered to have halted when the fetch unit has halted, there + // are no uops at the head of any buffer, and no exception is currently being + // handled. bool decodePending = fetchToDecodeBuffer_.getHeadSlots()[0].size() > 0; bool executePending = decodeToExecuteBuffer_.getHeadSlots()[0] != nullptr; bool writebackPending = completionSlots_[0].getHeadSlots()[0] != nullptr; return (fetchUnit_.hasHalted() && !decodePending && !writebackPending && - !executePending); + !executePending && exceptionHandler_ == nullptr); } const ArchitecturalRegisterFileSet& Core::getArchitecturalRegisterFileSet() @@ -186,6 +188,11 @@ void Core::handleException() { void Core::processExceptionHandler() { assert(exceptionHandler_ != nullptr && "Attempted to process an exception handler that wasn't present"); + if (dataMemory_.hasPendingRequests()) { + // Must wait for all memory requests to complete before processing the + // exception + return; + } auto success = exceptionHandler_->tick(); if (!success) { @@ -197,8 +204,9 @@ void Core::processExceptionHandler() { if (result.fatal) { hasHalted_ = true; - std::cout << "Halting due to fatal exception" << std::endl; + std::cout << "[SimEng:Core] Halting due to fatal exception" << std::endl; } else { + fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(result.instructionAddress); applyStateChange(result.stateChange); } @@ -332,11 +340,6 @@ void Core::applyStateChange(const arch::ProcessStateChange& change) { } } -void Core::incVCT(uint64_t iterations) { - registerFileSet_.set(VCTreg_, iterations); - return; -} - void Core::handleLoad(const std::shared_ptr& instruction) { loadData(instruction); if (instruction->exceptionEncountered()) { diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 9cd6e36cd2..a16e15a2f5 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -14,13 +14,10 @@ namespace models { namespace outoforder { // TODO: System register count has to match number of supported system registers - Core::Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, uint64_t processMemorySize, uint64_t entryPoint, const arch::Architecture& isa, BranchPredictor& branchPredictor, - pipeline::PortAllocator& portAllocator, - const std::vector>& rsArrangement, - YAML::Node config) + pipeline::PortAllocator& portAllocator, YAML::Node config) : isa_(isa), physicalRegisterStructures_( {{8, config["Register-Set"]["GeneralPurpose-Count"].as()}, @@ -28,12 +25,13 @@ Core::Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, config["Register-Set"]["FloatingPoint/SVE-Count"].as()}, {32, config["Register-Set"]["Predicate-Count"].as()}, {1, config["Register-Set"]["Conditional-Count"].as()}, - {8, 6}}), + {8, isa.getNumSystemRegisters()}}), physicalRegisterQuantities_( {config["Register-Set"]["GeneralPurpose-Count"].as(), config["Register-Set"]["FloatingPoint/SVE-Count"].as(), config["Register-Set"]["Predicate-Count"].as(), - config["Register-Set"]["Conditional-Count"].as(), 6}), + config["Register-Set"]["Conditional-Count"].as(), + isa.getNumSystemRegisters()}), registerFileSet_(physicalRegisterStructures_), registerAliasTable_(isa.getRegisterFileStructures(), physicalRegisterQuantities_), @@ -58,26 +56,33 @@ Core::Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, [this](auto regs, auto values) { dispatchIssueUnit_.forwardOperands(regs, values); }, - config["L1-Cache"]["Exclusive"].as(), - config["L1-Cache"]["Load-Bandwidth"].as(), - config["L1-Cache"]["Store-Bandwidth"].as(), - config["L1-Cache"]["Permitted-Requests-Per-Cycle"].as(), - config["L1-Cache"]["Permitted-Loads-Per-Cycle"].as(), - config["L1-Cache"]["Permitted-Stores-Per-Cycle"].as()), - reorderBuffer_(config["Queue-Sizes"]["ROB"].as(), - registerAliasTable_, loadStoreQueue_, - [this](auto instruction) { raiseException(instruction); }), + config["LSQ-L1-Interface"]["Exclusive"].as(), + config["LSQ-L1-Interface"]["Load-Bandwidth"].as(), + config["LSQ-L1-Interface"]["Store-Bandwidth"].as(), + config["LSQ-L1-Interface"]["Permitted-Requests-Per-Cycle"] + .as(), + config["LSQ-L1-Interface"]["Permitted-Loads-Per-Cycle"] + .as(), + config["LSQ-L1-Interface"]["Permitted-Stores-Per-Cycle"] + .as()), fetchUnit_(fetchToDecodeBuffer_, instructionMemory, processMemorySize, - entryPoint, config["Core"]["Fetch-Block-Size"].as(), + entryPoint, config["Fetch"]["Fetch-Block-Size"].as(), isa, branchPredictor), + reorderBuffer_( + config["Queue-Sizes"]["ROB"].as(), registerAliasTable_, + loadStoreQueue_, + [this](auto instruction) { raiseException(instruction); }, + [this](auto branchAddress) { + fetchUnit_.registerLoopBoundary(branchAddress); + }, + branchPredictor, config["Fetch"]["Loop-Buffer-Size"].as(), + config["Fetch"]["Loop-Detection-Threshold"].as()), decodeUnit_(fetchToDecodeBuffer_, decodeToRenameBuffer_, branchPredictor), renameUnit_(decodeToRenameBuffer_, renameToDispatchBuffer_, reorderBuffer_, registerAliasTable_, loadStoreQueue_, physicalRegisterStructures_.size()), - dispatchIssueUnit_( - renameToDispatchBuffer_, issuePorts_, registerFileSet_, portAllocator, - physicalRegisterQuantities_, rsArrangement, - config["Pipeline-Widths"]["Dispatch-Rate"].as()), + dispatchIssueUnit_(renameToDispatchBuffer_, issuePorts_, registerFileSet_, + portAllocator, physicalRegisterQuantities_, config), writebackUnit_( completionSlots_, registerFileSet_, [this](auto insnId) { reorderBuffer_.commitMicroOps(insnId); }), @@ -110,14 +115,13 @@ Core::Core(MemoryInterface& instructionMemory, MemoryInterface& dataMemory, // Query and apply initial state auto state = isa.getInitialState(); applyStateChange(state); - - // Get Virtual Counter Timer system register - VCTreg_ = isa_.getVCTreg(); }; void Core::tick() { ticks_++; + if (hasHalted_) return; + if (exceptionHandler_ != nullptr) { processExceptionHandler(); return; @@ -169,6 +173,7 @@ void Core::tick() { flushIfNeeded(); fetchUnit_.requestFromPC(); + isa_.updateSystemTimerRegisters(®isterFileSet_, ticks_); } void Core::flushIfNeeded() { @@ -196,6 +201,7 @@ void Core::flushIfNeeded() { targetAddress = reorderBuffer_.getFlushAddress(); } + fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); @@ -221,6 +227,7 @@ void Core::flushIfNeeded() { // Update PC and wipe Fetch/Decode buffer. targetAddress = decodeUnit_.getFlushAddress(); + fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); @@ -234,8 +241,9 @@ bool Core::hasHalted() const { return true; } - // Core is considered to have halted when the fetch unit has halted, and there - // are no uops at the head of any buffer. + // Core is considered to have halted when the fetch unit has halted, there + // are no uops at the head of any buffer, and no exception is currently being + // handled. if (!fetchUnit_.hasHalted()) { return false; } @@ -258,6 +266,8 @@ bool Core::hasHalted() const { } } + if (exceptionHandler_ != nullptr) return false; + return true; } @@ -296,6 +306,11 @@ void Core::handleException() { void Core::processExceptionHandler() { assert(exceptionHandler_ != nullptr && "Attempted to process an exception handler that wasn't present"); + if (dataMemory_.hasPendingRequests()) { + // Must wait for all memory requests to complete before processing the + // exception + return; + } bool success = exceptionHandler_->tick(); if (!success) { @@ -307,8 +322,9 @@ void Core::processExceptionHandler() { if (result.fatal) { hasHalted_ = true; - std::cout << "Halting due to fatal exception" << std::endl; + std::cout << "[SimEng:Core] Halting due to fatal exception" << std::endl; } else { + fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(result.instructionAddress); applyStateChange(result.stateChange); } @@ -358,11 +374,6 @@ void Core::applyStateChange(const arch::ProcessStateChange& change) { } } -void Core::incVCT(uint64_t iterations) { - registerFileSet_.set(VCTreg_, iterations); - return; -} - const ArchitecturalRegisterFileSet& Core::getArchitecturalRegisterFileSet() const { return mappedRegisterFileSet_; diff --git a/src/lib/pipeline/A64FXPortAllocator.cc b/src/lib/pipeline/A64FXPortAllocator.cc index 930bf46564..ba1db0471e 100644 --- a/src/lib/pipeline/A64FXPortAllocator.cc +++ b/src/lib/pipeline/A64FXPortAllocator.cc @@ -12,13 +12,13 @@ A64FXPortAllocator::A64FXPortAllocator( : // Initiliase reservation station to port mapping rsToPort_({{0, 1, 2}, {3, 4}, {5}, {6}, {7}}) {} -uint8_t A64FXPortAllocator::allocate(const std::vector& ports) { +uint16_t A64FXPortAllocator::allocate(const std::vector& ports) { assert(ports.size() && "No supported ports supplied; cannot allocate from a empty set"); const uint8_t attribute = attributeMapping(ports); - uint8_t rs = 0; - uint8_t port = 0; + uint16_t rs = 0; + uint16_t port = 0; bool foundRS = false; bool foundPort = false; @@ -144,11 +144,11 @@ uint8_t A64FXPortAllocator::allocate(const std::vector& ports) { return port; } -void A64FXPortAllocator::issued(uint8_t port) {} -void A64FXPortAllocator::deallocate(uint8_t port) { issued(port); }; +void A64FXPortAllocator::issued(uint16_t port) {} +void A64FXPortAllocator::deallocate(uint16_t port) { issued(port); }; uint8_t A64FXPortAllocator::attributeMapping( - const std::vector& ports) { + const std::vector& ports) { uint8_t attribute = 0; bool foundAttribute = false; if (ports == EXA_EXB_EAGA_EAGB) { // EXA,EXB,EAGA,EAGB diff --git a/src/lib/pipeline/BalancedPortAllocator.cc b/src/lib/pipeline/BalancedPortAllocator.cc index f692c3c478..a3db3f85e4 100644 --- a/src/lib/pipeline/BalancedPortAllocator.cc +++ b/src/lib/pipeline/BalancedPortAllocator.cc @@ -9,12 +9,12 @@ BalancedPortAllocator::BalancedPortAllocator( const std::vector>& portArrangement) : weights(portArrangement.size(), 0) {} -uint8_t BalancedPortAllocator::allocate(const std::vector& ports) { +uint16_t BalancedPortAllocator::allocate(const std::vector& ports) { assert(ports.size() && "No supported ports supplied; cannot allocate from a empty set"); bool foundPort = false; uint16_t bestWeight = 0xFFFF; - uint8_t bestPort = 0; + uint16_t bestPort = 0; for (const auto& portIndex : ports) { // Search for the lowest-weighted port available if (!foundPort || weights[portIndex] < bestWeight) { @@ -31,11 +31,11 @@ uint8_t BalancedPortAllocator::allocate(const std::vector& ports) { return bestPort; } -void BalancedPortAllocator::issued(uint8_t port) { +void BalancedPortAllocator::issued(uint16_t port) { assert(weights[port] > 0); weights[port]--; } -void BalancedPortAllocator::deallocate(uint8_t port) { issued(port); }; +void BalancedPortAllocator::deallocate(uint16_t port) { issued(port); }; void BalancedPortAllocator::setRSSizeGetter( std::function&)> rsSizes) { diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 77a9858dcc..5bb497e653 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -63,25 +63,25 @@ void DecodeUnit::tick() { if (!uop->isBranch()) { // Non-branch incorrectly predicted as a branch; let the predictor know - predictor_.update(uop, false, pc_); - // Remove macro-operations in microOps_ buffer after macro-operation - // decoded in this cycle - auto uopIt = microOps_.begin(); - // Find first microOps_ entry not belonging to same address as flushing - // instruction - while (uopIt != microOps_.end()) { - if ((*uopIt)->getInstructionAddress() != - uop->getInstructionAddress()) { - break; - } else { - uopIt++; - } - } - // Remove all entries after first macro-operation in buffer - while (uopIt != microOps_.end()) { - uopIt = microOps_.erase(uopIt); + predictor_.update(uop->getInstructionAddress(), false, pc_, + uop->getBranchType()); + } + // Remove macro-operations in microOps_ buffer after macro-operation + // decoded in this cycle + auto uopIt = microOps_.begin(); + // Find first microOps_ entry not belonging to same address as flushing + // instruction + while (uopIt != microOps_.end()) { + if ((*uopIt)->getInstructionAddress() != uop->getInstructionAddress()) { + break; + } else { + uopIt++; } } + // Remove all entries after first macro-operation in buffer + while (uopIt != microOps_.end()) { + uopIt = microOps_.erase(uopIt); + } // Skip processing remaining uops, as they need to be flushed break; diff --git a/src/lib/pipeline/DispatchIssueUnit.cc b/src/lib/pipeline/DispatchIssueUnit.cc index ecf5169d63..d79675e09d 100644 --- a/src/lib/pipeline/DispatchIssueUnit.cc +++ b/src/lib/pipeline/DispatchIssueUnit.cc @@ -2,7 +2,6 @@ #include #include -#include namespace simeng { namespace pipeline { @@ -11,51 +10,54 @@ DispatchIssueUnit::DispatchIssueUnit( PipelineBuffer>& fromRename, std::vector>>& issuePorts, const RegisterFileSet& registerFileSet, PortAllocator& portAllocator, - const std::vector& physicalRegisterStructure, - std::vector> rsArrangement, - uint8_t dispatchRate) + const std::vector& physicalRegisterStructure, YAML::Node config) : input_(fromRename), issuePorts_(issuePorts), registerFileSet_(registerFileSet), scoreboard_(physicalRegisterStructure.size()), dependencyMatrix_(physicalRegisterStructure.size()), - portAllocator_(portAllocator), - dispatchRate_(dispatchRate) { + portAllocator_(portAllocator) { // Initialise scoreboard for (size_t type = 0; type < physicalRegisterStructure.size(); type++) { scoreboard_[type].assign(physicalRegisterStructure[type], true); dependencyMatrix_[type].resize(physicalRegisterStructure[type]); } - // Create set of reservation station structs with correct issue port mappings - for (int port = 0; port < rsArrangement.size(); port++) { - auto RS = rsArrangement[port]; - if (reservationStations_.size() < RS.first + 1) { - std::vector ports; - reservationStations_.resize(RS.first + 1, {0, 0, ports}); - } - reservationStations_[RS.first].capacity = RS.second; - // Find number of ports already mapping to the given RS - uint8_t port_index = 0; - for (auto rsPort : portMapping_) { - if (rsPort.first == RS.first) { - port_index++; + // Create set of reservation station structs with correct issue port + // mappings + for (size_t i = 0; i < config["Reservation-Stations"].size(); i++) { + // Iterate over each reservation station in config + auto reservation_station = config["Reservation-Stations"][i]; + // Create ReservationStation struct to be stored + ReservationStation rs = { + reservation_station["Size"].as(), + reservation_station["Dispatch-Rate"].as(), + 0, + {}}; + // Resize rs port attribute to match what's defined in config file + rs.ports.resize(reservation_station["Ports"].size()); + for (size_t j = 0; j < reservation_station["Ports"].size(); j++) { + // Iterate over issue ports in config + uint16_t issue_port = reservation_station["Ports"][j].as(); + rs.ports[j].issuePort = issue_port; + // Add port mapping entry, resizing vector if needed + if ((issue_port + 1) > portMapping_.size()) { + portMapping_.resize((issue_port + 1)); } + portMapping_[issue_port] = {i, j}; } - // Add port - portMapping_.push_back({RS.first, port_index}); - reservationStations_[RS.first].ports.resize(port_index + 1); - reservationStations_[RS.first].ports[port_index].issuePort = port; + reservationStations_.push_back(rs); } - dispatches.resize(reservationStations_.size()); - for (uint8_t i = 0; i < reservationStations_.size(); i++) + for (uint16_t i = 0; i < reservationStations_.size(); i++) flushed_.emplace(i, std::initializer_list>{}); } void DispatchIssueUnit::tick() { input_.stall(false); - // Reset the counters - std::fill(dispatches.begin(), dispatches.end(), 0); + /** Stores the number of instructions dispatched for each + * reservation station. */ + std::vector dispatches = { + 0, static_cast(reservationStations_.size())}; for (size_t slot = 0; slot < input_.getWidth(); slot++) { auto& uop = input_.getHeadSlots()[slot]; @@ -63,7 +65,7 @@ void DispatchIssueUnit::tick() { continue; } - const std::vector& supportedPorts = uop->getSupportedPorts(); + const std::vector& supportedPorts = uop->getSupportedPorts(); if (uop->exceptionEncountered()) { // Exception; mark as ready to commit, and remove from pipeline uop->setCommitReady(); @@ -71,16 +73,16 @@ void DispatchIssueUnit::tick() { continue; } // Allocate issue port to uop - uint8_t port = portAllocator_.allocate(supportedPorts); - uint8_t RS_Index = portMapping_[port].first; - uint8_t RS_Port = portMapping_[port].second; + uint16_t port = portAllocator_.allocate(supportedPorts); + uint16_t RS_Index = portMapping_[port].first; + uint16_t RS_Port = portMapping_[port].second; assert(RS_Index < reservationStations_.size() && "Allocated port inaccessible"); ReservationStation& rs = reservationStations_[RS_Index]; // When appropriate, stall uop or input buffer if stall buffer full if (rs.currentSize == rs.capacity || - dispatches[RS_Index] == dispatchRate_) { + dispatches[RS_Index] == rs.dispatchRate) { // Deallocate port given portAllocator_.deallocate(port); input_.stall(true); diff --git a/src/lib/pipeline/ExecuteUnit.cc b/src/lib/pipeline/ExecuteUnit.cc index 01bccf220f..83a71c5b1a 100644 --- a/src/lib/pipeline/ExecuteUnit.cc +++ b/src/lib/pipeline/ExecuteUnit.cc @@ -142,7 +142,8 @@ void ExecuteUnit::execute(std::shared_ptr& uop) { pc_ = uop->getBranchAddress(); // Update branch predictor with branch results - predictor_.update(uop, uop->wasBranchTaken(), pc_); + predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), pc_, + uop->getBranchType()); // Update the branch instruction counter branchesExecuted_++; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 3ad14f885e..ade3d307c0 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -33,6 +33,29 @@ void FetchUnit::tick() { return; } + // If loop buffer has been filled, fill buffer to decode + if (loopBufferState_ == LoopBufferState::SUPPLYING) { + auto outputSlots = output_.getTailSlots(); + for (size_t slot = 0; slot < output_.getWidth(); slot++) { + auto& macroOp = outputSlots[slot]; + auto bytesRead = isa_.predecode(&(loopBuffer_.front().encoding), + loopBuffer_.front().instructionSize, + loopBuffer_.front().address, macroOp); + + assert(bytesRead != 0 && "predecode failure for loop buffer entry"); + + // Set prediction to recorded value during loop buffer filling + if (macroOp[0]->isBranch()) { + macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + } + + // Cycle queue by moving front entry to back + loopBuffer_.push_back(loopBuffer_.front()); + loopBuffer_.pop_front(); + } + return; + } + // Pointer to the instruction data to decode from const uint8_t* buffer; uint8_t bufferOffset; @@ -91,9 +114,8 @@ void FetchUnit::tick() { for (size_t slot = 0; slot < output_.getWidth(); slot++) { auto& macroOp = outputSlots[slot]; - BranchPrediction prediction = {false, 0}; - auto bytesRead = isa_.predecode(buffer + bufferOffset, bufferedBytes_, pc_, - prediction, macroOp); + auto bytesRead = + isa_.predecode(buffer + bufferOffset, bufferedBytes_, pc_, macroOp); // If predecode fails, bail and wait for more data if (bytesRead == 0) { @@ -102,17 +124,42 @@ void FetchUnit::tick() { break; } + // Create branch prediction after identifing instruction type + // (e.g. RET, BL, etc). + BranchPrediction prediction = {false, 0}; + if (macroOp[0]->isBranch()) { + prediction = branchPredictor_.predict(pc_, macroOp[0]->getBranchType(), + macroOp[0]->getKnownTarget()); + macroOp[0]->setBranchPrediction(prediction); + } + + if (loopBufferState_ == LoopBufferState::FILLING) { + // Record instruction fetch information in loop body + uint32_t encoding; + memcpy(&encoding, buffer + bufferOffset, sizeof(uint32_t)); + loopBuffer_.push_back( + {encoding, bytesRead, pc_, macroOp[0]->getBranchPrediction()}); + + if (pc_ == loopBoundaryAddress_) { + // loopBoundaryAddress_ has been fetched whilst filling the loop buffer. + // Stop filling as loop body has been recorded and begin to supply + // decode unit with instructions from the loop buffer + loopBufferState_ = LoopBufferState::SUPPLYING; + bufferedBytes_ = 0; + break; + } + } else if (loopBufferState_ == LoopBufferState::WAITING && + pc_ == loopBoundaryAddress_) { + // Once set loopBoundaryAddress_ is fetched, start to fill loop buffer + loopBufferState_ = LoopBufferState::FILLING; + } + assert(bytesRead <= bufferedBytes_ && "Predecode consumed more bytes than were available"); // Increment the offset, decrement available bytes bufferOffset += bytesRead; bufferedBytes_ -= bytesRead; - // Create branch prediction after identifing instruction type - // (e.g. RET, BL, etc). - prediction = branchPredictor_.predict(macroOp[0]); - macroOp[0]->setBranchPrediction(prediction); - if (!prediction.taken) { // Predicted as not taken; increment PC to next instruction pc_ += bytesRead; @@ -149,6 +196,14 @@ void FetchUnit::tick() { instructionMemory_.clearCompletedReads(); } +void FetchUnit::registerLoopBoundary(uint64_t branchAddress) { + // Set branch which forms the loop as the loopBoundaryAddress_ and place loop + // buffer in state to begin filling once the loopBoundaryAddress_ has been + // fetched + loopBufferState_ = LoopBufferState::WAITING; + loopBoundaryAddress_ = branchAddress; +} + bool FetchUnit::hasHalted() const { return hasHalted_; } void FetchUnit::updatePC(uint64_t address) { @@ -180,5 +235,11 @@ void FetchUnit::requestFromPC() { uint64_t FetchUnit::getBranchStalls() const { return branchStalls_; } +void FetchUnit::flushLoopBuffer() { + loopBuffer_.clear(); + loopBufferState_ = LoopBufferState::IDLE; + loopBoundaryAddress_ = 0; +} + } // namespace pipeline } // namespace simeng diff --git a/src/lib/pipeline/LoadStoreQueue.cc b/src/lib/pipeline/LoadStoreQueue.cc index a078be03ed..044990c9a4 100644 --- a/src/lib/pipeline/LoadStoreQueue.cc +++ b/src/lib/pipeline/LoadStoreQueue.cc @@ -19,8 +19,9 @@ LoadStoreQueue::LoadStoreQueue( unsigned int maxCombinedSpace, MemoryInterface& memory, span>> completionSlots, std::function, span)> forwardOperands, - bool exclusive, uint8_t loadBandwidth, uint8_t storeBandwidth, - uint8_t permittedRequests, uint8_t permittedLoads, uint8_t permittedStores) + bool exclusive, uint16_t loadBandwidth, uint16_t storeBandwidth, + uint16_t permittedRequests, uint16_t permittedLoads, + uint16_t permittedStores) : completionSlots_(completionSlots), forwardOperands_(forwardOperands), maxCombinedSpace_(maxCombinedSpace), @@ -38,8 +39,9 @@ LoadStoreQueue::LoadStoreQueue( MemoryInterface& memory, span>> completionSlots, std::function, span)> forwardOperands, - bool exclusive, uint8_t loadBandwidth, uint8_t storeBandwidth, - uint8_t permittedRequests, uint8_t permittedLoads, uint8_t permittedStores) + bool exclusive, uint16_t loadBandwidth, uint16_t storeBandwidth, + uint16_t permittedRequests, uint16_t permittedLoads, + uint16_t permittedStores) : completionSlots_(completionSlots), forwardOperands_(forwardOperands), maxLoadQueueSpace_(maxLoadQueueSpace), @@ -374,7 +376,7 @@ void LoadStoreQueue::tick() { // Send memory requests adhering to set bandwidth and number of permitted // requests per cycle // Index 0: loads, index 1: stores - std::array reqCounts = {0, 0}; + std::array reqCounts = {0, 0}; std::array dataTransfered = {0, 0}; std::array exceededLimits = {false, false}; auto itLoad = requestLoadQueue_.begin(); @@ -423,7 +425,7 @@ void LoadStoreQueue::tick() { // Iterate over requests ready this cycle while (itInsn != itReq->second.end()) { - // Increment count of this request type + // Speculatively increment count of this request type reqCounts[isStore]++; // Ensure the limit on the number of permitted operations is adhered @@ -435,6 +437,9 @@ void LoadStoreQueue::tick() { } else if (reqCounts[isStore] > reqLimits_[isStore]) { // No more requests of this type can be scheduled this cycle exceededLimits[isStore] = true; + // Remove speculative increment to ensure it doesn't count for + // comparisons aginast the totalLimit_ + reqCounts[isStore]--; break; } else { // Schedule requests from the queue of addresses in @@ -518,6 +523,12 @@ void LoadStoreQueue::tick() { while (completedLoads_.size() > 0 && count < completionSlots_.size()) { const auto& insn = completedLoads_.front(); + // Don't process load instruction if it has been flushed + if (insn->isFlushed()) { + completedLoads_.pop(); + continue; + } + // Forward the results forwardOperands_(insn->getDestinationRegisters(), insn->getResults()); diff --git a/src/lib/pipeline/M1PortAllocator.cc b/src/lib/pipeline/M1PortAllocator.cc new file mode 100644 index 0000000000..a8705d9ba7 --- /dev/null +++ b/src/lib/pipeline/M1PortAllocator.cc @@ -0,0 +1,70 @@ +#include "simeng/pipeline/M1PortAllocator.hh" + +#include +#include +#include + +namespace simeng { +namespace pipeline { + +M1PortAllocator::M1PortAllocator( + const std::vector>& portArrangement, + std::vector> rsArrangement) + : weights(portArrangement.size(), 0), rsArrangement_(rsArrangement) {} + +uint16_t M1PortAllocator::allocate(const std::vector& ports) { + assert(ports.size() && + "No supported ports supplied; cannot allocate from a empty set"); + bool foundPort = false; + uint16_t bestPort = 0; + uint16_t bestWeight = 0xFFFF; + + uint16_t bestRSQueueSize = 0xFFFF; + bool foundRS = false; + + // Update the the reference for number of free spaces in the reservation + // stations + std::vector rsFreeSpaces; + rsSizes_(rsFreeSpaces); + + for (const auto& portIndex : ports) { + auto rsIndex = rsArrangement_[portIndex].first; + auto rsSize = rsArrangement_[portIndex].second; + auto rsFreeSpace = rsFreeSpaces[rsIndex]; + auto rsQueueSize = (rsSize - rsFreeSpace); + + if (rsQueueSize < bestRSQueueSize) { + bestRSQueueSize = rsQueueSize; + foundRS = true; + + // Search for the lowest-weighted port available + if (!foundPort || weights[portIndex] < bestWeight) { + foundPort = true; + bestWeight = weights[portIndex]; + bestPort = portIndex; + } + } + } + + assert(foundPort && foundRS && "Unsupported group; cannot allocate a port"); + + // Increment the weight of the allocated port + weights[bestPort]++; + return bestPort; +} + +void M1PortAllocator::issued(uint16_t port) { + assert(weights[port] > 0); + weights[port]--; +} + +void M1PortAllocator::deallocate(uint16_t port) { issued(port); }; + +void M1PortAllocator::setRSSizeGetter( + std::function&)> rsSizes) { + rsSizes_ = rsSizes; +} + +void M1PortAllocator::tick() {} +} // namespace pipeline +} // namespace simeng diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index d49e131bb2..9ce147ce27 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -9,11 +9,18 @@ namespace pipeline { ReorderBuffer::ReorderBuffer( unsigned int maxSize, RegisterAliasTable& rat, LoadStoreQueue& lsq, - std::function&)> raiseException) + std::function&)> raiseException, + std::function sendLoopBoundary, + BranchPredictor& predictor, uint16_t loopBufSize, + uint16_t loopDetectionThreshold) : rat_(rat), lsq_(lsq), maxSize_(maxSize), - raiseException_(raiseException) {} + raiseException_(raiseException), + sendLoopBoundary_(sendLoopBoundary), + predictor_(predictor), + loopBufSize_(loopBufSize), + loopDetectionThreshold_(loopDetectionThreshold) {} void ReorderBuffer::reserve(const std::shared_ptr& insn) { assert(buffer_.size() < maxSize_ && @@ -84,7 +91,6 @@ unsigned int ReorderBuffer::commit(unsigned int maxCommitSize) { } const auto& destinations = uop->getDestinationRegisters(); - const auto& results = uop->getResults(); for (int i = 0; i < destinations.size(); i++) { rat_.commit(destinations[i]); } @@ -107,6 +113,42 @@ unsigned int ReorderBuffer::commit(unsigned int maxCommitSize) { return n + 1; } } + + // Increment or swap out branch counter for loop detection + if (uop->isBranch() && !loopDetected_) { + bool increment = true; + if (branchCounter_.first.address != uop->getInstructionAddress()) { + // Mismatch on instruction address, reset + increment = false; + } else if (branchCounter_.first.outcome != uop->getBranchPrediction()) { + // Mismatch on branch outcome, reset + increment = false; + } else if ((instructionsCommitted_ - branchCounter_.first.commitNumber) > + loopBufSize_) { + // Loop too big to fit in loop buffer, reset + increment = false; + } + + if (increment) { + // Reset commitNumber value + branchCounter_.first.commitNumber = instructionsCommitted_; + // Increment counter + branchCounter_.second++; + + if (branchCounter_.second > loopDetectionThreshold_) { + // If the same branch with the same outcome is sequentially retired + // more times than the loopDetectionThreshold_ value, identify as a + // loop boundary + loopDetected_ = true; + sendLoopBoundary_(uop->getInstructionAddress()); + } + } else { + // Swap out latest branch + branchCounter_ = {{uop->getInstructionAddress(), + uop->getBranchPrediction(), instructionsCommitted_}, + 0}; + } + } buffer_.pop_front(); } @@ -130,8 +172,16 @@ void ReorderBuffer::flush(uint64_t afterSeqId) { rat_.rewind(reg); } uop->setFlushed(); + // If the instruction is a branch, supply address to branch flushing logic + if (uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } buffer_.pop_back(); } + + // Reset branch counter and loop detection + branchCounter_ = {{0, {false, 0}, 0}, 0}; + loopDetected_ = false; } unsigned int ReorderBuffer::size() const { return buffer_.size(); } diff --git a/src/tools/simeng/main.cc b/src/tools/simeng/main.cc index 6a380fca12..c920b4afdd 100644 --- a/src/tools/simeng/main.cc +++ b/src/tools/simeng/main.cc @@ -5,45 +5,21 @@ #include #include -#include "simeng/AlwaysNotTakenPredictor.hh" -#include "simeng/BTBPredictor.hh" -#include "simeng/BTB_BWTPredictor.hh" #include "simeng/Core.hh" -#include "simeng/Elf.hh" -#include "simeng/FixedLatencyMemoryInterface.hh" -#include "simeng/FlatMemoryInterface.hh" -#include "simeng/ModelConfig.hh" +#include "simeng/CoreInstance.hh" +#include "simeng/MemoryInterface.hh" #include "simeng/SpecialFileDirGen.hh" -#include "simeng/arch/Architecture.hh" -#include "simeng/arch/aarch64/Architecture.hh" -#include "simeng/arch/aarch64/Instruction.hh" -#include "simeng/arch/aarch64/MicroDecoder.hh" -#include "simeng/kernel/Linux.hh" -#include "simeng/models/emulation/Core.hh" -#include "simeng/models/inorder/Core.hh" -#include "simeng/models/outoforder/Core.hh" -#include "simeng/pipeline/A64FXPortAllocator.hh" -#include "simeng/pipeline/BalancedPortAllocator.hh" #include "simeng/version.hh" -#include "yaml-cpp/yaml.h" - -enum class SimulationMode { Emulation, InOrderPipelined, OutOfOrder }; - -float clockFreq_; -uint32_t timerFreq_; /** Tick the provided core model until it halts. */ -int simulate(simeng::Core& core, simeng::MemoryInterface& instructionMemory, - simeng::MemoryInterface& dataMemory) { - int iterations = 0; - float timerModulo = (clockFreq_ * 1e9) / (timerFreq_ * 1e6); +int simulate(simeng::Core& core, simeng::MemoryInterface& dataMemory, + simeng::MemoryInterface& instructionMemory) { + uint64_t iterations = 0; // Tick the core and memory interfaces until the program has halted while (!core.hasHalted() || dataMemory.hasPendingRequests()) { // Tick the core core.tick(); - // Update Virtual Counter Timer at correct frequency. - if (iterations % (uint32_t)timerModulo == 0) core.incVCT(iterations); // Tick memory instructionMemory.tick(); @@ -57,268 +33,89 @@ int simulate(simeng::Core& core, simeng::MemoryInterface& instructionMemory, int main(int argc, char** argv) { // Print out build metadata - std::cout << "Build metadata:" << std::endl; - std::cout << "\tVersion: " SIMENG_VERSION << std::endl; - std::cout << "\tCompile Time - Date: " __TIME__ " - " __DATE__ << std::endl; - std::cout << "\tBuild type: " SIMENG_BUILD_TYPE << std::endl; - std::cout << "\tCompile options: " SIMENG_COMPILE_OPTIONS << std::endl; - std::cout << "\tTest suite: " SIMENG_ENABLE_TESTS << std::endl; + std::cout << "[SimEng] Build metadata:" << std::endl; + std::cout << "[SimEng] \tVersion: " SIMENG_VERSION << std::endl; + std::cout << "[SimEng] \tCompile Time - Date: " __TIME__ " - " __DATE__ + << std::endl; + std::cout << "[SimEng] \tBuild type: " SIMENG_BUILD_TYPE << std::endl; + std::cout << "[SimEng] \tCompile options: " SIMENG_COMPILE_OPTIONS + << std::endl; + std::cout << "[SimEng] \tTest suite: " SIMENG_ENABLE_TESTS << std::endl; std::cout << std::endl; - SimulationMode mode = SimulationMode::InOrderPipelined; + // Create the instance of the core to be simulated + std::unique_ptr coreInstance; std::string executablePath = ""; - YAML::Node config; + std::string configFilePath = ""; + std::vector executableArgs = {}; + // Determine if a config file has been supplied. if (argc > 1) { - config = simeng::ModelConfig(argv[1]).getConfigFile(); - } else { - config = YAML::Load(DEFAULT_CONFIG); - } - - if (config["Core"]["Simulation-Mode"].as() == "emulation") { - mode = SimulationMode::Emulation; - } else if (config["Core"]["Simulation-Mode"].as() == - "outoforder") { - mode = SimulationMode::OutOfOrder; - } - - clockFreq_ = config["Core"]["Clock-Frequency"].as(); - timerFreq_ = config["Core"]["Timer-Frequency"].as(); - - if (argc > 2) { - executablePath = std::string(argv[2]); - } - - // Create the process image - std::unique_ptr process; - - if (executablePath.length() > 0) { - // Attempt to create the process image from the specified command-line - std::vector commandLine(argv + 2, argv + argc); - process = - std::make_unique(commandLine, config); - if (!process->isValid()) { - std::cerr << "Could not read/parse " << argv[2] << std::endl; - exit(1); + configFilePath = std::string(argv[1]); + // Determine if an executable has been supplied + if (argc > 2) { + executablePath = std::string(argv[2]); + // Create a vector of any potential executable arguments from their + // relative position within the argv variable + char** startOfArgs = argv + 3; + int numberofArgs = argc - 3; + executableArgs = + std::vector(startOfArgs, startOfArgs + numberofArgs); } + coreInstance = std::make_unique( + configFilePath, executablePath, executableArgs); } else { - // Create the process image directly - - // char* memory = new char[1024](); - - // Simple program demonstrating various instructions - // uint32_t hex[] = { - // 0x320003E0, // orr w0, wzr, #1 - // 0x321F0001, // orr w1, w0, #2 - // 0xB90003E1, // str w1, [sp] - // 0xB94003E0, // ldr w0, [sp] - // 0xF94003E0, // ldr x0, [sp] - // 0x14000002, // b #8 - // 0x320003E0, // orr w0, wzr, #1 - // 0x32000002, // orr w2, w0, #1 - // 0x71000420, // subs w0, w1, #1 - // }; - - // Simple loop; counts down from 1024*1024 - // uint32_t hex[] = { - // // 0x321E03E0, // orr w0, wzr, #4 - // 0x320C03E0, // orr w0, wzr, #1048576 - // // 0x321603E0, // orr w0, wzr, #1024 - // 0x71000400, // subs w0, w0, #1 - // // 0x320003E0, // orr w0, wzr, #1 - // // 0x71000400, // subs w0, w0, #1 - // 0x54FFFFE1, // b.ne -4 - // }; - - // Out-of-order test; counts down from 1024*1024, with an independent `orr` - // at the start of each branch. With an instruction latency of 2 or greater, - // the `orr` at the start of the next loop should issue/execute while the - // preceding branch is waiting on the result from the `subs`. - uint32_t hex[] = { - // 0x321E03E0, // orr w0, wzr, #4 - // 0x321603E0, // orr w0, wzr, #1024 - 0x320C03E0, // orr w0, wzr, #1048576 - 0x320003E1, // orr w0, wzr, #1 - 0x71000400, // subs w0, w0, #1 - // 0x00000000, // invalid - 0x54FFFFC1, // b.ne -8 - // .exit: - 0xD2800000, // mov x0, #0 - 0xD2800BC8, // mov x8, #94 - 0xD4000001, // svc #0 - }; - - // Load/store consistency test; a simple bubble sort algorithm - // uint32_t hex[] = { - // 0x320003E0, // orr w0, wzr, #1 - // 0x51000400, // sub w0, w0, #1 - - // 0x11013001, // add w1, w0, #76 - // // .start: - // 0x11000002, // add w2, w0, #0 - // // .compare: - // 0xB9400044, // ldr w4, [x2, 0] - // 0xB9400445, // ldr w5, [x2, 4] - // 0x4B0400A6, // sub w6, w5, w4 - // 0x37F80046, // tbnz w6, #31, #8 (.swap) - // 0x14000003, // b #12 (.next) - // // .swap: - // 0xB9000444, // str w4, [x2, 4] - // 0xB9000045, // str w5, [x2, 0] - // // .next: - // 0x11001042, // add w2, w2, #4 - // 0x4B010046, // sub w6, w2, w1 - // 0x37FFFEE6, // tbnz w6, #31, #-36 (.compare) - // 0x51001021, // sub w1, w1, #4 - // 0x4B010006, // sub w6, w0, w1 - // 0x37FFFE66, // tbnz w6, #31, #-52 (.start) - // }; - - // Force a load/store ordering violation - // uint32_t hex[] = { - // 0x320003E0, // orr w0, wzr, #1 - // 0x51000400, // sub w0, w0, #1 - - // 0x11000002, // add w2, w0, #0 - // 0x11013001, // add w1, w0, #76 - - // 0xB9000041, // str w1, [x2] - // 0xB9400043, // ldr w3, [x2] - // 0xB9000443, // str w3, [x2, 4] - // }; - - // Some arbitrary values to sort - // std::vector memoryValues = {9, 6, 7, 20, 5, 0, 80, 2, 1, 6, - // 17, 4, 3, 22, 117, 11, 4, 12, 10, 18}; - // memcpy(memory, memoryValues.data(), memoryValues.size() * sizeof(int)); - - process = std::make_unique( - simeng::span(reinterpret_cast(hex), sizeof(hex)), config); + // Without a config file, no executable can be supplied so pass default + // (empty) values for executable information + coreInstance = + std::make_unique(executablePath, executableArgs); + configFilePath = "Default"; } - // Read the process image and copy to memory - auto processImage = process->getProcessImage(); - size_t processMemorySize = processImage.size(); - char* processMemory = new char[processMemorySize](); - std::copy(processImage.begin(), processImage.end(), processMemory); - - uint64_t entryPoint = process->getEntryPoint(); - - // Create the OS kernel with the process - simeng::kernel::Linux kernel; - kernel.createProcess(*process.get()); - - simeng::FlatMemoryInterface instructionMemory(processMemory, - processMemorySize); - - // Create the architecture, with knowledge of the kernel - std::unique_ptr arch = - std::make_unique(kernel, config); - - auto predictor = simeng::BTBPredictor( - config["Branch-Predictor"]["BTB-bitlength"].as()); - auto config_ports = config["Ports"]; - std::vector> portArrangement(config_ports.size()); - // Extract number of ports - for (size_t i = 0; i < config_ports.size(); i++) { - auto config_groups = config_ports[i]["Instruction-Group-Support"]; - // Extract number of groups in port - for (size_t j = 0; j < config_groups.size(); j++) { - portArrangement[i].push_back(config_groups[j].as()); - } - } - auto portAllocator = simeng::pipeline::BalancedPortAllocator(portArrangement); - - // Configure reservation station arrangment - std::vector> rsArrangement; - for (size_t i = 0; i < config["Reservation-Stations"].size(); i++) { - auto reservation_station = config["Reservation-Stations"][i]; - for (size_t j = 0; j < reservation_station["Ports"].size(); j++) { - uint8_t port = reservation_station["Ports"][j].as(); - if (rsArrangement.size() < port + 1) { - rsArrangement.resize(port + 1); - } - rsArrangement[port] = {i, reservation_station["Size"].as()}; - } - } + // Replace empty executablePath string with more useful content for + // outputting + if (executablePath == "") executablePath = "Default"; + + // Get simulation objects needed to forward simulation + std::shared_ptr core = coreInstance->getCore(); + std::shared_ptr dataMemory = + coreInstance->getDataMemory(); + std::shared_ptr instructionMemory = + coreInstance->getInstructionMemory(); + + // Output general simumlation details + std::cout << "[SimEng] Running in " << coreInstance->getSimulationModeString() + << " mode" << std::endl; + std::cout << "[SimEng] Workload: " << executablePath; + for (const auto& arg : executableArgs) std::cout << " " << arg; + std::cout << std::endl; + std::cout << "[SimEng] Config file: " << configFilePath << std::endl; + // Run simulation + std::cout << "[SimEng] Starting...\n" << std::endl; int iterations = 0; - - std::string modeString; - std::unique_ptr core; - std::unique_ptr dataMemory; - switch (mode) { - case SimulationMode::OutOfOrder: { - modeString = "Out-of-Order"; - dataMemory = std::make_unique( - processMemory, processMemorySize, - config["L1-Cache"]["Access-Latency"].as()); - core = std::make_unique( - instructionMemory, *dataMemory, processMemorySize, entryPoint, *arch, - predictor, portAllocator, rsArrangement, config); - break; - } - case SimulationMode::InOrderPipelined: { - modeString = "In-Order Pipelined"; - std::unique_ptr flatDataMemory = - std::make_unique(processMemory, - processMemorySize); - core = std::make_unique( - instructionMemory, *flatDataMemory, processMemorySize, entryPoint, - *arch, predictor); - dataMemory = std::move(flatDataMemory); - break; - } - default: { - modeString = "Emulation"; - dataMemory = std::make_unique( - processMemory, processMemorySize); - core = std::make_unique( - instructionMemory, *dataMemory, entryPoint, processMemorySize, *arch); - break; - } - }; - - simeng::SpecialFileDirGen SFdir = simeng::SpecialFileDirGen(config); - // Create the Special Files directory if indicated to do so in Config - if (config["CPU-Info"]["Generate-Special-Dir"].as() == "T") { - // Remove any current special files dir - SFdir.RemoveExistingSFDir(); - // Create new special files dir - SFdir.GenerateSFDir(); - } - - std::cout << "Running in " << modeString << " mode\n"; - std::cout << "Starting..." << std::endl; auto startTime = std::chrono::high_resolution_clock::now(); + iterations = simulate(*core, *dataMemory, *instructionMemory); - iterations = simulate(*core, *dataMemory, instructionMemory); - + // Get timing information auto endTime = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(endTime - startTime) .count(); - auto hz = iterations / (static_cast(duration) / 1000.0); - auto khz = hz / 1000.0; - auto retired = core->getInstructionsRetiredCount(); - auto mips = retired / static_cast(duration) / 1000.0; + double khz = (iterations / (static_cast(duration) / 1000.0)) / 1000.0; + uint64_t retired = core->getInstructionsRetiredCount(); + double mips = (retired / (static_cast(duration))) / 1000.0; // Print stats - std::cout << "\n"; + std::cout << std::endl; auto stats = core->getStats(); for (const auto& [key, value] : stats) { - std::cout << key << ": " << value << "\n"; + std::cout << "[SimEng] " << key << ": " << value << std::endl; } - - std::cout << "\nFinished " << iterations << " ticks in " << duration << "ms (" - << std::round(khz) << " kHz, " << std::setprecision(2) << mips - << " MIPS)" << std::endl; - - // If Special Files directory was created, now remove it - // if (config["CPU-Info"]["Generate-Special-Dir"].as() == "T") { - // Remove special files dir - // SFdir.RemoveExistingSFDir(); - //} + std::cout << std::endl; + std::cout << "[SimEng] Finished " << iterations << " ticks in " << duration + << "ms (" << std::round(khz) << " kHz, " << std::setprecision(2) + << mips << " MIPS)" << std::endl; // Print build metadata and core statistics in YAML format // to facilitate parsing. Print "YAML-SEQ" to indicate beginning @@ -349,7 +146,5 @@ int main(int argc, char** argv) { #endif - delete[] processMemory; - return 0; } \ No newline at end of file diff --git a/test/regression/RegressionTest.cc b/test/regression/RegressionTest.cc index 798897ad9a..c04da38d44 100644 --- a/test/regression/RegressionTest.cc +++ b/test/regression/RegressionTest.cc @@ -18,19 +18,16 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -#include "simeng/BTBPredictor.hh" #include "simeng/FixedLatencyMemoryInterface.hh" #include "simeng/FlatMemoryInterface.hh" +#include "simeng/GenericPredictor.hh" #include "simeng/kernel/Linux.hh" #include "simeng/kernel/LinuxProcess.hh" #include "simeng/models/emulation/Core.hh" #include "simeng/models/inorder/Core.hh" #include "simeng/models/outoforder/Core.hh" -RegressionTest::~RegressionTest() { - delete[] code_; - delete[] processMemory_; -} +RegressionTest::~RegressionTest() { delete[] code_; } void RegressionTest::TearDown() { if (!programFinished_) { @@ -48,25 +45,35 @@ void RegressionTest::run(const char* source, const char* triple) { // Get pre-defined config file for OoO model YAML::Node config = generateConfig(); - // Create a linux process from the assembled code block + // Create a linux process from the assembled code block. + // Memory allocation for process images also takes place + // during linux process creation. The Elf binary is parsed + // and relevant sections are copied to the process image. + // The process image is finalised by the createStack method + // which creates and populates the initial process stack. + // The created process image can be accessed via a shared_ptr + // returned by the getProcessImage method. process_ = std::make_unique( simeng::span(reinterpret_cast(code_), codeSize_), config); ASSERT_TRUE(process_->isValid()); uint64_t entryPoint = process_->getEntryPoint(); - - // Allocate memory for the process and copy the full process image to it - simeng::span processImage = process_->getProcessImage(); - processMemorySize_ = processImage.size(); - if (processMemory_) delete[] processMemory_; - processMemory_ = new char[processMemorySize_]; - std::copy(processImage.begin(), processImage.end(), processMemory_); - - // Create memory interfaces for instruction and data access + processMemorySize_ = process_->getProcessImageSize(); + // This instance of procImgPtr pointer needs to be shared because + // getMemoryValue in RegressionTest.hh uses reference to the class + // member processMemory_. + std::shared_ptr procImgPtr = process_->getProcessImage(); + processMemory_ = procImgPtr.get(); + + // Create memory interfaces for instruction and data access. + // For each memory interface, a dereferenced shared_ptr to the + // processImage is passed as argument. simeng::FlatMemoryInterface instructionMemory(processMemory_, processMemorySize_); + std::unique_ptr flatDataMemory = std::make_unique(processMemory_, processMemorySize_); + std::unique_ptr fixedLatencyDataMemory = std::make_unique( processMemory_, processMemorySize_, 4); @@ -89,11 +96,8 @@ void RegressionTest::run(const char* source, const char* triple) { std::unique_ptr portAllocator = createPortAllocator(); - // Create the reservationStation-Port mapping relationship - const std::vector> rsArrangement = {{0, 60}}; - // Create a branch predictor for a pipelined core - simeng::BTBPredictor predictor(8); + simeng::GenericPredictor predictor(config); // Create the core model switch (std::get<0>(GetParam())) { case EMULATION: @@ -111,8 +115,7 @@ void RegressionTest::run(const char* source, const char* triple) { case OUTOFORDER: core_ = std::make_unique( instructionMemory, *fixedLatencyDataMemory, processMemorySize_, - entryPoint, *architecture_, predictor, *portAllocator, rsArrangement, - config); + entryPoint, *architecture_, predictor, *portAllocator, config); dataMemory = std::move(fixedLatencyDataMemory); break; } diff --git a/test/regression/aarch64/AArch64RegressionTest.hh b/test/regression/aarch64/AArch64RegressionTest.hh index 4984bd1f95..52601725c1 100644 --- a/test/regression/aarch64/AArch64RegressionTest.hh +++ b/test/regression/aarch64/AArch64RegressionTest.hh @@ -6,17 +6,21 @@ #define AARCH64_CONFIG \ ("{Core: {Simulation-Mode: emulation, Clock-Frequency: 2.5, " \ - "Fetch-Block-Size: 32, Micro-Operations: False}, Process-Image: " \ - "{Heap-Size: 100000, Stack-Size: 100000}, Register-Set: " \ - "{GeneralPurpose-Count: 154, FloatingPoint/SVE-Count: 90, " \ + "Timer-Frequency: 100, Micro-Operations: False}, Fetch: " \ + "{Fetch-Block-Size: 32, Loop-Buffer-Size: 64, Loop-Detection-Threshold: " \ + "4}, Process-Image: {Heap-Size: 100000, Stack-Size: 100000}, " \ + "Register-Set: {GeneralPurpose-Count: 154, FloatingPoint/SVE-Count: 90, " \ "Predicate-Count: 17, Conditional-Count: 128}, Pipeline-Widths: { Commit: " \ - "4, Dispatch-Rate: 4, FrontEnd: 4, LSQ-Completion: 2}, Queue-Sizes: {ROB: " \ - "180, Load: 64, Store: 36}, Branch-Predictor: {BTB-bitlength: 16}, " \ - "L1-Cache: {Access-Latency: 4, Exclusive: False, Load-Bandwidth: 32, " \ - "Store-Bandwidth: 16, Permitted-Requests-Per-Cycle: 2, " \ - "Permitted-Loads-Per-Cycle: 2, Permitted-Stores-Per-Cycle: 1}, Ports: " \ - "{'0': {Portname: Port 0, Instruction-Group-Support: [0, 14, 52, 66, 67, " \ - "70, 71]}}, Reservation-Stations: {'0': {Size: 60, Ports: [0]}}, " \ + "4, FrontEnd: 4, LSQ-Completion: 2}, Queue-Sizes: {ROB: 180, Load: 64, " \ + "Store: 36}, Branch-Predictor: {BTB-Tag-Bits: 11, Saturating-Count-Bits: " \ + "2, Global-History-Length: 10, RAS-entries: 5, Fallback-Static-Predictor: " \ + "2}, Data-Memory: {Interface-Type: Flat}, Instruction-Memory: " \ + "{Interface-Type: Flat}, LSQ-L1-Interface: {Access-Latency: 4, Exclusive: " \ + "False, Load-Bandwidth: 32, Store-Bandwidth: 16, " \ + "Permitted-Requests-Per-Cycle: 2, Permitted-Loads-Per-Cycle: 2, " \ + "Permitted-Stores-Per-Cycle: 1}, Ports: {'0': {Portname: Port 0, " \ + "Instruction-Group-Support: [0, 14, 52, 66, 67, 70, 71]}}, " \ + "Reservation-Stations: {'0': {Size: 60, Dispatch-Rate: 4, Ports: [0]}}, " \ "Execution-Units: {'0': {Pipelined: true}}}") /** A helper function to convert the supplied parameters of @@ -63,8 +67,8 @@ inline std::vector> genCoreTypeVLPairs( return coreVLPairs; } -/** A helper macro to run a snippet of Armv8 assembly code, returning from the - * calling function if a fatal error occurs. Four bytes containing zeros are +/** A helper macro to run a snippet of Armv9.2-a assembly code, returning from + * the calling function if a fatal error occurs. Four bytes containing zeros are * appended to the source to ensure that the program will terminate with an * illegal instruction exception instead of running into the heap. */ #define RUN_AARCH64(source) \ @@ -174,9 +178,9 @@ class AArch64RegressionTest : public RegressionTest { uint64_t getSystemRegister(uint16_t encoding) const { auto arch = reinterpret_cast( architecture_.get()); - uint16_t tag = arch->getSystemRegisterTag(encoding); return getRegister( - {simeng::arch::aarch64::RegisterType::SYSTEM, tag}); + {simeng::arch::aarch64::RegisterType::SYSTEM, + static_cast(arch->getSystemRegisterTag(encoding))}); } /** Get the value of a vector register element. */ diff --git a/test/regression/aarch64/Exception.cc b/test/regression/aarch64/Exception.cc index fd4b1d0d65..74e5f4390d 100644 --- a/test/regression/aarch64/Exception.cc +++ b/test/regression/aarch64/Exception.cc @@ -10,7 +10,9 @@ TEST_P(Exception, misaligned_pc) { mov x0, 5 br x0 )"); - const char err[] = "\nEncountered misaligned program counter exception"; + const char err[] = + "\n[SimEng:ExceptionHandler] Encountered misaligned program counter " + "exception"; EXPECT_EQ(stdout_.substr(0, sizeof(err) - 1), err); } diff --git a/test/regression/aarch64/Syscall.cc b/test/regression/aarch64/Syscall.cc index 5f180e8e3c..3826844602 100644 --- a/test/regression/aarch64/Syscall.cc +++ b/test/regression/aarch64/Syscall.cc @@ -14,6 +14,68 @@ using Syscall = AArch64RegressionTest; /** The maximum size of a filesystem path. */ static const size_t LINUX_PATH_MAX = 4096; +TEST_P(Syscall, getrandom) { + initialHeapData_.resize(24); + memset(initialHeapData_.data(), -1, 16); + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + # store inital heap address + mov x10, x0 + + # Save 8 random bytes to the heap + # getrandom(buf * = [a], buflen = 8, no flags) + mov x1, #8 + mov x8, #278 + svc #0 + + # Save another 8 random bytes to the heap + # getrandom(buf * = [a], buflen = 8, no flags) + add x0, x10, #8 + mov x1, #8 + mov x8, #278 + svc #0 + + )"); + + // Check getrandom returned 8 (8 bytes were requested) + EXPECT_EQ(getGeneralRegister(0), 8); + + int heapStart = getGeneralRegister(10); + for (size_t i = 0; i < 8; i++) { + printf("compare %x == %x\n", getMemoryValue(heapStart + i), + getMemoryValue(heapStart + 8 + i)); + } + + // check that the retuned bytes arent all equal to -1. + // heap was initialised to -1 so check bytes have changed + bool allUnchanged = true; + for (size_t i = 0; i < 16; i++) { + if (getMemoryValue(heapStart + i) != 0xFF) { + allUnchanged = false; + break; + } + } + EXPECT_EQ(allUnchanged, false); + + // Check that the returned bytes from the two syscalls dont all match. + // If they do then the returned bytes surely werent random + bool allMatch = true; + for (char i = 0; i < 8; i++) { + if (getMemoryValue(heapStart + i) != + getMemoryValue(heapStart + 8 + i)) { + allMatch = false; + break; + } + } + + EXPECT_EQ(allMatch, false); +} + TEST_P(Syscall, ioctl) { // TIOCGWINSZ: test it returns zero and sets the output to anything initialHeapData_.resize(8); diff --git a/test/regression/aarch64/SystemRegisters.cc b/test/regression/aarch64/SystemRegisters.cc index 98ded12ded..869526f600 100644 --- a/test/regression/aarch64/SystemRegisters.cc +++ b/test/regression/aarch64/SystemRegisters.cc @@ -71,6 +71,20 @@ TEST_P(SystemRegister, sysreg_access) { EXPECT_EQ(getSystemRegister(0xde82), 42); } +TEST_P(SystemRegister, counter_timers) { + // Ensure that the VCT is incremented at correct rate : once per ((2.5 * 1e9) + // / (100 * 1e6)) cycles (i.e. once per 25 cycles). + RUN_AARCH64(R"( + mov x2, xzr + mov x1, #16 + # Loop of 3 instructions * 16 iterations = 48, + 2 mov instructions = 50 total instructions & ~50 cycles + sub x1, x1, #1 + cmp x1, x2 + b.ne #-8 + )"); + EXPECT_EQ(getSystemRegister(0xdf02), 2); +} + INSTANTIATE_TEST_SUITE_P( AArch64, SystemRegister, ::testing::Values(std::make_tuple(EMULATION, YAML::Load("{}")), diff --git a/test/regression/aarch64/instructions/load.cc b/test/regression/aarch64/instructions/load.cc index a16e4c657e..387d0a058b 100644 --- a/test/regression/aarch64/instructions/load.cc +++ b/test/regression/aarch64/instructions/load.cc @@ -180,6 +180,60 @@ TEST_P(InstLoad, ld1_tworeg) { // 128-bit CHECK_NEON(3, uint64_t, {(0x98765432ull << 16), (0xABCDEF12ull << 32)}); } +TEST_P(InstLoad, ld1_multi_struct) { + // 16-bit, load into one register + // 16B = 16 elements of one byte + initialHeapData_.resize(16); + uint8_t* heapi8 = reinterpret_cast(initialHeapData_.data()); + heapi8[0] = 0xFF; + heapi8[1] = 0x00; + heapi8[2] = 0x11; + heapi8[3] = 0x22; + heapi8[4] = 0x33; + heapi8[5] = 0x44; + heapi8[6] = 0x55; + heapi8[7] = 0x66; + heapi8[8] = 0x77; + heapi8[9] = 0x88; + heapi8[10] = 0x99; + heapi8[11] = 0xAA; + heapi8[12] = 0xBB; + heapi8[13] = 0xCC; + heapi8[14] = 0xDD; + heapi8[15] = 0xEE; + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + # Load values from heap + ld1 {v0.16b}, [x0] + + # save heap address before post index + mov x10, x0 + + # Load values from heap with post-index + ld1 {v1.16b}, [x0], #16 + + # save heap address after post index + mov x11, x0 + + )"); + + CHECK_NEON(0, uint8_t, + {0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE}); + + CHECK_NEON(1, uint8_t, + {0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE}); + + EXPECT_EQ(getGeneralRegister(11), + getGeneralRegister(10) + 16); +} + TEST_P(InstLoad, ld2_multi_struct) { // 32-bit Post index initialHeapData_.resize(64); @@ -198,10 +252,13 @@ TEST_P(InstLoad, ld2_multi_struct) { mov x8, 214 svc #0 - # Save heap address before ld2 + # Simple version does not alter x0 + ld2 {v4.4s, v5.4s}, [x0] + + # Save heap address before ld2 post index mov x10, x0 - # Load values from heap + # Load values from heap, post index x0 ld2 {v0.4s, v1.4s}, [x0], #32 # Save heap address after ld2 @@ -211,6 +268,7 @@ TEST_P(InstLoad, ld2_multi_struct) { mov x1, #48 ld2 {v2.4s, v3.4s}, [x0], x1 mov x12, x0 + )"); EXPECT_EQ(getGeneralRegister(11), getGeneralRegister(10) + 32); @@ -220,6 +278,8 @@ TEST_P(InstLoad, ld2_multi_struct) { getGeneralRegister(10) + 48); CHECK_NEON(2, float, {0.25f, 1.25f, 0.125f, 5.0f}); CHECK_NEON(3, float, {2.0f, 7.5f, 0.75f, -0.5f}); + CHECK_NEON(4, float, {0.25f, 1.25f, 0.125f, 5.0f}); + CHECK_NEON(5, float, {2.0f, 7.5f, 0.75f, -0.5f}); } TEST_P(InstLoad, ldadd) { diff --git a/test/regression/aarch64/instructions/neon.cc b/test/regression/aarch64/instructions/neon.cc index 80a4e9e1a8..4131eb5c21 100644 --- a/test/regression/aarch64/instructions/neon.cc +++ b/test/regression/aarch64/instructions/neon.cc @@ -368,6 +368,50 @@ TEST_P(InstNeon, and) { } TEST_P(InstNeon, bic) { + // 16 bit + // Vector, immediate + initialHeapData_.resize(32); + uint16_t* heap16 = reinterpret_cast(initialHeapData_.data()); + + // v0 + heap16[0] = 0xDEAD; + heap16[1] = 0x1234; + heap16[2] = 0x89AB; + heap16[3] = 0xF0F0; + heap16[4] = 0xDEAD; + heap16[5] = 0x1234; + heap16[6] = 0x89AB; + heap16[7] = 0xF0F0; + + // v1 + heap16[8] = 0xDEAD; + heap16[9] = 0x1234; + heap16[10] = 0x89AB; + heap16[11] = 0xF0F0; + heap16[12] = 0xDEAD; + heap16[13] = 0x1234; + heap16[14] = 0x89AB; + heap16[15] = 0xF0F0; + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + bic v0.8h, #0x80, lsl #8 + bic v1.8h, #0xFF + )"); + + CHECK_NEON(0, uint16_t, + {0x5ead, 0x1234, 0x09ab, 0x70f0, 0x5EAD, 0x1234, 0x9AB, 0x70F0}); + + CHECK_NEON(1, uint16_t, + {0xde00, 0x1200, 0x8900, 0xf000, 0xde00, 0x1200, 0x8900, 0xf000}); + + // 32-bit // Vector, immediate initialHeapData_.resize(32); uint32_t* heap = reinterpret_cast(initialHeapData_.data()); @@ -550,7 +594,7 @@ TEST_P(InstNeon, bsl) { } TEST_P(InstNeon, cmeq) { - // 8-bit + // 8-bit, 16 lane initialHeapData_.resize(32); uint8_t* heap8 = reinterpret_cast(initialHeapData_.data()); for (int i = 0; i < 16; i++) { @@ -578,6 +622,39 @@ TEST_P(InstNeon, cmeq) { {0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}); + // 8-bit, 8 lane + initialHeapData_.resize(16); + uint8_t* heapv8i8 = reinterpret_cast(initialHeapData_.data()); + for (int i = 0; i < 8; i++) { + heapv8i8[i] = i; + heapv8i8[i + 8] = i; + } + + // v0 changes + heapv8i8[0] = -1; + heapv8i8[3] = 0; + heapv8i8[6] = 0; + + // v1 changes + heapv8i8[8] = -1; + heapv8i8[11] = -128; + heapv8i8[14] = 0; + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #8] + cmeq v2.8b, v0.8b, v1.8b + cmeq v3.8b, v0.8b, 0 + )"); + + CHECK_NEON(2, uint8_t, {0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}); + CHECK_NEON(3, uint8_t, {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00}); + // 32-bit initialHeapData_.resize(128); uint32_t* heap32 = reinterpret_cast(initialHeapData_.data()); @@ -590,6 +667,7 @@ TEST_P(InstNeon, cmeq) { heap32[5] = 11; heap32[6] = 12; heap32[7] = 10; + RUN_AARCH64(R"( # Get heap address mov x0, 0 @@ -603,6 +681,68 @@ TEST_P(InstNeon, cmeq) { CHECK_NEON(2, uint32_t, {0, 0xFFFFFFFFu, 0xFFFFFFFFu, 0}); } +TEST_P(InstNeon, cmhs) { + // cmhs vd.16b, vn.16b, vm.16b + initialHeapData_.resize(32); + int8_t* heap = reinterpret_cast(initialHeapData_.data()); + + // v0 + heap[0] = 0; + heap[1] = 0x7F; + heap[2] = INT8_MAX; + heap[3] = 1; + heap[4] = -128; + heap[5] = -1; + heap[6] = 0xAA; + heap[7] = 0xBB; + heap[8] = 0xCC; + heap[9] = INT8_MAX; + heap[10] = INT8_MAX - 1; + heap[11] = INT8_MAX - 2; + heap[12] = 0x7F; + heap[13] = 0x7F; + heap[14] = 0x7F; + heap[15] = 0x7F; + + // v1 + heap[16] = INT8_MAX; + heap[17] = 0x7F; + heap[18] = 0; + heap[19] = -128; + heap[20] = 1; + heap[21] = 0; + heap[22] = 0xAA; + heap[23] = 0xBB; + heap[24] = 0xCC; + heap[25] = 0; + heap[26] = 1; + heap[27] = 2; + heap[28] = 0x7F; + heap[29] = 0x7F; + heap[30] = 0x7F; + heap[31] = 0x7F; + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + + cmhs v2.16b, v0.16b, v1.16b + cmhs v3.16b, v1.16b, v0.16b + )"); + + CHECK_NEON(2, uint8_t, + {0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}); + CHECK_NEON(3, uint8_t, + {0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF}); +} + TEST_P(InstNeon, cmhi) { initialHeapData_.resize(32); uint32_t* heap = reinterpret_cast(initialHeapData_.data()); @@ -951,6 +1091,13 @@ TEST_P(InstNeon, faddp) { faddp v2.2d, v1.2d, v0.2d )"); CHECK_NEON(2, double, {7.5, 0.5}); + + // dd, V.2S + RUN_AARCH64(R"( + fmov v0.2s, #0.125 + faddp s1, v0.2s + )"); + CHECK_NEON(1, float, {0.25, 0}); } TEST_P(InstNeon, fadd) { initialHeapData_.resize(64); @@ -1000,8 +1147,10 @@ TEST_P(InstNeon, fadd) { ldr q0, [x0] ldr q1, [x0, #16] fadd v2.4s, v0.4s, v1.4s + fadd v3.2s, v0.2s, v1.2s )"); CHECK_NEON(2, float, {87.72f, -160.38, -0.927f, 701.90f}); + CHECK_NEON(3, float, {87.72f, -160.38, 0, 0}); } TEST_P(InstNeon, fcmeq) { @@ -1307,23 +1456,35 @@ TEST_P(InstNeon, fdiv) { TEST_P(InstNeon, fmla) { // 32-bit - initialHeapData_.resize(48); + initialHeapData_.resize(80); float* fheap = reinterpret_cast(initialHeapData_.data()); + + // v0 fheap[0] = 7.0; fheap[1] = -3.4; fheap[2] = -0.16; fheap[3] = 0.0; + // v1 fheap[4] = 8.72; fheap[5] = -1.67; fheap[6] = 7.90; fheap[7] = -0.01; + // v2 fheap[8] = 1.0; fheap[9] = -4.3; fheap[10] = -0.1; fheap[11] = 0.0; + // v4 + fheap[12] = 1.0; + fheap[13] = -4.3; + + // v5 + fheap[14] = 1.0; + fheap[15] = 1.0; + RUN_AARCH64(R"( # Get heap address mov x0, 0 @@ -1335,9 +1496,20 @@ TEST_P(InstNeon, fmla) { ldr q2, [x0, #32] fmla v2.4s, v0.4s, v1.4s fmla v3.4s, v0.4s, v2.s[0] + + ldr q4, [x0, #48] + ldr q5, [x0, #56] + fmla v4.2s, v0.2s, v1.2s + fmla v5.2s, v0.2s, v2.s[0] + )"); + + CHECK_NEON(0, float, {7.0, -3.4, -0.16, -0.0}); + CHECK_NEON(1, float, {8.72, -1.67, 7.90, -0.01}); CHECK_NEON(2, float, {62.04, 1.378, -1.364, 0.0}); CHECK_NEON(3, float, {434.28, -210.936, -9.9264, 0.0}); + CHECK_NEON(4, float, {62.04, 1.3779}); + CHECK_NEON(5, float, {435.28, -209.936}); // 64-bit initialHeapData_.resize(48); @@ -2054,8 +2226,10 @@ TEST_P(InstNeon, fsub) { ldr q0, [x0] ldr q1, [x0, #16] fsub v2.4s, v0.4s, v1.4s + fsub v3.2s, v0.2s, v1.2s )"); CHECK_NEON(2, float, {-1.0, -41.76, 320.875, 198.0}); + CHECK_NEON(3, float, {-1.0, -41.76, 0, 0}); } TEST_P(InstNeon, ins) { @@ -2260,6 +2434,9 @@ TEST_P(InstNeon, mvni) { mvni v3.2s, 42 mvni v4.2s, 42, lsl #8 mvni v5.2s, 3, lsl #24 + + mvni v6.2s, 32, msl #8 + mvni v7.4s, 32, msl #8 )"); CHECK_NEON(0, uint32_t, {~42u, ~42u, ~42u, ~42u}); CHECK_NEON(1, uint32_t, {~(42u << 8), ~(42u << 8), ~(42u << 8), ~(42u << 8)}); @@ -2267,6 +2444,10 @@ TEST_P(InstNeon, mvni) { CHECK_NEON(3, uint32_t, {~42u, ~42u, 0, 0}); CHECK_NEON(4, uint32_t, {~(42u << 8), ~(42u << 8), 0, 0}); CHECK_NEON(5, uint32_t, {~(3u << 24), ~(3u << 24), 0, 0}); + CHECK_NEON(6, uint32_t, {~((32u << 8) | 255), ~((32u << 8) | 255), 0, 0}); + CHECK_NEON(7, uint32_t, + {~((32u << 8) | 255), ~((32u << 8) | 255), ~((32u << 8) | 255), + ~((32u << 8) | 255)}); } TEST_P(InstNeon, not ) { @@ -2329,6 +2510,7 @@ TEST_P(InstNeon, orr) { heap[5] = 0x77777777; heap[6] = 0xEEEEEEEE; heap[7] = 0x0F0F0F0F; + RUN_AARCH64(R"( # Get heap address mov x0, 0 @@ -2338,12 +2520,134 @@ TEST_P(InstNeon, orr) { ldr q0, [x0] ldr q1, [x0, #16] orr v2.16b, v0.16b, v1.16b + orr v4.8b, v0.8b, v1.8b # Test mov alias as well mov v3.16b, v0.16b + mov v5.8b, v0.8b )"); CHECK_NEON(2, uint32_t, {0xFEFDFEFF, 0x7777777F, 0xFEFEFEFE, 0xAFCFEF0F}); + CHECK_NEON(4, uint32_t, {0xFEFDFEFF, 0x7777777F, 0x00000000, 0x00000000}); + CHECK_NEON(3, uint32_t, {0xDEADBEEF, 0x12345678, 0x98765432, 0xABCDEF01}); + CHECK_NEON(5, uint32_t, {0xDEADBEEF, 0x12345678, 0x00000000, 0x00000000}); +} + +TEST_P(InstNeon, uminp) { + // uminp vd.16b vn.16b vm.16b + initialHeapData_.resize(32); + uint8_t* heap = reinterpret_cast(initialHeapData_.data()); + + // v0 + heap[0] = 0x01; + heap[1] = 0x00; + heap[2] = 0xFF; + heap[3] = 0xAA; + heap[4] = 0xBB; + heap[5] = 0xCC; + heap[6] = 0xDD; + heap[7] = 0xEE; + + heap[8] = 0x01; + heap[9] = 0x02; + heap[10] = 0x03; + heap[11] = 0x04; + heap[12] = 0x05; + heap[13] = 0x06; + heap[14] = 0x07; + heap[15] = 0x08; + + // v1 + heap[16] = 0x00; + heap[17] = 0x00; + heap[18] = 0xEE; + heap[19] = 0x11; + heap[20] = 0x22; + heap[21] = 0x33; + heap[22] = 0x44; + heap[23] = 0x55; + + heap[24] = 0xFF; + heap[25] = 0xEE; + heap[26] = 0xDD; + heap[27] = 0xCC; + heap[28] = 0xBB; + heap[29] = 0xAA; + heap[30] = 0x99; + heap[31] = 0x88; + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + uminp v2.16b, v0.16b, v1.16b + + )"); + CHECK_NEON(2, uint8_t, + {0x00, 0x00, 0xEE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08}); +} +TEST_P(InstNeon, umaxp) { + // umaxp vd.16b vn.16b vm.16b + initialHeapData_.resize(32); + uint8_t* heap = reinterpret_cast(initialHeapData_.data()); + + // v0 + heap[0] = 0x01; + heap[1] = 0x00; + heap[2] = 0xFF; + heap[3] = 0xAA; + heap[4] = 0xBB; + heap[5] = 0xCC; + heap[6] = 0xDD; + heap[7] = 0xEE; + + heap[8] = 0x01; + heap[9] = 0x02; + heap[10] = 0x03; + heap[11] = 0x04; + heap[12] = 0x05; + heap[13] = 0x06; + heap[14] = 0x07; + heap[15] = 0x08; + + // v1 + heap[16] = 0x00; + heap[17] = 0x00; + heap[18] = 0xEE; + heap[19] = 0x11; + heap[20] = 0x22; + heap[21] = 0x33; + heap[22] = 0x44; + heap[23] = 0x55; + + heap[24] = 0xFF; + heap[25] = 0xEE; + heap[26] = 0xDD; + heap[27] = 0xCC; + heap[28] = 0xBB; + heap[29] = 0xAA; + heap[30] = 0x99; + heap[31] = 0x88; + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + umaxp v2.16b, v0.16b, v1.16b + + )"); + CHECK_NEON(2, uint8_t, + {0x01, 0x00, 0xFF, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xEE, 0xDD, + 0xCC, 0xBB, 0xAA, 0x99, 0x88}); } TEST_P(InstNeon, smax) { @@ -2935,6 +3239,367 @@ TEST_P(InstNeon, xtn) { CHECK_NEON(2, uint16_t, {42, (1u << 15), UINT16_MAX, 7, 0, 0, 0, 0}); } +TEST_P(InstNeon, tbl) { + initialHeapData_.resize(512); + uint64_t* heap = reinterpret_cast(initialHeapData_.data()); + + // table for all tests + heap[0] = 0x7766554433221100; // v0 bytes 0-7 + heap[1] = 0xFFEEDDCCBBAA9988; // v0 bytes 8-15 + heap[2] = 0x7766554433221100; // v1 bytes 0-7 + heap[3] = 0xFFEEDDCCBBAA9988; // v1 bytes 8-15 + heap[4] = 0xDEADBEEFDEADBEEF; // v2 bytes 0-7 + heap[5] = 0xBA5EBA11BA5EBA11; // v2 bytes 8-15 + heap[6] = 0x50FAFACE50FAFACE; // v3 bytes 0-7 + heap[7] = 0xF007BA11F007BA11; // v3 bytes 8-15 + + // Size 1 table: + // Indices + heap[8] = 0xFF0004000200FF00; // v4 bytes 0-7 + heap[9] = 0x0D000C000B000A00; // v4 bytes 8-15 + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + # table + ldr q0, [x0] + + # indicies + ldr q4, [x0, #64] + ldr q5, [x0, #96] + + # size 1 table + tbl v6.8b, {v0.16b}, v4.8b + tbl v7.16b, {v0.16b}, v4.16b + )"); + + CHECK_NEON(6, uint8_t, {0x00, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00}); + CHECK_NEON(7, uint8_t, + {0x00, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00, 0x00, 0xAA, 0x00, + 0xBB, 0x00, 0xCC, 0x00, 0xDD}); + + // Size 2 table: + // Indices + heap[8] = 0xFF001E000200FF00; // v4 bytes 0-7 + heap[9] = 0x1F00FF0012001100; // v4 bytes 8-15 + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + # table + ldr q0, [x0] + ldr q1, [x0, #16] + + # indicies + ldr q4, [x0, #64] + + # size 2 table + tbl v6.8b, {v0.16b, v1.16b}, v4.8b + tbl v7.16b, {v0.16b, v1.16b}, v4.16b + + )"); + + CHECK_NEON(6, uint8_t, {0x00, 0x00, 0x00, 0x22, 0x00, 0xEE, 0x00, 0x00}); + CHECK_NEON(7, uint8_t, + {0x00, 0x00, 0x00, 0x22, 0x00, 0xEE, 0x00, 0x00, 0x00, 0x11, 0x00, + 0x22, 0x00, 0x00, 0x00, 0xFF}); + + // Size 3 table: + // Indices + heap[8] = 0xFF002F0002002400; // v4 bytes 0-7 + heap[9] = 0x1F00FF002F001100; // v4 bytes 8-15 + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + # table + ldr q0, [x0] + ldr q1, [x0, #16] + ldr q2, [x0, #32] + + # indicies + ldr q4, [x0, #64] + + # size 2 table + tbl v6.8b, {v0.16b, v1.16b, v2.16b}, v4.8b + tbl v7.16b, {v0.16b, v1.16b, v2.16b}, v4.16b + + )"); + + CHECK_NEON(6, uint8_t, {0x00, 0xEF, 0x00, 0x22, 0x00, 0xBA, 0x00, 0x00}); + CHECK_NEON(7, uint8_t, + {0x00, 0xEF, 0x00, 0x22, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x11, 0x00, + 0xBA, 0x00, 0x00, 0x00, 0xFF}); + + // Size 4 table: + // Indices + heap[8] = 0xFF002F000200243F; // v4 bytes 0-7 + heap[9] = 0x1F30FF002F001100; // v4 bytes 8-15 + + RUN_AARCH64(R"( + # Get heap address + mov x0, 0 + mov x8, 214 + svc #0 + + # table + ldr q0, [x0] + ldr q1, [x0, #16] + ldr q2, [x0, #32] + ldr q3, [x0, #48] + + # indicies + ldr q4, [x0, #64] + + # size 2 table + tbl v6.8b, {v0.16b, v1.16b, v2.16b, v3.16b}, v4.8b + tbl v7.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v4.16b + + )"); + + CHECK_NEON(6, uint8_t, {0xF0, 0xEF, 0x00, 0x22, 0x00, 0xBA, 0x00, 0x00}); + CHECK_NEON(7, uint8_t, + {0xF0, 0xEF, 0x00, 0x22, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x11, 0x00, + 0xBA, 0x00, 0x00, 0xCE, 0xFF}); +} + +TEST_P(InstNeon, rev) { + // REV64 + RUN_AARCH64(R"( + index z0.b, #0, #1 + + rev64 v1.16b, v0.16b + rev64 v2.4h, v0.4h + rev64 v3.8h, v0.8h + rev64 v4.2s, v0.2s + rev64 v5.4s, v0.4s + rev64 v6.8b, v0.8b + )"); + + CHECK_NEON(1, uint8_t, + { + 0x07, + 0x06, + 0x05, + 0x04, + 0x03, + 0x02, + 0x01, + 0x00, + 0x0f, + 0x0e, + 0x0d, + 0x0c, + 0x0b, + 0x0a, + 0x09, + 0x08, + }); + CHECK_NEON(2, uint16_t, + {0x0706, 0x0504, 0x0302, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000}); + CHECK_NEON(3, uint16_t, + {0x0706, 0x0504, 0x0302, 0x0100, 0x0f0e, 0x0d0c, 0x0b0a, 0x0908}); + CHECK_NEON(4, uint32_t, {0x7060504, 0x3020100, 0x0, 0x0}); + CHECK_NEON(5, uint32_t, {0x7060504, 0x3020100, 0xf0e0d0c, 0xb0a0908}); + CHECK_NEON( + 6, uint8_t, + {0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00}); + + // REV32 + RUN_AARCH64(R"( + index z0.b, #0, #1 + + rev32 v1.8b, v0.8b + rev32 v2.16b, v0.16b + rev32 v3.4h, v0.4h + rev32 v4.8h, v0.8h + )"); + + CHECK_NEON(1, uint8_t, + {0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}); + CHECK_NEON(2, uint8_t, + {0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, + 0x08, 0x0f, 0x0e, 0x0d, 0x0c}); + CHECK_NEON(3, uint16_t, + {0x0302, 0x0100, 0x0706, 0x0504, 0x0000, 0x0000, 0x0000, 0x0000}); + CHECK_NEON(4, uint16_t, + {0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c}); + + // REV16 + RUN_AARCH64(R"( + index z0.b, #0, #1 + + rev16 v1.8b, v0.8b + rev16 v2.16b, v0.16b + )"); + + CHECK_NEON(1, uint8_t, + {0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}); + CHECK_NEON(2, uint8_t, + {0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, + 0x0a, 0x0d, 0x0c, 0x0f, 0xe}); +} + +TEST_P(InstNeon, trn) { + initialHeapData_.resize(128); + uint64_t* heap64 = reinterpret_cast(initialHeapData_.data()); + heap64[0] = 0x0F0D0B0907050301; + heap64[1] = 0x1F1D1B1917151311; + heap64[2] = 0x0E0C0A0806040200; + heap64[3] = 0x1E1C1A1816141210; + + // trn1 + RUN_AARCH64(R"( + # Get heap address + mov x0, #0 + mov x8, #214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + + trn1 v2.16b, v1.16b, v0.16b + trn1 v3.8b, v1.8b, v0.8b + trn1 v4.4h, v1.4h, v0.4h + trn1 v5.8h, v1.8h, v0.8h + trn1 v6.2s, v1.2s, v0.2s + trn1 v7.4s, v1.4s, v0.4s + trn1 v8.2d, v1.2d, v0.2d + + )"); + + CHECK_NEON(2, uint8_t, + {0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xc, 0xd, 0x10, 0x11, 0x14, 0x15, + 0x18, 0x19, 0x1c, 0x1d}); + CHECK_NEON(3, uint8_t, + {0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xc, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0}); + CHECK_NEON(4, uint16_t, {0x200, 0x301, 0xa08, 0xb09, 0x0, 0x0, 0x0, 0x0}); + CHECK_NEON(5, uint16_t, + {0x200, 0x301, 0xa08, 0xb09, 0x1210, 0x1311, 0x1a18, 0x1b19}); + CHECK_NEON(6, uint32_t, {0x6040200, 0x7050301, 0x0, 0x0}); + CHECK_NEON(7, uint32_t, {0x6040200, 0x7050301, 0x16141210, 0x17151311}); + CHECK_NEON(8, uint64_t, {0xe0c0a0806040200, 0xf0d0b0907050301}); + + // trn2 + RUN_AARCH64(R"( + # Get heap address + mov x0, #0 + mov x8, #214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + + trn2 v2.16b, v1.16b, v0.16b + trn2 v3.8b, v1.8b, v0.8b + trn2 v4.4h, v1.4h, v0.4h + trn2 v5.8h, v1.8h, v0.8h + trn2 v6.2s, v1.2s, v0.2s + trn2 v7.4s, v1.4s, v0.4s + trn2 v8.2d, v1.2d, v0.2d + + )"); + + CHECK_NEON(2, uint8_t, + {0x2, 0x3, 0x6, 0x7, 0xa, 0xb, 0xe, 0xf, 0x12, 0x13, 0x16, 0x17, + 0x1a, 0x1b, 0x1e, 0x1f}); + CHECK_NEON(3, uint8_t, + {0x2, 0x3, 0x6, 0x7, 0xa, 0xb, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0}); + CHECK_NEON(4, uint16_t, {0x604, 0x705, 0xe0c, 0xf0d, 0x0, 0x0, 0x0, 0x0}); + CHECK_NEON(5, uint16_t, + {0x604, 0x705, 0xe0c, 0xf0d, 0x1614, 0x1715, 0x1e1c, 0x1f1d}); + CHECK_NEON(6, uint32_t, {0xe0c0a08, 0xf0d0b09, 0x0, 0x0}); + CHECK_NEON(7, uint32_t, {0xe0c0a08, 0xf0d0b09, 0x1e1c1a18, 0x1f1d1b19}); + CHECK_NEON(8, uint64_t, {0x1e1c1a1816141210, 0x1f1d1b1917151311}); +} + +TEST_P(InstNeon, uzp) { + initialHeapData_.resize(128); + uint64_t* heap64 = reinterpret_cast(initialHeapData_.data()); + heap64[0] = 0x0F0D0B0907050301; + heap64[1] = 0x1F1D1B1917151311; + heap64[2] = 0x0E0C0A0806040200; + heap64[3] = 0x1E1C1A1816141210; + + // uzp1 + RUN_AARCH64(R"( + # Get heap address + mov x0, #0 + mov x8, #214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + + uzp1 v2.16b, v1.16b, v0.16b + uzp1 v3.8b, v1.8b, v0.8b + uzp1 v4.4h, v1.4h, v0.4h + uzp1 v5.8h, v1.8h, v0.8h + uzp1 v6.2s, v1.2s, v0.2s + uzp1 v7.4s, v1.4s, v0.4s + uzp1 v8.2d, v1.2d, v0.2d + + )"); + + CHECK_NEON(2, uint8_t, + {0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x1, 0x5, 0x9, 0xd, + 0x11, 0x15, 0x19, 0x1d}); + CHECK_NEON(3, uint8_t, + {0x0, 0x4, 0x8, 0xc, 0x1, 0x5, 0x9, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0}); + CHECK_NEON(4, uint16_t, {0x200, 0xa08, 0x301, 0xb09, 0x0, 0x0, 0x0, 0x0}); + CHECK_NEON(5, uint16_t, + {0x200, 0xa08, 0x1210, 0x1a18, 0x301, 0xb09, 0x1311, 0x1b19}); + CHECK_NEON(6, uint32_t, {0x6040200, 0x7050301, 0x0, 0x0}); + CHECK_NEON(7, uint32_t, {0x6040200, 0x16141210, 0x7050301, 0x17151311}); + CHECK_NEON(8, uint64_t, {0xe0c0a0806040200, 0xf0d0b0907050301}); + + // uzp2 + RUN_AARCH64(R"( + # Get heap address + mov x0, #0 + mov x8, #214 + svc #0 + + ldr q0, [x0] + ldr q1, [x0, #16] + + uzp2 v2.16b, v1.16b, v0.16b + uzp2 v3.8b, v1.8b, v0.8b + uzp2 v4.4h, v1.4h, v0.4h + uzp2 v5.8h, v1.8h, v0.8h + uzp2 v6.2s, v1.2s, v0.2s + uzp2 v7.4s, v1.4s, v0.4s + uzp2 v8.2d, v1.2d, v0.2d + + )"); + + CHECK_NEON(2, uint8_t, + {0x2, 0x6, 0xa, 0xe, 0x12, 0x16, 0x1a, 0x1e, 0x3, 0x7, 0xb, 0xf, + 0x13, 0x17, 0x1b, 0x1f}); + CHECK_NEON(3, uint8_t, + {0x2, 0x6, 0xa, 0xe, 0x3, 0x7, 0xb, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0}); + CHECK_NEON(4, uint16_t, {0x604, 0xe0c, 0x705, 0xf0d, 0x0, 0x0, 0x0, 0x0}); + CHECK_NEON(5, uint16_t, + {0x604, 0xe0c, 0x1614, 0x1e1c, 0x705, 0xf0d, 0x1715, 0x1f1d}); + CHECK_NEON(6, uint32_t, {0xe0c0a08, 0xf0d0b09, 0x0, 0x0}); + CHECK_NEON(7, uint32_t, {0xe0c0a08, 0x1e1c1a18, 0xf0d0b09, 0x1f1d1b19}); + CHECK_NEON(8, uint64_t, {0x1e1c1a1816141210, 0x1f1d1b1917151311}); +} INSTANTIATE_TEST_SUITE_P(AArch64, InstNeon, ::testing::Values(std::make_tuple(EMULATION, YAML::Load("{}"))), diff --git a/test/regression/aarch64/instructions/sve.cc b/test/regression/aarch64/instructions/sve.cc index b2043e7cf6..b0618e66dc 100644 --- a/test/regression/aarch64/instructions/sve.cc +++ b/test/regression/aarch64/instructions/sve.cc @@ -1341,6 +1341,36 @@ TEST_P(InstSve, cnt) { EXPECT_EQ(getGeneralRegister(5), (VL / 16) * 3); EXPECT_EQ(getGeneralRegister(6), (VL / 32) * 3); EXPECT_EQ(getGeneralRegister(7), (VL / 64) * 3); + + // pattern != all + RUN_AARCH64(R"( + cntb x0, pow2, mul #2 + cnth x1, vl1, mul #2 + cntw x2, vl2, mul #2 + cntd x3, vl5, mul #2 + cntb x4, vl7, mul #2 + cnth x5, vl32, mul #2 + cntw x6, vl128, mul #2 + cntd x7, mul4, mul #2 + )"); + uint16_t maxElemsB = VL / 8; + uint16_t maxElemsH = VL / 16; + uint16_t maxElemsS = VL / 32; + uint16_t maxElemsD = VL / 64; + uint16_t n = 1; + while (maxElemsB >= std::pow(2, n)) { + n = n + 1; + } + uint16_t pow2B = std::pow(2, n - 1); + + EXPECT_EQ(getGeneralRegister(0), pow2B * 2); + EXPECT_EQ(getGeneralRegister(1), maxElemsH >= 1 ? (1 * 2) : 0); + EXPECT_EQ(getGeneralRegister(2), maxElemsS >= 2 ? (2 * 2) : 0); + EXPECT_EQ(getGeneralRegister(3), maxElemsD >= 5 ? (5 * 2) : 0); + EXPECT_EQ(getGeneralRegister(4), maxElemsB >= 7 ? (7 * 2) : 0); + EXPECT_EQ(getGeneralRegister(5), maxElemsH >= 32 ? (32 * 2) : 0); + EXPECT_EQ(getGeneralRegister(6), maxElemsS >= 128 ? (128 * 2) : 0); + EXPECT_EQ(getGeneralRegister(7), (maxElemsD - (maxElemsD % 4)) * 2); } TEST_P(InstSve, cntp) { @@ -1605,6 +1635,34 @@ TEST_P(InstSve, dec) { EXPECT_EQ(getGeneralRegister(2), 512 - (VL / 64)); EXPECT_EQ(getGeneralRegister(3), 512 - (VL / 64) * 3); + + // pattern != all + RUN_AARCH64(R"( + mov x0, #44 + mov x1, #20 + mov x2, #71 + mov x3, #56 + + decb x0, pow2, mul #2 + decd x1, vl5, mul #2 + decb x2, vl128, mul #2 + decd x3, mul4, mul #2 + )"); + uint16_t maxElemsB = VL / 8; + uint16_t maxElemsD = VL / 64; + uint16_t n = 1; + while (maxElemsB >= std::pow(2, n)) { + n = n + 1; + } + uint16_t pow2B = std::pow(2, n - 1); + + EXPECT_EQ(getGeneralRegister(0), 44 - (pow2B * 2)); + EXPECT_EQ(getGeneralRegister(1), + (maxElemsD >= 5) ? (20 - (5 * 2)) : 20); + EXPECT_EQ(getGeneralRegister(2), + (maxElemsB >= 128) ? 71 - (128 * 2) : 71); + EXPECT_EQ(getGeneralRegister(3), + 56 - ((maxElemsD - (maxElemsD % 4)) * 2)); } TEST_P(InstSve, dupm) { @@ -1960,6 +2018,51 @@ TEST_P(InstSve, inc) { EXPECT_EQ(getGeneralRegister(6), 128 + (VL / 16) * 3); EXPECT_EQ(getGeneralRegister(7), 160 + (VL / 32) * 3); + // pattern != all + RUN_AARCH64(R"( + mov x0, #64 + mov x1, #96 + mov x2, #128 + mov x3, #160 + mov x4, #64 + mov x5, #96 + mov x6, #128 + mov x7, #160 + incb x0, pow2, mul #2 + incd x1, vl16, mul #2 + inch x2, vl6, mul #2 + incw x3, vl7, mul #2 + incb x4, vl256, mul #2 + incd x5, vl64, mul #2 + inch x6, vl2, mul #2 + incw x7, mul3, mul #2 + )"); + uint16_t maxElemsB = VL / 8; + uint16_t maxElemsH = VL / 16; + uint16_t maxElemsS = VL / 32; + uint16_t maxElemsD = VL / 64; + uint16_t n = 1; + while (maxElemsB >= std::pow(2, n)) { + n = n + 1; + } + uint16_t pow2B = std::pow(2, n - 1); + + EXPECT_EQ(getGeneralRegister(0), 64 + (pow2B * 2)); + EXPECT_EQ(getGeneralRegister(1), + (maxElemsD >= 16) ? (96 + (16 * 2)) : 96); + EXPECT_EQ(getGeneralRegister(2), + (maxElemsH >= 6) ? (128 + (6 * 2)) : 128); + EXPECT_EQ(getGeneralRegister(3), + (maxElemsS >= 7) ? (160 + (7 * 2)) : 160); + EXPECT_EQ(getGeneralRegister(4), + (maxElemsB >= 256) ? (64 + (256 * 2)) : 64); + EXPECT_EQ(getGeneralRegister(5), + (maxElemsD >= 64) ? (96 + (64 * 2)) : 96); + EXPECT_EQ(getGeneralRegister(6), + (maxElemsH >= 2) ? (128 + (2 * 2)) : 128); + EXPECT_EQ(getGeneralRegister(7), + 160 + ((maxElemsS - (maxElemsS % 3)) * 2)); + // pattern = all // Vector Variants RUN_AARCH64(R"( @@ -1989,6 +2092,51 @@ TEST_P(InstSve, inc) { fillNeon({(int64_t)(3 + ((VL / 64)))}, (VL / 8))); CHECK_NEON(5, int64_t, fillNeon({(int64_t)(84 + ((VL / 64) * 5))}, (VL / 8))); + + // pattern != all + // Vector Variants + RUN_AARCH64(R"( + dup z0.s, #15 + dup z1.s, #37 + dup z2.h, #25 + dup z3.h, #19 + dup z4.d, #3 + dup z5.d, #84 + + incw z0.s, pow2, mul #3 + incw z1.s, mul3, mul #2 + inch z2.h, vl2, mul #3 + inch z3.h, vl128, mul #3 + incd z4.d, vl7, mul #3 + incd z5.d, vl1, mul#3 + )"); + n = 1; + while (maxElemsS >= std::pow(2, n)) { + n = n + 1; + } + uint16_t pow2S = std::pow(2, n - 1); + + CHECK_NEON(0, int32_t, + fillNeon({(int32_t)(15 + (pow2S * 3))}, (VL / 8))); + CHECK_NEON( + 1, int32_t, + fillNeon({(int32_t)(37 + ((maxElemsS - (maxElemsS % 3)) * 2))}, + (VL / 8))); + CHECK_NEON( + 2, int16_t, + fillNeon({(int16_t)((maxElemsH >= 2) ? (25 + (2 * 3)) : 25)}, + (VL / 8))); + CHECK_NEON( + 3, int16_t, + fillNeon({(int16_t)((maxElemsH >= 128) ? (19 + (128 * 3)) : 19)}, + (VL / 8))); + CHECK_NEON(4, int64_t, + fillNeon( + {(int64_t)((maxElemsD >= 7) ? (3 + (7 * 3)) : 3)}, (VL / 8))); + CHECK_NEON( + 5, int64_t, + fillNeon({(int64_t)((maxElemsD >= 1) ? (84 + (1 * 3)) : 84)}, + (VL / 8))); } TEST_P(InstSve, fabs) { diff --git a/test/unit/BTBPredictorTest.cc b/test/unit/BTBPredictorTest.cc deleted file mode 100644 index 5c4656e883..0000000000 --- a/test/unit/BTBPredictorTest.cc +++ /dev/null @@ -1,45 +0,0 @@ -#include "MockInstruction.hh" -#include "gtest/gtest.h" -#include "simeng/BTBPredictor.hh" - -namespace simeng { - -class BTBPredictorTest : public testing::Test { - public: - BTBPredictorTest() : uop(new MockInstruction), uopPtr(uop) { - uop->setInstructionAddress(0); - } - - protected: - MockInstruction* uop; - std::shared_ptr uopPtr; -}; - -// Tests that a BTBPredictor will predict not taken for an unencountered branch -TEST_F(BTBPredictorTest, Miss) { - auto predictor = simeng::BTBPredictor(8); - auto prediction = predictor.predict(uopPtr); - EXPECT_FALSE(prediction.taken); -} - -// Tests that a BTBPredictor will predict a previously encountered branch -// correctly, when no address aliasing has occurred -TEST_F(BTBPredictorTest, Hit) { - auto predictor = simeng::BTBPredictor(8); - predictor.update(uopPtr, true, 1); - auto prediction = predictor.predict(uopPtr); - EXPECT_TRUE(prediction.taken); - EXPECT_EQ(prediction.target, 1); -} - -// Tests that a BTBPredictor will predict not taken after a branch direction -// change -TEST_F(BTBPredictorTest, DirectionChange) { - auto predictor = simeng::BTBPredictor(8); - predictor.update(uopPtr, true, 1); - predictor.update(uopPtr, false, 0); - auto prediction = predictor.predict(uopPtr); - EXPECT_FALSE(prediction.taken); -} - -} // namespace simeng diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 36c9d9078a..a3e400aad2 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -10,7 +10,7 @@ set(TEST_SOURCES pipeline/RegisterAliasTableTest.cc pipeline/ReorderBufferTest.cc pipeline/WritebackUnitTest.cc - BTBPredictorTest.cc + GenericPredictorTest.cc ISATest.cc RegisterValueTest.cc PoolTest.cc diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc new file mode 100644 index 0000000000..522bad3067 --- /dev/null +++ b/test/unit/GenericPredictorTest.cc @@ -0,0 +1,155 @@ +#include "MockInstruction.hh" +#include "gtest/gtest.h" +#include "simeng/GenericPredictor.hh" + +namespace simeng { + +class GenericPredictorTest : public testing::Test { + public: + GenericPredictorTest() : uop(new MockInstruction), uopPtr(uop) { + uop->setInstructionAddress(0); + } + + protected: + MockInstruction* uop; + std::shared_ptr uopPtr; +}; + +// Tests that a GenericPredictor will predict the correct direction on a +// miss +TEST_F(GenericPredictorTest, Miss) { + auto predictor = simeng::GenericPredictor(YAML::Load( + "{Branch-Predictor: {BTB-Tag-Bits: 11, Saturating-Count-Bits: 2, " + "Global-History-Length: 10, RAS-entries: 5, Fallback-Static-Predictor: " + "2}}")); + auto prediction = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + + predictor = simeng::GenericPredictor(YAML::Load( + "{Branch-Predictor: {BTB-Tag-Bits: 11, Saturating-Count-Bits: 2, " + "Global-History-Length: 10, RAS-entries: 5, Fallback-Static-Predictor: " + "1}}")); + prediction = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_FALSE(prediction.taken); + prediction = predictor.predict(8, BranchType::Unconditional, 0); + EXPECT_TRUE(prediction.taken); +} + +// Tests that a GenericPredictor will predict branch-and-link return pairs +// correctly +TEST_F(GenericPredictorTest, RAS) { + auto predictor = simeng::GenericPredictor(YAML::Load( + "{Branch-Predictor: {BTB-Tag-Bits: 11, Saturating-Count-Bits: 2, " + "Global-History-Length: 10, RAS-entries: 10, Fallback-Static-Predictor: " + "2}}")); + auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 16); + prediction = predictor.predict(24, BranchType::SubroutineCall, 8); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 32); + prediction = predictor.predict(40, BranchType::SubroutineCall, 8); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 48); + prediction = predictor.predict(56, BranchType::SubroutineCall, 8); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 64); + prediction = predictor.predict(72, BranchType::SubroutineCall, 8); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 80); + + prediction = predictor.predict(84, BranchType::Return, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 76); + prediction = predictor.predict(68, BranchType::Return, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 60); + prediction = predictor.predict(52, BranchType::Return, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 44); + prediction = predictor.predict(36, BranchType::Return, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 28); + prediction = predictor.predict(20, BranchType::Return, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 12); +} + +// Tests that a GenericPredictor will predict a previously encountered branch +// correctly, when no address aliasing has occurred +TEST_F(GenericPredictorTest, Hit) { + auto predictor = simeng::GenericPredictor(YAML::Load( + "{Branch-Predictor: {BTB-Tag-Bits: 11, Saturating-Count-Bits: 2, " + "Global-History-Length: 1, RAS-entries: 5, Fallback-Static-Predictor: " + "2}}")); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional); + + auto prediction = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 16); +} + +// Tests that a GenericPredictor will predict correctly for two different +// behaviours of the same branch but in different states of the program +TEST_F(GenericPredictorTest, GlobalIndexing) { + auto predictor = simeng::GenericPredictor(YAML::Load( + "{Branch-Predictor: {BTB-Tag-Bits: 11, Saturating-Count-Bits: 2, " + "Global-History-Length: 5, RAS-entries: 5, Fallback-Static-Predictor: " + "1}}")); + // Spool up first global history pattern + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + // Ensure default behaviour for first encounter + auto prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + EXPECT_FALSE(prediction.taken); + EXPECT_EQ(prediction.target, 0x23); + // Set entry in BTB + predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + + // Spool up second global history pattern + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + // Ensure default behaviour for re-encounter but with different global history + prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + EXPECT_FALSE(prediction.taken); + EXPECT_EQ(prediction.target, 0x23); + // Set entry in BTB + predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + + // Recreate first global history pattern + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + // Get prediction + prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0xAB); + // Set entry in BTB + predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + + // Recreate second global history pattern + predictor.update(0, false, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, true, 4, BranchType::Unconditional); + predictor.update(0, false, 4, BranchType::Unconditional); + // Get prediction + prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0xBA); + predictor.update(0x1F, true, 0xBA, BranchType::Conditional); +} + +} // namespace simeng diff --git a/test/unit/ISATest.cc b/test/unit/ISATest.cc index 65e032373a..70f77edcdc 100644 --- a/test/unit/ISATest.cc +++ b/test/unit/ISATest.cc @@ -9,7 +9,8 @@ namespace { TEST(ISATest, CreateAArch64) { simeng::kernel::Linux kernel; YAML::Node config = YAML::Load( - "{Core: {Simulation-Mode: emulation, Micro-Operations: True, " + "{Core: {Simulation-Mode: emulation, Clock-Frequency: 2.5, " + "Timer-Frequency: 100, Micro-Operations: True, " "Vector-Length: 512}}"); // Pass a config file with only the options required by the aarch64 // architecture class to function diff --git a/test/unit/MockArchitecture.hh b/test/unit/MockArchitecture.hh index f2572c0eb4..802b9a6585 100644 --- a/test/unit/MockArchitecture.hh +++ b/test/unit/MockArchitecture.hh @@ -8,21 +8,22 @@ namespace simeng { /** Mock implementation of the `Architecture` interface. */ class MockArchitecture : public arch::Architecture { public: - MOCK_CONST_METHOD5(predecode, + MOCK_CONST_METHOD4(predecode, uint8_t(const void* ptr, uint8_t bytesAvailable, - uint64_t instructionAddress, - BranchPrediction prediction, MacroOp& output)); + uint64_t instructionAddress, MacroOp& output)); MOCK_CONST_METHOD0(getRegisterFileStructures, std::vector()); MOCK_CONST_METHOD1(canRename, bool(Register reg)); - MOCK_CONST_METHOD1(getSystemRegisterTag, uint16_t(uint16_t reg)); + MOCK_CONST_METHOD1(getSystemRegisterTag, int32_t(uint16_t reg)); + MOCK_CONST_METHOD0(getNumSystemRegisters, uint16_t()); MOCK_CONST_METHOD3(handleException, std::shared_ptr( const std::shared_ptr& instruction, const Core& core, MemoryInterface& memory)); MOCK_CONST_METHOD0(getInitialState, arch::ProcessStateChange()); MOCK_CONST_METHOD0(getMaxInstructionSize, uint8_t()); - MOCK_CONST_METHOD0(getVCTreg, simeng::Register()); + MOCK_CONST_METHOD2(updateSystemTimerRegisters, + void(RegisterFileSet* regFile, const uint64_t iterations)); }; } // namespace simeng diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 47d577754a..ac0d42966b 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -8,9 +8,11 @@ namespace simeng { /** Mock implementation of the `BranchPredictor` interface. */ class MockBranchPredictor : public BranchPredictor { public: - MOCK_METHOD1(predict, BranchPrediction(std::shared_ptr& uop)); - MOCK_METHOD3(update, void(std::shared_ptr& uop, bool taken, - uint64_t targetAddress)); + MOCK_METHOD3(predict, BranchPrediction(uint64_t address, BranchType type, + uint64_t knownTarget)); + MOCK_METHOD4(update, void(uint64_t address, bool taken, + uint64_t targetAddress, BranchType type)); + MOCK_METHOD1(flush, void(uint64_t address)); }; } // namespace simeng diff --git a/test/unit/MockInstruction.hh b/test/unit/MockInstruction.hh index 7577689f7f..5574b06c78 100644 --- a/test/unit/MockInstruction.hh +++ b/test/unit/MockInstruction.hh @@ -25,19 +25,18 @@ class MockInstruction : public Instruction { MOCK_CONST_METHOD0(checkEarlyBranchMisprediction, std::tuple()); + MOCK_CONST_METHOD0(getBranchType, BranchType()); + MOCK_CONST_METHOD0(getKnownTarget, uint64_t()); MOCK_CONST_METHOD0(isStoreAddress, bool()); MOCK_CONST_METHOD0(isStoreData, bool()); MOCK_CONST_METHOD0(isLoad, bool()); MOCK_CONST_METHOD0(isBranch, bool()); MOCK_CONST_METHOD0(isASIMD, bool()); - MOCK_CONST_METHOD0(isRET, bool()); - MOCK_CONST_METHOD0(isBL, bool()); MOCK_CONST_METHOD0(isPredicate, bool()); MOCK_CONST_METHOD0(getGroup, uint16_t()); - MOCK_METHOD1(setSupportedPorts, void(std::vector)); - MOCK_METHOD0(getSupportedPorts, const std::vector&()); + MOCK_METHOD0(getSupportedPorts, const std::vector&()); void setBranchResults(bool wasTaken, uint64_t targetAddress) { branchTaken_ = wasTaken; diff --git a/test/unit/pipeline/DecodeUnitTest.cc b/test/unit/pipeline/DecodeUnitTest.cc index 88134712ce..71062f35bc 100644 --- a/test/unit/pipeline/DecodeUnitTest.cc +++ b/test/unit/pipeline/DecodeUnitTest.cc @@ -68,12 +68,16 @@ TEST_F(PipelineDecodeUnitTest, Flush) { uop->setInstructionAddress(2); + // Return branch type as unconditional by default + ON_CALL(*uop, getBranchType()) + .WillByDefault(Return(BranchType::Unconditional)); + EXPECT_CALL(*uop, checkEarlyBranchMisprediction()) .WillOnce(Return(std::tuple(true, 1))); EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); // Check the predictor is updated with the correct instruction address and PC - EXPECT_CALL(predictor, update(uopPtr, false, 1)); + EXPECT_CALL(predictor, update(2, false, 1, BranchType::Unconditional)); decodeUnit.tick(); diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index bd0c0f7eb2..eb130f53ad 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -101,9 +101,12 @@ TEST_F(PipelineExecuteUnitTest, ExecuteBranch) { ON_CALL(*uop, canExecute()).WillByDefault(Return(true)); // Anticipate testing instruction type; return true for branch ON_CALL(*uop, isBranch()).WillByDefault(Return(true)); + // Return branch type as unconditional by default + ON_CALL(*uop, getBranchType()) + .WillByDefault(Return(BranchType::Unconditional)); - const bool taken = true; - const uint64_t pc = 1; + bool taken = true; + uint64_t pc = 1; const uint64_t insnAddress = 2; uop->setInstructionAddress(insnAddress); @@ -115,7 +118,9 @@ TEST_F(PipelineExecuteUnitTest, ExecuteBranch) { })); // Check that the branch predictor was updated with the results - EXPECT_CALL(predictor, update(uopPtr, taken, pc)).Times(1); + EXPECT_CALL(*uop, getBranchType()).Times(1); + EXPECT_CALL(predictor, update(2, taken, pc, BranchType::Unconditional)) + .Times(1); // Check that empty forwarding call is made EXPECT_CALL(executionHandlers, forwardOperands(IsEmpty(), IsEmpty())) diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 66edf43b9a..fef76a9f61 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -45,26 +45,18 @@ class PipelineFetchUnitTest : public testing::Test { std::shared_ptr uopPtr; }; -// Tests that ticking a fetch unit attempts to predict a branch, attempts to -// predecode from the correct program counter using the supplied prediction, and -// generates output correctly. +// Tests that ticking a fetch unit attempts to predecode from the correct +// program counter and generates output correctly. TEST_F(PipelineFetchUnitTest, Tick) { - BranchPrediction prediction{false, 0}; MacroOp macroOp = {uopPtr}; ON_CALL(memory, getCompletedReads()).WillByDefault(Return(completedReads)); ON_CALL(isa, getMaxInstructionSize()).WillByDefault(Return(4)); - // Verify the prediction matches the one we provided // Set the output parameter to a 1-wide macro-op - EXPECT_CALL(isa, predecode(_, _, 0, - AllOf(Field(&BranchPrediction::taken, false), - Field(&BranchPrediction::target, 0)), - _)) - .WillOnce(DoAll(SetArgReferee<4>(macroOp), Return(4))); - - EXPECT_CALL(predictor, predict(uopPtr)).WillOnce(Return(prediction)); + EXPECT_CALL(isa, predecode(_, _, 0, _)) + .WillOnce(DoAll(SetArgReferee<3>(macroOp), Return(4))); fetchUnit.tick(); @@ -76,9 +68,12 @@ TEST_F(PipelineFetchUnitTest, Tick) { TEST_F(PipelineFetchUnitTest, TickStalled) { output.stall(true); - EXPECT_CALL(isa, predecode(_, _, _, _, _)).Times(0); + // Anticipate testing instruction type; return true for branch + ON_CALL(*uop, isBranch()).WillByDefault(Return(true)); + + EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _)).Times(0); fetchUnit.tick(); @@ -94,7 +89,7 @@ TEST_F(PipelineFetchUnitTest, FetchUnaligned) { ON_CALL(memory, getCompletedReads()).WillByDefault(Return(completedReads)); // Set PC to 14, so there will not be enough data to start decoding - EXPECT_CALL(isa, predecode(_, _, _, _, _)).Times(0); + EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); fetchUnit.updatePC(14); fetchUnit.tick(); @@ -107,8 +102,8 @@ TEST_F(PipelineFetchUnitTest, FetchUnaligned) { MemoryReadResult nextBlockValue = {{16, 16}, 0, 1}; span nextBlock = {&nextBlockValue, 1}; EXPECT_CALL(memory, getCompletedReads()).WillOnce(Return(nextBlock)); - EXPECT_CALL(isa, predecode(_, _, _, _, _)) - .WillOnce(DoAll(SetArgReferee<4>(macroOp), Return(4))); + EXPECT_CALL(isa, predecode(_, _, _, _)) + .WillOnce(DoAll(SetArgReferee<3>(macroOp), Return(4))); fetchUnit.tick(); } diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 3456c677ba..66b8f93dc4 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -1,3 +1,4 @@ +#include "../MockBranchPredictor.hh" #include "../MockInstruction.hh" #include "../MockMemoryInterface.hh" #include "gmock/gmock.h" @@ -31,9 +32,10 @@ class ReorderBufferTest : public testing::Test { uop2(new MockInstruction), uopPtr(uop), uopPtr2(uop2), - reorderBuffer(maxROBSize, rat, lsq, [this](auto insn) { - exceptionHandler.raiseException(insn); - }) {} + reorderBuffer( + maxROBSize, rat, lsq, + [this](auto insn) { exceptionHandler.raiseException(insn); }, + [](auto branchAddress) {}, predictor, 0, 0) {} protected: const uint8_t maxLSQLoads = 32; @@ -43,6 +45,7 @@ class ReorderBufferTest : public testing::Test { char memory[1024]; RegisterAliasTable rat; LoadStoreQueue lsq; + MockBranchPredictor predictor; MockExceptionHandler exceptionHandler;