diff --git a/parallel-rsp/.clang-format b/parallel-rsp/.clang-format
new file mode 100755
index 0000000..443f90b
--- /dev/null
+++ b/parallel-rsp/.clang-format
@@ -0,0 +1,167 @@
+# The style used for all options not specifically set in the configuration.
+BasedOnStyle: LLVM
+
+# The extra indent or outdent of access modifiers, e.g. public:.
+AccessModifierOffset: -4
+
+# If true, aligns escaped newlines as far left as possible. Otherwise puts them into the right-most column.
+AlignEscapedNewlinesLeft: true
+
+# If true, aligns trailing comments.
+AlignTrailingComments: false
+
+# Allow putting all parameters of a function declaration onto the next line even if BinPackParameters is false.
+AllowAllParametersOfDeclarationOnNextLine: false
+
+# Allows contracting simple braced statements to a single line.
+AllowShortBlocksOnASingleLine: false
+
+# If true, short case labels will be contracted to a single line.
+AllowShortCaseLabelsOnASingleLine: false
+
+# Dependent on the value, int f() { return 0; } can be put on a single line. Possible values: None, Inline, All.
+AllowShortFunctionsOnASingleLine: None
+
+# If true, if (a) return; can be put on a single line.
+AllowShortIfStatementsOnASingleLine: false
+
+# If true, while (true) continue; can be put on a single line.
+AllowShortLoopsOnASingleLine: false
+
+# If true, always break after function definition return types.
+AlwaysBreakAfterDefinitionReturnType: false
+
+# If true, always break before multiline string literals.
+AlwaysBreakBeforeMultilineStrings: false
+
+# If true, always break after the template<...> of a template declaration.
+AlwaysBreakTemplateDeclarations: true
+
+# If false, a function call's arguments will either be all on the same line or will have one line each.
+BinPackArguments: true
+
+# If false, a function declaration's or function definition's parameters will either all be on the same line
+# or will have one line each.
+BinPackParameters: true
+
+# The way to wrap binary operators. Possible values: None, NonAssignment, All.
+BreakBeforeBinaryOperators: None
+
+# The brace breaking style to use. Possible values: Attach, Linux, Stroustrup, Allman, GNU.
+BreakBeforeBraces: Allman
+
+# If true, ternary operators will be placed after line breaks.
+BreakBeforeTernaryOperators: false
+
+# Always break constructor initializers before commas and align the commas with the colon.
+BreakConstructorInitializersBeforeComma: true
+
+# The column limit. A column limit of 0 means that there is no column limit.
+ColumnLimit: 120
+
+# A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed.
+CommentPragmas: '^ *'
+
+# If the constructor initializers don't fit on a line, put each initializer on its own line.
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+
+# The number of characters to use for indentation of constructor initializer lists.
+ConstructorInitializerIndentWidth: 4
+
+# Indent width for line continuations.
+ContinuationIndentWidth: 4
+
+# If true, format braced lists as best suited for C++11 braced lists.
+Cpp11BracedListStyle: false
+
+# Disables formatting at all.
+DisableFormat: false
+
+# A vector of macros that should be interpreted as foreach loops instead of as function calls.
+#ForEachMacros: ''
+
+# Indent case labels one level from the switch statement.
+# When false, use the same indentation level as for the switch statement.
+# Switch statement body is always indented one level more than case labels.
+IndentCaseLabels: false
+
+# The number of columns to use for indentation.
+IndentWidth: 4
+
+# Indent if a function definition or declaration is wrapped after the type.
+IndentWrappedFunctionNames: false
+
+# If true, empty lines at the start of blocks are kept.
+KeepEmptyLinesAtTheStartOfBlocks: true
+
+# Language, this format style is targeted at. Possible values: None, Cpp, Java, JavaScript, Proto.
+Language: Cpp
+
+# The maximum number of consecutive empty lines to keep.
+MaxEmptyLinesToKeep: 1
+
+# The indentation used for namespaces. Possible values: None, Inner, All.
+NamespaceIndentation: None
+
+# The penalty for breaking a function call after "call(".
+PenaltyBreakBeforeFirstCallParameter: 19
+
+# The penalty for each line break introduced inside a comment.
+PenaltyBreakComment: 300
+
+# The penalty for breaking before the first <<.
+PenaltyBreakFirstLessLess: 120
+
+# The penalty for each line break introduced inside a string literal.
+PenaltyBreakString: 1000
+
+# The penalty for each character outside of the column limit.
+PenaltyExcessCharacter: 1000000
+
+# Penalty for putting the return type of a function onto its own line.
+PenaltyReturnTypeOnItsOwnLine: 1000000000
+
+# Pointer and reference alignment style. Possible values: Left, Right, Middle.
+PointerAlignment: Right
+
+# If true, a space may be inserted after C style casts.
+SpaceAfterCStyleCast: false
+
+# If false, spaces will be removed before assignment operators.
+SpaceBeforeAssignmentOperators: true
+
+# Defines in which cases to put a space before opening parentheses. Possible values: Never, ControlStatements, Always.
+SpaceBeforeParens: ControlStatements
+
+# If true, spaces may be inserted into '()'.
+SpaceInEmptyParentheses: false
+
+# The number of spaces before trailing line comments (// - comments).
+SpacesBeforeTrailingComments: 1
+
+# If true, spaces will be inserted after '<' and before '>' in template argument lists.
+SpacesInAngles: false
+
+# If true, spaces may be inserted into C style casts.
+SpacesInCStyleCastParentheses: false
+
+# If true, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals).
+SpacesInContainerLiterals: false
+
+# If true, spaces will be inserted after '(' and before ')'.
+SpacesInParentheses: false
+
+# If true, spaces will be inserted after '[' and befor']'.
+SpacesInSquareBrackets: false
+
+# Format compatible with this standard, e.g. use A > instead of A> for LS_Cpp03. Possible values: Cpp03, Cpp11, Auto.
+Standard: Cpp11
+
+# The number of columns used for tab stops.
+TabWidth: 4
+
+# The way to use tab characters in the resulting file. Possible values: Never, ForIndentation, Always.
+UseTab: ForIndentation
+
+# Do not reflow comments
+ReflowComments: false
diff --git a/parallel-rsp/.gitignore b/parallel-rsp/.gitignore
new file mode 100644
index 0000000..51e8cd3
--- /dev/null
+++ b/parallel-rsp/.gitignore
@@ -0,0 +1,8 @@
+*.o
+*.d
+*.bin
+*.elf
+/cmake-build-*
+/.idea
+*.iml
+/build-*
diff --git a/parallel-rsp/CMakeLists.txt b/parallel-rsp/CMakeLists.txt
new file mode 100644
index 0000000..43e5f5f
--- /dev/null
+++ b/parallel-rsp/CMakeLists.txt
@@ -0,0 +1,99 @@
+cmake_minimum_required(VERSION 3.5)
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_C_STANDARD 99)
+project(parallel-rsp LANGUAGES CXX C)
+
+
+set(NAME_PLUGIN_M64P "mupen64plus-rsp-parallel")
+
+include_directories(../mupen64plus-core/src/api)
+add_definitions(-DM64P_PLUGIN_API)
+add_definitions(-DPARALLEL_INTEGRATION)
+
+if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang"))
+ set(PARALLEL_RSP_CXX_FLAGS -Wall -Wextra -Wno-missing-field-initializers -Wno-empty-body -ffast-math -Wno-unused-parameter)
+elseif (MSVC)
+ set(PARALLEL_RSP_CXX_FLAGS /D_CRT_SECURE_NO_WARNINGS /wd4267 /wd4244 /wd4309 /wd4005 /MP /DNOMINMAX)
+endif()
+
+add_library(${NAME_PLUGIN_M64P} SHARED
+# main.cpp
+ parallel.cpp
+# debug_rsp.cpp
+ rsp/vfunctions.cpp
+ rsp_jit.cpp rsp_jit.hpp
+ jit_allocator.cpp jit_allocator.hpp
+ rsp_disasm.cpp rsp_disasm.hpp
+ rsp/ls.cpp rsp/pipeline.h
+ rsp/reciprocal.cpp rsp/reciprocal.h
+ rsp_1.1.h
+ rsp/cp0.cpp rsp/cp2.cpp
+ arch/simd/rsp/rsp_core.cpp
+ arch/simd/rsp/clamp.h
+ arch/simd/rsp/rsp_common.h
+ arch/simd/rsp/SSE2NEON.h
+ arch/simd/rsp/rsp_impl.h
+ arch/simd/rsp/vcr.h
+ arch/simd/rsp/vabs.h
+ arch/simd/rsp/vadd.h
+ arch/simd/rsp/vaddc.h
+ arch/simd/rsp/vand.h
+ arch/simd/rsp/vch.h
+ arch/simd/rsp/vcl.h
+ arch/simd/rsp/vcr.h
+ arch/simd/rsp/vcmp.h
+ arch/simd/rsp/vdivh.h
+ arch/simd/rsp/vmac.h
+ arch/simd/rsp/vmov.h
+ arch/simd/rsp/vmrg.h
+ arch/simd/rsp/vmudh.h
+ arch/simd/rsp/vmul.h
+ arch/simd/rsp/vmull.h
+ arch/simd/rsp/vmulh.h
+ arch/simd/rsp/vmuln.h
+ arch/simd/rsp/vor.h
+ arch/simd/rsp/vrcpsq.h
+ arch/simd/rsp/vrsq.h
+ arch/simd/rsp/vsub.h
+ arch/simd/rsp/vsubc.h
+ arch/simd/rsp/vxor.h
+ arch/simd/rsp/vmulm.h)
+
+option(PARALLEL_RSP_DEBUG_JIT "Enable the debug JIT." OFF)
+
+if (PARALLEL_RSP_DEBUG_JIT)
+ if (ANDROID)
+ message("Android does not support debug JIT. Disabling it.")
+ elseif (NOT WIN32)
+ target_sources(${NAME_PLUGIN_M64P} PRIVATE debug_rsp.cpp debug_rsp.hpp debug_jit.cpp debug_jit.hpp)
+ target_compile_definitions(${NAME_PLUGIN_M64P} PUBLIC PARALLEL_RSP_DEBUG_JIT)
+ endif()
+endif()
+
+set_target_properties(${NAME_PLUGIN_M64P} PROPERTIES PREFIX "")
+target_include_directories(${NAME_PLUGIN_M64P} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(${NAME_PLUGIN_M64P} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/arch/simd/rsp)
+target_include_directories(${NAME_PLUGIN_M64P} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/api)
+target_compile_options(${NAME_PLUGIN_M64P} PRIVATE ${PARALLEL_RSP_CXX_FLAGS})
+
+option(PARALLEL_RSP_BAKED_LIGHTNING "Use built-in Lightning." ON)
+
+target_compile_definitions(${NAME_PLUGIN_M64P} PUBLIC PARALLEL_RSP_LIGHTNING)
+if (PARALLEL_RSP_BAKED_LIGHTNING)
+ add_library(lightning STATIC
+ lightning/lib/jit_disasm.c
+ lightning/lib/jit_memory.c
+ lightning/lib/jit_names.c
+ lightning/lib/jit_note.c
+ lightning/lib/jit_print.c
+ lightning/lib/jit_size.c
+ lightning/lib/lightning.c)
+ set_property(TARGET lightning PROPERTY POSITION_INDEPENDENT_CODE ON)
+ target_include_directories(lightning PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/lightning/include)
+ if (WIN32)
+ target_sources(lightning PRIVATE win32/mman/sys/mman.c)
+ target_include_directories(lightning PRIVATE win32/mman)
+ endif()
+endif()
+target_link_libraries(${NAME_PLUGIN_M64P} PUBLIC lightning)
diff --git a/parallel-rsp/CREDITS.txt b/parallel-rsp/CREDITS.txt
new file mode 100644
index 0000000..49f4064
--- /dev/null
+++ b/parallel-rsp/CREDITS.txt
@@ -0,0 +1,13 @@
+Written by Themaister.
+
+The code is heavily reliant on MarathonMan's CEN64 RSP implementation, as well as CXD4's RSP implementation.
+
+MIPS core: Rewritten from scratch
+CP0: Near copy-pasta from CEN64
+CP2: Near copy-pasta from CEN64
+LS pipe: Near copy-pasta from CXD4
+Mupen64plus glue code: Reused most of CXD4.
+Lightning jitter interface: Written from scratch
+
+The plugin's focus is to support dynamic recompilation for performance,
+instead of being pure interpreters as CEN64 and CXD4's implementations are.
diff --git a/parallel-rsp/LICENSE b/parallel-rsp/LICENSE
new file mode 100644
index 0000000..03a00fc
--- /dev/null
+++ b/parallel-rsp/LICENSE
@@ -0,0 +1,16 @@
+==============
+parallel-rsp
+==============
+
+This project is dual licensed under
+
+MIT (LICENSE.MIT)
+
+or
+
+LGPLv3 (LICENSE.LESSER)
+
+If statically linking against the GNU Lightning project (lightning/),
+note that Lightning is dual-licensed as GPLv3 or LGPLv3.
+parallel-rsp can be configured to dynamically link against Lightning or not link against Lightning at all.
+
diff --git a/parallel-rsp/LICENSE.LESSER b/parallel-rsp/LICENSE.LESSER
new file mode 100644
index 0000000..fc8a5de
--- /dev/null
+++ b/parallel-rsp/LICENSE.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/parallel-rsp/LICENSE.MIT b/parallel-rsp/LICENSE.MIT
new file mode 100644
index 0000000..62b163d
--- /dev/null
+++ b/parallel-rsp/LICENSE.MIT
@@ -0,0 +1,20 @@
+Copyright (c) 2020 Hans-Kristian Arntzen
+
+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/parallel-rsp/android_fuzz_runner.sh b/parallel-rsp/android_fuzz_runner.sh
new file mode 100755
index 0000000..b9a2ad7
--- /dev/null
+++ b/parallel-rsp/android_fuzz_runner.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+RSP_FUZZ="$1"
+
+adb push "$RSP_FUZZ" /data/local/tmp/rsp-vu-fuzzer >/dev/null || exit 1
+adb shell chmod +x /data/local/tmp/rsp-vu-fuzzer >/dev/null || exit 1
+adb shell /data/local/tmp/rsp-vu-fuzzer || exit 1
+adb shell rm /data/local/tmp/rsp-vu-fuzzer || exit 1
diff --git a/parallel-rsp/android_test_runner.sh b/parallel-rsp/android_test_runner.sh
new file mode 100755
index 0000000..0b071bc
--- /dev/null
+++ b/parallel-rsp/android_test_runner.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+RSP_RUNNER="$1"
+RSP_BINFOLDER="$2"
+TEST_NAME="$3"
+
+adb push "$RSP_RUNNER" /data/local/tmp/rsp-runner >/dev/null || exit 1
+adb shell chmod +x /data/local/tmp/rsp-runner >/dev/null || exit 1
+adb push "$RSP_BINFOLDER"/"$TEST_NAME".global.bin /data/local/tmp/ >/dev/null || exit 1
+adb push "$RSP_BINFOLDER"/"$TEST_NAME".bin /data/local/tmp/ >/dev/null || exit 1
+adb shell /data/local/tmp/rsp-runner /data/local/tmp/"$TEST_NAME".global.bin /data/local/tmp/"$TEST_NAME".bin || exit 1
+adb shell rm /data/local/tmp/rsp-runner >/dev/null || exit 1
+adb shell rm /data/local/tmp/"$TEST_NAME".global.bin /data/local/tmp/"$TEST_NAME".bin >/dev/null || exit 1
diff --git a/parallel-rsp/arch/simd/rsp/SSE2NEON.h b/parallel-rsp/arch/simd/rsp/SSE2NEON.h
new file mode 100644
index 0000000..23cdd15
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/SSE2NEON.h
@@ -0,0 +1,2791 @@
+#ifndef SSE2NEON_H
+#define SSE2NEON_H
+
+// This header file provides a simple API translation layer
+// between SSE intrinsics to their corresponding Arm/Aarch64 NEON versions
+//
+// This header file does not yet translate all of the SSE intrinsics.
+//
+// Contributors to this work are:
+// John W. Ratcliff
+// Brandon Rowlett
+// Ken Fast
+// Eric van Beurden
+// Alexander Potylitsin
+// Hasindu Gamaarachchi
+// Jim Huang
+// Mark Cheng
+// Malcolm James MacLeod
+
+/*
+ * The MIT license:
+ *
+ * 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.
+ */
+
+#if defined(__GNUC__) || defined(__clang__)
+
+#pragma push_macro("FORCE_INLINE")
+#pragma push_macro("ALIGN_STRUCT")
+#define FORCE_INLINE static inline __attribute__((always_inline))
+#define ALIGN_STRUCT(x) __attribute__((aligned(x)))
+
+#else
+
+#error "Macro name collisions may happens with unknown compiler"
+#ifdef FORCE_INLINE
+#undef FORCE_INLINE
+#endif
+#define FORCE_INLINE static inline
+#ifndef ALIGN_STRUCT
+#define ALIGN_STRUCT(x) __declspec(align(x))
+#endif
+
+#endif
+
+#include
+
+#include "arm_neon.h"
+
+/**
+ * MACRO for shuffle parameter for _mm_shuffle_ps().
+ * Argument fp3 is a digit[0123] that represents the fp from argument "b"
+ * of mm_shuffle_ps that will be placed in fp3 of result. fp2 is the same
+ * for fp2 in result. fp1 is a digit[0123] that represents the fp from
+ * argument "a" of mm_shuffle_ps that will be places in fp1 of result.
+ * fp0 is the same for fp0 of result.
+ */
+#define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \
+ (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0)))
+
+/* indicate immediate constant argument in a given range */
+#define __constrange(a, b) const
+
+typedef float32x2_t __m64;
+typedef float32x4_t __m128;
+typedef int32x4_t __m128i;
+
+// ******************************************
+// type-safe casting between types
+// ******************************************
+
+#define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x)
+#define vreinterpretq_m128_f32(x) (x)
+#define vreinterpretq_m128_f64(x) vreinterpretq_f32_f64(x)
+
+#define vreinterpretq_m128_u8(x) vreinterpretq_f32_u8(x)
+#define vreinterpretq_m128_u16(x) vreinterpretq_f32_u16(x)
+#define vreinterpretq_m128_u32(x) vreinterpretq_f32_u32(x)
+#define vreinterpretq_m128_u64(x) vreinterpretq_f32_u64(x)
+
+#define vreinterpretq_m128_s8(x) vreinterpretq_f32_s8(x)
+#define vreinterpretq_m128_s16(x) vreinterpretq_f32_s16(x)
+#define vreinterpretq_m128_s32(x) vreinterpretq_f32_s32(x)
+#define vreinterpretq_m128_s64(x) vreinterpretq_f32_s64(x)
+
+#define vreinterpretq_f16_m128(x) vreinterpretq_f16_f32(x)
+#define vreinterpretq_f32_m128(x) (x)
+#define vreinterpretq_f64_m128(x) vreinterpretq_f64_f32(x)
+
+#define vreinterpretq_u8_m128(x) vreinterpretq_u8_f32(x)
+#define vreinterpretq_u16_m128(x) vreinterpretq_u16_f32(x)
+#define vreinterpretq_u32_m128(x) vreinterpretq_u32_f32(x)
+#define vreinterpretq_u64_m128(x) vreinterpretq_u64_f32(x)
+
+#define vreinterpretq_s8_m128(x) vreinterpretq_s8_f32(x)
+#define vreinterpretq_s16_m128(x) vreinterpretq_s16_f32(x)
+#define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x)
+#define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x)
+
+#define vreinterpretq_m128i_s8(x) vreinterpretq_s32_s8(x)
+#define vreinterpretq_m128i_s16(x) vreinterpretq_s32_s16(x)
+#define vreinterpretq_m128i_s32(x) (x)
+#define vreinterpretq_m128i_s64(x) vreinterpretq_s32_s64(x)
+
+#define vreinterpretq_m128i_u8(x) vreinterpretq_s32_u8(x)
+#define vreinterpretq_m128i_u16(x) vreinterpretq_s32_u16(x)
+#define vreinterpretq_m128i_u32(x) vreinterpretq_s32_u32(x)
+#define vreinterpretq_m128i_u64(x) vreinterpretq_s32_u64(x)
+
+#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s32(x)
+#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s32(x)
+#define vreinterpretq_s32_m128i(x) (x)
+#define vreinterpretq_s64_m128i(x) vreinterpretq_s64_s32(x)
+
+#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s32(x)
+#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s32(x)
+#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s32(x)
+#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s32(x)
+
+// A struct is defined in this header file called 'SIMDVec' which can be used
+// by applications which attempt to access the contents of an _m128 struct
+// directly. It is important to note that accessing the __m128 struct directly
+// is bad coding practice by Microsoft: @see:
+// https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx
+//
+// However, some legacy source code may try to access the contents of an __m128
+// struct directly so the developer can use the SIMDVec as an alias for it. Any
+// casting must be done manually by the developer, as you cannot cast or
+// otherwise alias the base NEON data type for intrinsic operations.
+//
+// union intended to allow direct access to an __m128 variable using the names
+// that the MSVC compiler provides. This union should really only be used when
+// trying to access the members of the vector as integer values. GCC/clang
+// allow native access to the float members through a simple array access
+// operator (in C since 4.6, in C++ since 4.8).
+//
+// Ideally direct accesses to SIMD vectors should not be used since it can cause
+// a performance hit. If it really is needed however, the original __m128
+// variable can be aliased with a pointer to this union and used to access
+// individual components. The use of this union should be hidden behind a macro
+// that is used throughout the codebase to access the members instead of always
+// declaring this type of variable.
+typedef union ALIGN_STRUCT(16) SIMDVec {
+ float
+ m128_f32[4]; // as floats - do not to use this. Added for convenience.
+ int8_t m128_i8[16]; // as signed 8-bit integers.
+ int16_t m128_i16[8]; // as signed 16-bit integers.
+ int32_t m128_i32[4]; // as signed 32-bit integers.
+ int64_t m128_i64[2]; // as signed 64-bit integers.
+ uint8_t m128_u8[16]; // as unsigned 8-bit integers.
+ uint16_t m128_u16[8]; // as unsigned 16-bit integers.
+ uint32_t m128_u32[4]; // as unsigned 32-bit integers.
+ uint64_t m128_u64[2]; // as unsigned 64-bit integers.
+} SIMDVec;
+
+// casting using SIMDVec
+#define vreinterpretq_nth_u64_m128i(x, n) (((SIMDVec *) &x)->m128_u64[n])
+#define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n])
+
+
+// ******************************************
+// Backwards compatibility for compilers with lack of specific type support
+// ******************************************
+
+// Older gcc does not define vld1q_u8_x4 type
+#if defined(__GNUC__) && !defined(__clang__)
+#if __GNUC__ < 9 || (__GNUC__ == 9 && (__GNUC_MINOR__ <= 2))
+FORCE_INLINE uint8x16x4_t vld1q_u8_x4(const uint8_t *p)
+{
+ uint8x16x4_t ret;
+ ret.val[0] = vld1q_u8(p + 0);
+ ret.val[1] = vld1q_u8(p + 16);
+ ret.val[2] = vld1q_u8(p + 32);
+ ret.val[3] = vld1q_u8(p + 48);
+ return ret;
+}
+#endif
+#endif
+
+
+// ******************************************
+// Set/get methods
+// ******************************************
+
+// Loads one cache line of data from address p to a location closer to the
+// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx
+FORCE_INLINE void _mm_prefetch(const void *p, int i)
+{
+ __builtin_prefetch(p);
+}
+
+// extracts the lower order floating point value from the parameter :
+// https://msdn.microsoft.com/en-us/library/bb514059%28v=vs.120%29.aspx?f=255&MSPPError=-2147217396
+FORCE_INLINE float _mm_cvtss_f32(__m128 a)
+{
+ return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+}
+
+// Sets the 128-bit value to zero
+// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_setzero_si128(void)
+{
+ return vreinterpretq_m128i_s32(vdupq_n_s32(0));
+}
+
+// Clears the four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setzero_ps(void)
+{
+ return vreinterpretq_m128_f32(vdupq_n_f32(0));
+}
+
+// Sets the four single-precision, floating-point values to w.
+//
+// r0 := r1 := r2 := r3 := w
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set1_ps(float _w)
+{
+ return vreinterpretq_m128_f32(vdupq_n_f32(_w));
+}
+
+// Sets the four single-precision, floating-point values to w.
+// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps1(float _w)
+{
+ return vreinterpretq_m128_f32(vdupq_n_f32(_w));
+}
+
+// Sets the four single-precision, floating-point values to the four inputs.
+// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x)
+{
+ float __attribute__((aligned(16))) data[4] = {x, y, z, w};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Sets the four single-precision, floating-point values to the four inputs in
+// reverse order.
+// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x)
+{
+ float __attribute__((aligned(16))) data[4] = {w, z, y, x};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Sets the 8 signed 16-bit integer values in reverse order.
+//
+// Return Value
+// r0 := w0
+// r1 := w1
+// ...
+// r7 := w7
+FORCE_INLINE __m128i _mm_setr_epi16(short w0,
+ short w1,
+ short w2,
+ short w3,
+ short w4,
+ short w5,
+ short w6,
+ short w7)
+{
+ int16_t __attribute__((aligned(16)))
+ data[8] = {w0, w1, w2, w3, w4, w5, w6, w7};
+ return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data));
+}
+
+// Sets the 4 signed 32-bit integer values in reverse order
+// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0)
+{
+ int32_t __attribute__((aligned(16))) data[4] = {i3, i2, i1, i0};
+ return vreinterpretq_m128i_s32(vld1q_s32(data));
+}
+
+// Sets the 16 signed 8-bit integer values to b.
+//
+// r0 := b
+// r1 := b
+// ...
+// r15 := b
+//
+// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi8(char w)
+{
+ return vreinterpretq_m128i_s8(vdupq_n_s8(w));
+}
+
+// Sets the 8 signed 16-bit integer values to w.
+//
+// r0 := w
+// r1 := w
+// ...
+// r7 := w
+//
+// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set1_epi16(short w)
+{
+ return vreinterpretq_m128i_s16(vdupq_n_s16(w));
+}
+
+// Sets the 16 signed 8-bit integer values.
+// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set_epi8(char b15,
+ char b14,
+ char b13,
+ char b12,
+ char b11,
+ char b10,
+ char b9,
+ char b8,
+ char b7,
+ char b6,
+ char b5,
+ char b4,
+ char b3,
+ char b2,
+ char b1,
+ char b0)
+{
+ int8_t __attribute__((aligned(16)))
+ data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3,
+ (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7,
+ (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11,
+ (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};
+ return (__m128i) vld1q_s8(data);
+}
+
+// Sets the 8 signed 16-bit integer values.
+// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set_epi16(short i7,
+ short i6,
+ short i5,
+ short i4,
+ short i3,
+ short i2,
+ short i1,
+ short i0)
+{
+ int16_t __attribute__((aligned(16)))
+ data[8] = {i0, i1, i2, i3, i4, i5, i6, i7};
+ return vreinterpretq_m128i_s16(vld1q_s16(data));
+}
+
+// Sets the 16 signed 8-bit integer values in reverse order.
+// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_setr_epi8(char b0,
+ char b1,
+ char b2,
+ char b3,
+ char b4,
+ char b5,
+ char b6,
+ char b7,
+ char b8,
+ char b9,
+ char b10,
+ char b11,
+ char b12,
+ char b13,
+ char b14,
+ char b15)
+{
+ int8_t __attribute__((aligned(16)))
+ data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3,
+ (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7,
+ (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11,
+ (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};
+ return (__m128i) vld1q_s8(data);
+}
+
+// Sets the 4 signed 32-bit integer values to i.
+//
+// r0 := i
+// r1 := i
+// r2 := i
+// r3 := I
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi32(int _i)
+{
+ return vreinterpretq_m128i_s32(vdupq_n_s32(_i));
+}
+
+// Sets the 4 signed 64-bit integer values to i.
+// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi64(int64_t _i)
+{
+ return vreinterpretq_m128i_s64(vdupq_n_s64(_i));
+}
+
+// Sets the 4 signed 32-bit integer values.
+// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
+{
+ int32_t __attribute__((aligned(16))) data[4] = {i0, i1, i2, i3};
+ return vreinterpretq_m128i_s32(vld1q_s32(data));
+}
+
+// Returns the __m128i structure with its two 64-bit integer values
+// initialized to the values of the two 64-bit integers passed in.
+// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2)
+{
+ int64_t __attribute__((aligned(16))) data[2] = {i2, i1};
+ return vreinterpretq_m128i_s64(vld1q_s64(data));
+}
+
+// Stores four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ps(float *p, __m128 a)
+{
+ vst1q_f32(p, vreinterpretq_f32_m128(a));
+}
+
+// Stores four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a)
+{
+ vst1q_f32(p, vreinterpretq_f32_m128(a));
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p.
+// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a)
+{
+ vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p.
+// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a)
+{
+ vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));
+}
+
+// Stores the lower single - precision, floating - point value.
+// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ss(float *p, __m128 a)
+{
+ vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0);
+}
+
+// Reads the lower 64 bits of b and stores them into the lower 64 bits of a.
+// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b)
+{
+ uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a));
+ uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b));
+ *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi));
+}
+
+// Stores the lower two single-precision floating point values of a to the
+// address p.
+//
+// *p0 := b0
+// *p1 := b1
+//
+// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx
+FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a)
+{
+ *p = vget_low_f32(a);
+}
+
+// Loads a single single-precision, floating-point value, copying it into all
+// four words
+// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load1_ps(const float *p)
+{
+ return vreinterpretq_m128_f32(vld1q_dup_f32(p));
+}
+#define _mm_load_ps1 _mm_load1_ps
+
+// Sets the lower two single-precision, floating-point values with 64
+// bits of data loaded from the address p; the upper two values are passed
+// through from a.
+//
+// Return Value
+// r0 := *p0
+// r1 := *p1
+// r2 := a2
+// r3 := a3
+//
+// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *b)
+{
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vld1_f32((const float32_t *) b), vget_high_f32(a)));
+}
+
+// Loads four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load_ps(const float *p)
+{
+ return vreinterpretq_m128_f32(vld1q_f32(p));
+}
+
+// Loads four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_loadu_ps(const float *p)
+{
+ // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are
+ // equivalent for neon
+ return vreinterpretq_m128_f32(vld1q_f32(p));
+}
+
+// Loads an single - precision, floating - point value into the low word and
+// clears the upper three words.
+// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_load_ss(const float *p)
+{
+ return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0));
+}
+
+FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p)
+{
+ /* Load the lower 64 bits of the value pointed to by p into the
+ * lower 64 bits of the result, zeroing the upper 64 bits of the result.
+ */
+ return vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0));
+}
+
+// ******************************************
+// Logic/Binary operations
+// ******************************************
+
+// Compares for inequality.
+// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(vmvnq_u32(
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))));
+}
+
+// Computes the bitwise AND-NOT of the four single-precision, floating-point
+// values of a and b.
+//
+// r0 := ~a0 & b0
+// r1 := ~a1 & b1
+// r2 := ~a2 & b2
+// r3 := ~a3 & b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ vbicq_s32(vreinterpretq_s32_m128(b),
+ vreinterpretq_s32_m128(a))); // *NOTE* argument swap
+}
+
+// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the
+// 128-bit value in a.
+//
+// r := (~a) & b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vbicq_s32(vreinterpretq_s32_m128i(b),
+ vreinterpretq_s32_m128i(a))); // *NOTE* argument swap
+}
+
+// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in
+// b.
+//
+// r := a & b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the bitwise AND of the four single-precision, floating-point values
+// of a and b.
+//
+// r0 := a0 & b0
+// r1 := a1 & b1
+// r2 := a2 & b2
+// r3 := a3 & b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Computes the bitwise OR of the four single-precision, floating-point values
+// of a and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Computes bitwise EXOR (exclusive-or) of the four single-precision,
+// floating-point values of a and b.
+// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b.
+//
+// r := a | b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in
+// b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Moves the upper two values of B into the lower two values of A.
+//
+// r3 := a3
+// r2 := a2
+// r1 := b3
+// r0 := b2
+FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B)
+{
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A));
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B));
+ return vreinterpretq_m128_f32(vcombine_f32(b32, a32));
+}
+
+// Moves the lower two values of B into the upper two values of A.
+//
+// r3 := b1
+// r2 := b0
+// r1 := a1
+// r0 := a0
+FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B));
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b10));
+}
+
+// NEON does not provide this method
+// Creates a 4-bit mask from the most significant bits of the four
+// single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_ps(__m128 a)
+{
+#if 0 /* C version */
+ uint32x4_t &ia = *(uint32x4_t *) &a;
+ return (ia[0] >> 31) | ((ia[1] >> 30) & 2) | ((ia[2] >> 29) & 4) |
+ ((ia[3] >> 28) & 8);
+#endif
+ static const uint32x4_t movemask = {1, 2, 4, 8};
+ static const uint32x4_t highbit = {0x80000000, 0x80000000, 0x80000000,
+ 0x80000000};
+ uint32x4_t t0 = vreinterpretq_u32_m128(a);
+ uint32x4_t t1 = vtstq_u32(t0, highbit);
+ uint32x4_t t2 = vandq_u32(t1, movemask);
+ uint32x2_t t3 = vorr_u32(vget_low_u32(t2), vget_high_u32(t2));
+ return vget_lane_u32(t3, 0) | vget_lane_u32(t3, 1);
+}
+
+FORCE_INLINE __m128i _mm_abs_epi32(__m128i a)
+{
+ return vqabsq_s32(a);
+}
+
+FORCE_INLINE __m128i _mm_abs_epi16(__m128i a)
+{
+ return vreinterpretq_s32_s16(vqabsq_s16(vreinterpretq_s16_s32(a)));
+}
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of b and places it into the high end of the result.
+FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b)
+{
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a32, b10));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in high
+// end of result takes the higher two 32 bit values from b and swaps them and
+// places in low end of result.
+FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32x2_t b23 = vrev64_f32(vget_high_f32(vreinterpretq_f32_m128(b)));
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b23));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b)
+{
+ float32x2_t a21 = vget_high_f32(
+ vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));
+ float32x2_t b03 = vget_low_f32(
+ vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));
+ return vreinterpretq_m128_f32(vcombine_f32(a21, b03));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b)
+{
+ float32x2_t a03 = vget_low_f32(
+ vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));
+ float32x2_t b21 = vget_high_f32(
+ vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));
+ return vreinterpretq_m128_f32(vcombine_f32(a03, b21));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b10));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b10));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32x2_t b01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(b)));
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b01));
+}
+
+// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the
+// high
+FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b32));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b)
+{
+ float32x2_t a11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 1);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(vcombine_f32(a11, b00));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b)
+{
+ float32x2_t a22 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(vcombine_f32(a22, b00));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b)
+{
+ float32x2_t a00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 0);
+ float32x2_t b22 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(vcombine_f32(a00, b22));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b)
+{
+ float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ float32x2_t a22 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);
+ float32x2_t a02 = vset_lane_f32(a0, a22, 1); /* TODO: use vzip ?*/
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a02, b32));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b)
+{
+ float32x2_t a33 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 1);
+ float32x2_t b11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a33, b11));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32_t b2 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 2);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b20));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b20));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b)
+{
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a32, b20));
+}
+
+// NEON does not support a general purpose permute intrinsic
+// Selects four specific single-precision, floating-point values from a and b,
+// based on the mask i.
+// https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx
+#if 0 /* C version */
+FORCE_INLINE __m128 _mm_shuffle_ps_default(__m128 a,
+ __m128 b,
+ __constrange(0, 255) int imm)
+{
+ __m128 ret;
+ ret[0] = a[imm & 0x3];
+ ret[1] = a[(imm >> 2) & 0x3];
+ ret[2] = b[(imm >> 4) & 0x03];
+ ret[3] = b[(imm >> 6) & 0x03];
+ return ret;
+}
+#endif
+#define _mm_shuffle_ps_default(a, b, imm) \
+ ({ \
+ float32x4_t ret; \
+ ret = vmovq_n_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(a), (imm) &0x3)); \
+ ret = vsetq_lane_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(a), ((imm) >> 2) & 0x3), \
+ ret, 1); \
+ ret = vsetq_lane_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 4) & 0x3), \
+ ret, 2); \
+ ret = vsetq_lane_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 6) & 0x3), \
+ ret, 3); \
+ vreinterpretq_m128_f32(ret); \
+ })
+
+// FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255)
+// int imm)
+#define _mm_shuffle_ps(a, b, imm) \
+ ({ \
+ __m128 ret; \
+ switch (imm) { \
+ case _MM_SHUFFLE(1, 0, 3, 2): \
+ ret = _mm_shuffle_ps_1032((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 3, 0, 1): \
+ ret = _mm_shuffle_ps_2301((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 3, 2, 1): \
+ ret = _mm_shuffle_ps_0321((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 1, 0, 3): \
+ ret = _mm_shuffle_ps_2103((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 1, 0): \
+ ret = _mm_movelh_ps((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 0, 1): \
+ ret = _mm_shuffle_ps_1001((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 1, 0, 1): \
+ ret = _mm_shuffle_ps_0101((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(3, 2, 1, 0): \
+ ret = _mm_shuffle_ps_3210((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 0, 1, 1): \
+ ret = _mm_shuffle_ps_0011((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 0, 2, 2): \
+ ret = _mm_shuffle_ps_0022((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 2, 0, 0): \
+ ret = _mm_shuffle_ps_2200((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(3, 2, 0, 2): \
+ ret = _mm_shuffle_ps_3202((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(3, 2, 3, 2): \
+ ret = _mm_movehl_ps((b), (a)); \
+ break; \
+ case _MM_SHUFFLE(1, 1, 3, 3): \
+ ret = _mm_shuffle_ps_1133((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 0, 1, 0): \
+ ret = _mm_shuffle_ps_2010((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 0, 0, 1): \
+ ret = _mm_shuffle_ps_2001((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 0, 3, 2): \
+ ret = _mm_shuffle_ps_2032((a), (b)); \
+ break; \
+ default: \
+ ret = _mm_shuffle_ps_default((a), (b), (imm)); \
+ break; \
+ } \
+ ret; \
+ })
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of a and places it into the high end of the result.
+FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a)
+{
+ int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(vcombine_s32(a32, a10));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in low end
+// of result takes the higher two 32 bit values from a and swaps them and places
+// in high end of result.
+FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a)
+{
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a)));
+ return vreinterpretq_m128i_s32(vcombine_s32(a01, a23));
+}
+
+// rotates the least significant 32 bits into the most signficant 32 bits, and
+// shifts the rest down
+FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a)
+{
+ return vreinterpretq_m128i_s32(
+ vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1));
+}
+
+// rotates the most significant 32 bits into the least signficant 32 bits, and
+// shifts the rest up
+FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a)
+{
+ return vreinterpretq_m128i_s32(
+ vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3));
+}
+
+// gets the lower 64 bits of a, and places it in the upper 64 bits
+// gets the lower 64 bits of a and places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a)
+{
+ int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(vcombine_s32(a10, a10));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the
+// lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a)
+{
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(vcombine_s32(a01, a10));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the
+// upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and
+// places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a)
+{
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ return vreinterpretq_m128i_s32(vcombine_s32(a01, a01));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a)
+{
+ int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1);
+ int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0);
+ return vreinterpretq_m128i_s32(vcombine_s32(a11, a22));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a)
+{
+ int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0);
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ return vreinterpretq_m128i_s32(vcombine_s32(a22, a01));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a)
+{
+ int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1);
+ return vreinterpretq_m128i_s32(vcombine_s32(a32, a33));
+}
+
+// Shuffle packed 8-bit integers in a according to shuffle control mask in the
+// corresponding 8-bit element of b, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8&expand=5146
+FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b)
+{
+#if __aarch64__
+ int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a
+ uint8x16_t idx = vreinterpretq_u8_m128i(b); // input b
+ uint8_t __attribute__((aligned(16)))
+ mask[16] = {0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F};
+ uint8x16_t idx_masked =
+ vandq_u8(idx, vld1q_u8(mask)); // avoid using meaningless bits
+
+ return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked));
+#else
+ uint8_t *tbl = (uint8_t *) &a; // input a
+ uint8_t *idx = (uint8_t *) &b; // input b
+ int32_t r[4];
+
+ r[0] = ((idx[3] & 0x80) ? 0 : tbl[idx[3] % 16]) << 24;
+ r[0] |= ((idx[2] & 0x80) ? 0 : tbl[idx[2] % 16]) << 16;
+ r[0] |= ((idx[1] & 0x80) ? 0 : tbl[idx[1] % 16]) << 8;
+ r[0] |= ((idx[0] & 0x80) ? 0 : tbl[idx[0] % 16]);
+
+ r[1] = ((idx[7] & 0x80) ? 0 : tbl[idx[7] % 16]) << 24;
+ r[1] |= ((idx[6] & 0x80) ? 0 : tbl[idx[6] % 16]) << 16;
+ r[1] |= ((idx[5] & 0x80) ? 0 : tbl[idx[5] % 16]) << 8;
+ r[1] |= ((idx[4] & 0x80) ? 0 : tbl[idx[4] % 16]);
+
+ r[2] = ((idx[11] & 0x80) ? 0 : tbl[idx[11] % 16]) << 24;
+ r[2] |= ((idx[10] & 0x80) ? 0 : tbl[idx[10] % 16]) << 16;
+ r[2] |= ((idx[9] & 0x80) ? 0 : tbl[idx[9] % 16]) << 8;
+ r[2] |= ((idx[8] & 0x80) ? 0 : tbl[idx[8] % 16]);
+
+ r[3] = ((idx[15] & 0x80) ? 0 : tbl[idx[15] % 16]) << 24;
+ r[3] |= ((idx[14] & 0x80) ? 0 : tbl[idx[14] % 16]) << 16;
+ r[3] |= ((idx[13] & 0x80) ? 0 : tbl[idx[13] % 16]) << 8;
+ r[3] |= ((idx[12] & 0x80) ? 0 : tbl[idx[12] % 16]);
+
+ return vld1q_s32(r);
+#endif
+}
+
+
+#if 0 /* C version */
+FORCE_INLINE __m128i _mm_shuffle_epi32_default(__m128i a,
+ __constrange(0, 255) int imm)
+{
+ __m128i ret;
+ ret[0] = a[imm & 0x3];
+ ret[1] = a[(imm >> 2) & 0x3];
+ ret[2] = a[(imm >> 4) & 0x03];
+ ret[3] = a[(imm >> 6) & 0x03];
+ return ret;
+}
+#endif
+#define _mm_shuffle_epi32_default(a, imm) \
+ ({ \
+ int32x4_t ret; \
+ ret = vmovq_n_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) &0x3)); \
+ ret = vsetq_lane_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \
+ ret, 1); \
+ ret = vsetq_lane_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \
+ ret, 2); \
+ ret = vsetq_lane_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \
+ ret, 3); \
+ vreinterpretq_m128i_s32(ret); \
+ })
+
+// FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255)
+// int imm)
+#if defined(__aarch64__)
+#define _mm_shuffle_epi32_splat(a, imm) \
+ ({ \
+ vreinterpretq_m128i_s32( \
+ vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \
+ })
+#else
+#define _mm_shuffle_epi32_splat(a, imm) \
+ ({ \
+ vreinterpretq_m128i_s32( \
+ vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \
+ })
+#endif
+
+// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm.
+// https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx
+// FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, __constrange(0,255) int
+// imm)
+#define _mm_shuffle_epi32(a, imm) \
+ ({ \
+ __m128i ret; \
+ switch (imm) { \
+ case _MM_SHUFFLE(1, 0, 3, 2): \
+ ret = _mm_shuffle_epi_1032((a)); \
+ break; \
+ case _MM_SHUFFLE(2, 3, 0, 1): \
+ ret = _mm_shuffle_epi_2301((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 3, 2, 1): \
+ ret = _mm_shuffle_epi_0321((a)); \
+ break; \
+ case _MM_SHUFFLE(2, 1, 0, 3): \
+ ret = _mm_shuffle_epi_2103((a)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 1, 0): \
+ ret = _mm_shuffle_epi_1010((a)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 0, 1): \
+ ret = _mm_shuffle_epi_1001((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 1, 0, 1): \
+ ret = _mm_shuffle_epi_0101((a)); \
+ break; \
+ case _MM_SHUFFLE(2, 2, 1, 1): \
+ ret = _mm_shuffle_epi_2211((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 1, 2, 2): \
+ ret = _mm_shuffle_epi_0122((a)); \
+ break; \
+ case _MM_SHUFFLE(3, 3, 3, 2): \
+ ret = _mm_shuffle_epi_3332((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 0, 0, 0): \
+ ret = _mm_shuffle_epi32_splat((a), 0); \
+ break; \
+ case _MM_SHUFFLE(1, 1, 1, 1): \
+ ret = _mm_shuffle_epi32_splat((a), 1); \
+ break; \
+ case _MM_SHUFFLE(2, 2, 2, 2): \
+ ret = _mm_shuffle_epi32_splat((a), 2); \
+ break; \
+ case _MM_SHUFFLE(3, 3, 3, 3): \
+ ret = _mm_shuffle_epi32_splat((a), 3); \
+ break; \
+ default: \
+ ret = _mm_shuffle_epi32_default((a), (imm)); \
+ break; \
+ } \
+ ret; \
+ })
+
+// Shuffles the upper 4 signed or unsigned 16 - bit integers in a as specified
+// by imm. https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a,
+// __constrange(0,255) int imm)
+#define _mm_shufflelo_epi16_function(a, imm) \
+ ({ \
+ int16x8_t ret = vreinterpretq_s16_s32(a); \
+ int16x4_t lowBits = vget_low_s16(ret); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) &0x3), ret, 4); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \
+ 5); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \
+ 6); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \
+ 7); \
+ vreinterpretq_s32_s16(ret); \
+ })
+
+// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, __constrange(0,255) int
+// imm)
+#define _mm_shufflelo_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm))
+
+// Shuffles the upper 4 signed or unsigned 16 - bit integers in a as specified
+// by imm. https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a,
+// __constrange(0,255) int imm)
+#define _mm_shufflehi_epi16_function(a, imm) \
+ ({ \
+ int16x8_t ret = vreinterpretq_s16_s32(a); \
+ int16x4_t highBits = vget_high_s16(ret); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) &0x3), ret, 4); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \
+ 5); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \
+ 6); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \
+ 7); \
+ vreinterpretq_s32_s16(ret); \
+ })
+
+// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, __constrange(0,255) int
+// imm)
+#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm))
+
+// Shifts the 4 signed 32-bit integers in a right by count bits while shifting
+// in the sign bit.
+//
+// r0 := a0 >> count
+// r1 := a1 >> count
+// r2 := a2 >> count
+// r3 := a3 >> count immediate
+FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, int count)
+{
+ return vshlq_s32(a, vdupq_n_s32(-count));
+}
+
+// Shifts the 8 signed 16-bit integers in a right by count bits while shifting
+// in the sign bit.
+//
+// r0 := a0 >> count
+// r1 := a1 >> count
+// ...
+// r7 := a7 >> count
+FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int count)
+{
+ return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count));
+}
+
+// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+// ...
+// r7 := a7 << count
+//
+// https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx
+#define _mm_slli_epi16(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 31) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s16( \
+ vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while
+// shifting in zeros. :
+// https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx
+// FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_slli_epi32(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 31) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s32( \
+ vshlq_n_s32(vreinterpretq_s32_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and
+// store the results in dst.
+#define _mm_slli_epi64(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 63) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s64( \
+ vshlq_n_s64(vreinterpretq_s64_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 8 signed or unsigned 16-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+// ...
+// r7 := srl(a7, count)
+//
+// https://msdn.microsoft.com/en-us/library/6tcwd38t(v=vs.90).aspx
+#define _mm_srli_epi16(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 31) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_u16( \
+ vshrq_n_u16(vreinterpretq_u16_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 4 signed or unsigned 32-bit integers in a right by count bits
+// while shifting in zeros.
+// https://msdn.microsoft.com/en-us/library/w486zcfa(v=vs.100).aspx FORCE_INLINE
+// __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_srli_epi32(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 31) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_u32( \
+ vshrq_n_u32(vreinterpretq_u32_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+#define _mm_srli_epi64(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 63) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_u64( \
+ vshrq_n_u64(vreinterpretq_u64_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 4 signed 32 - bit integers in a right by count bits while shifting
+// in the sign bit.
+// https://msdn.microsoft.com/en-us/library/z1939387(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_srai_epi32(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 31) { \
+ ret = vreinterpretq_m128i_s32( \
+ vshrq_n_s32(vreinterpretq_s32_m128i(a), 16)); \
+ ret = vreinterpretq_m128i_s32( \
+ vshrq_n_s32(vreinterpretq_s32_m128i(ret), 16)); \
+ } else { \
+ ret = vreinterpretq_m128i_s32( \
+ vshrq_n_s32(vreinterpretq_s32_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 128 - bit value in a right by imm bytes while shifting in
+// zeros.imm must be an immediate.
+//
+// r := srl(a, imm*8)
+//
+// https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx
+// FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm)
+#define _mm_srli_si128(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 15) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s8( \
+ vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm
+// must be an immediate.
+//
+// r := a << (imm * 8)
+//
+// https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm)
+#define _mm_slli_si128(a, imm) \
+ ({ \
+ __m128i ret; \
+ if ((imm) <= 0) { \
+ ret = a; \
+ } else if ((imm) > 15) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s8(vextq_s8( \
+ vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \
+ } \
+ ret; \
+ })
+
+// NEON does not provide a version of this function, here is an article about
+// some ways to repro the results.
+// http://stackoverflow.com/questions/11870910/sse-mm-movemask-epi8-equivalent-method-for-arm-neon
+// Creates a 16-bit mask from the most significant bits of the 16 signed or
+// unsigned 8-bit integers in a and zero extends the upper bits.
+// https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_epi8(__m128i _a)
+{
+ uint8x16_t input = vreinterpretq_u8_m128i(_a);
+ static const int8_t __attribute__((aligned(16)))
+ xr[8] = {-7, -6, -5, -4, -3, -2, -1, 0};
+ uint8x8_t mask_and = vdup_n_u8(0x80);
+ int8x8_t mask_shift = vld1_s8(xr);
+
+ uint8x8_t lo = vget_low_u8(input);
+ uint8x8_t hi = vget_high_u8(input);
+
+ lo = vand_u8(lo, mask_and);
+ lo = vshl_u8(lo, mask_shift);
+
+ hi = vand_u8(hi, mask_and);
+ hi = vshl_u8(hi, mask_shift);
+
+ lo = vpadd_u8(lo, lo);
+ lo = vpadd_u8(lo, lo);
+ lo = vpadd_u8(lo, lo);
+
+ hi = vpadd_u8(hi, hi);
+ hi = vpadd_u8(hi, hi);
+ hi = vpadd_u8(hi, hi);
+
+ return ((hi[0] << 8) | (lo[0] & 0xFF));
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and
+// mask, and return 1 if the result is zero, otherwise return 0.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros&expand=5871
+FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask)
+{
+ int64x2_t a_and_mask =
+ vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask));
+ return (vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)) ? 0
+ : 1;
+}
+
+// ******************************************
+// Math operations
+// ******************************************
+
+// Subtracts the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 - b0
+// r1 := a1 - b1
+// r2 := a2 - b2
+// r3 := a3 - b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a,
+// and store the results in dst.
+// r0 := a0 - b0
+// r1 := a1 - b1
+FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s64(
+ vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+}
+
+// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or
+// unsigned 32-bit integers of a.
+//
+// r0 := a0 - b0
+// r1 := a1 - b1
+// r2 := a2 - b2
+// r3 := a3 - b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128_f32(
+ vsubq_s32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit
+// integers of a and saturates..
+// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit
+// integers of a and saturates.
+//
+// r0 := UnsignedSaturate(a0 - b0)
+// r1 := UnsignedSaturate(a1 - b1)
+// ...
+// r15 := UnsignedSaturate(a15 - b15)
+//
+// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers
+// of a and saturates.
+//
+// r0 := SignedSaturate(a0 - b0)
+// r1 := SignedSaturate(a1 - b1)
+// ...
+// r7 := SignedSaturate(a7 - b7)
+FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+FORCE_INLINE __m128i _mm_sign_epi32(__m128i a, __m128i b)
+{
+ __m128i zer0 = vdupq_n_s32(0);
+ __m128i ltMask = vreinterpretq_s32_u32(vcltq_s32(b, zer0));
+ __m128i gtMask = vreinterpretq_s32_u32(vcgtq_s32(b, zer0));
+ __m128i neg = vnegq_s32(a);
+ __m128i tmp = vandq_s32(a, gtMask);
+ return vorrq_s32(tmp, vandq_s32(neg, ltMask));
+}
+
+FORCE_INLINE __m128i _mm_sign_epi16(__m128i a, __m128i b)
+{
+ int16x8_t zer0 = vdupq_n_s16(0);
+ int16x8_t ltMask =
+ vreinterpretq_s16_u16(vcltq_s16(vreinterpretq_s16_s32(b), zer0));
+ int16x8_t gtMask =
+ vreinterpretq_s16_u16(vcgtq_s16(vreinterpretq_s16_s32(b), zer0));
+ int16x8_t neg = vnegq_s16(vreinterpretq_s16_s32(a));
+ int16x8_t tmp = vandq_s16(vreinterpretq_s16_s32(a), gtMask);
+ return vreinterpretq_s32_s16(vorrq_s16(tmp, vandq_s16(neg, ltMask)));
+}
+
+// Adds the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 + b0
+// r1 := a1 + b1
+// r2 := a2 + b2
+// r3 := a3 + b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// adds the scalar single-precision floating point values of a and b.
+// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b)
+{
+ float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0);
+ float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0);
+ // the upper values in the result must be the remnants of .
+ return vreinterpretq_m128_f32(vaddq_f32(a, value));
+}
+
+// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or
+// unsigned 32-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b)
+{
+ return vreinterpretq_s32_s64(
+ vaddq_s64(vreinterpretq_s64_s32(a), vreinterpretq_s64_s32(b)));
+}
+
+// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or
+// unsigned 32-bit integers in b.
+//
+// r0 := a0 + b0
+// r1 := a1 + b1
+// r2 := a2 + b2
+// r3 := a3 + b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or
+// unsigned 16-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or
+// unsigned 8-bit integers in b.
+// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90)
+FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b
+// and saturates.
+//
+// r0 := SignedSaturate(a0 + b0)
+// r1 := SignedSaturate(a1 + b1)
+// ...
+// r7 := SignedSaturate(a7 + b7)
+//
+// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in
+// b and saturates..
+// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or
+// unsigned 16-bit integers from b.
+//
+// r0 := (a0 * b0)[15:0]
+// r1 := (a1 * b1)[15:0]
+// ...
+// r7 := (a7 * b7)[15:0]
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or
+// unsigned 32-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Multiplies the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 * b0
+// r1 := a1 * b1
+// r2 := a2 * b2
+// r3 := a3 * b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Multiply the low unsigned 32-bit integers from each packed 64-bit element in
+// a and b, and store the unsigned 64-bit results in dst.
+//
+// r0 := (uint32_t*)a0 * (uint32_t*)b0
+// r1 := (uint32_t*)a2 * (uint32_t*)b2
+#if 1 /* C version */
+FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b)
+{
+ __m128i d;
+ vreinterpretq_nth_u64_m128i(d, 0) =
+ (uint64_t)(vreinterpretq_nth_u32_m128i(a, 0)) *
+ (uint64_t)(vreinterpretq_nth_u32_m128i(b, 0));
+ vreinterpretq_nth_u64_m128i(d, 1) =
+ (uint64_t)(vreinterpretq_nth_u32_m128i(a, 2)) *
+ (uint64_t)(vreinterpretq_nth_u32_m128i(b, 2));
+ return d;
+}
+#else /* Neon version */
+// Default to c version until casting can be sorted out on neon version.
+// (Otherwise requires compiling with -fpermissive) Also unclear whether neon
+// version actually performs better.
+FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b)
+{
+ // shuffle: 0, 1, 2, 3 -> 0, 2, 1, 3 */
+ __m128i const a_shuf =
+ *(__m128i *) (&vzip_u32(vget_low_u32(vreinterpretq_u32_m128i(a)),
+ vget_high_u32(vreinterpretq_u32_m128i(a))));
+ __m128i const b_shuf =
+ *(__m128i *) (&vzip_u32(vget_low_u32(vreinterpretq_u32_m128i(b)),
+ vget_high_u32(vreinterpretq_u32_m128i(b))));
+
+ // Multiply low word (32 bit) against low word (32 bit) and high word (32
+ // bit) against high word (32 bit). Pack both results (64 bit) into 128 bit
+ // register and return result.
+ return vreinterpretq_m128i_u64(
+ vmull_u32(vget_low_u32(vreinterpretq_u32_m128i(a_shuf)),
+ vget_low_u32(vreinterpretq_u32_m128i(b_shuf))));
+}
+#endif
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit
+// integers from b.
+//
+// r0 := (a0 * b0) + (a1 * b1)
+// r1 := (a2 * b2) + (a3 * b3)
+// r2 := (a4 * b4) + (a5 * b5)
+// r3 := (a6 * b6) + (a7 * b7)
+// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b)
+{
+ int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)),
+ vget_low_s16(vreinterpretq_s16_m128i(b)));
+ int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)),
+ vget_high_s16(vreinterpretq_s16_m128i(b)));
+
+ int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low));
+ int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high));
+
+ return vreinterpretq_s32_m128i(vcombine_s32(low_sum, high_sum));
+}
+
+// Computes the absolute difference of the 16 unsigned 8-bit integers from a
+// and the 16 unsigned 8-bit integers from b.
+//
+// Return Value
+// Sums the upper 8 differences and lower 8 differences and packs the
+// resulting 2 unsigned 16-bit integers into the upper and lower 64-bit
+// elements.
+//
+// r0 := abs(a0 - b0) + abs(a1 - b1) +...+ abs(a7 - b7)
+// r1 := 0x0
+// r2 := 0x0
+// r3 := 0x0
+// r4 := abs(a8 - b8) + abs(a9 - b9) +...+ abs(a15 - b15)
+// r5 := 0x0
+// r6 := 0x0
+// r7 := 0x0
+FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b)
+{
+ uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b));
+ uint16_t r0 = t[0] + t[1] + t[2] + t[3];
+ uint16_t r4 = t[4] + t[5] + t[6] + t[7];
+ uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0);
+ return (__m128i) vsetq_lane_u16(r4, r, 4);
+}
+
+// Divides the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 / b0
+// r1 := a1 / b1
+// r2 := a2 / b2
+// r3 := a3 / b3
+//
+// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b)
+{
+ float32x4_t recip0 = vrecpeq_f32(vreinterpretq_f32_m128(b));
+ float32x4_t recip1 =
+ vmulq_f32(recip0, vrecpsq_f32(recip0, vreinterpretq_f32_m128(b)));
+ return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip1));
+}
+
+// Divides the scalar single-precision floating point value of a by b.
+// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b)
+{
+ float32_t value =
+ vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// This version does additional iterations to improve accuracy. Between 1 and 4
+// recommended. Computes the approximations of reciprocals of the four
+// single-precision, floating-point values of a.
+// https://msdn.microsoft.com/en-us/library/vstudio/796k1tty(v=vs.100).aspx
+FORCE_INLINE __m128 recipq_newton(__m128 in, int n)
+{
+ int i;
+ float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in));
+ for (i = 0; i < n; ++i) {
+ recip =
+ vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));
+ }
+ return vreinterpretq_m128_f32(recip);
+}
+
+// Computes the approximations of reciprocals of the four single-precision,
+// floating-point values of a.
+// https://msdn.microsoft.com/en-us/library/vstudio/796k1tty(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_rcp_ps(__m128 in)
+{
+ float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in));
+ recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));
+ return vreinterpretq_m128_f32(recip);
+}
+
+// Computes the approximations of square roots of the four single-precision,
+// floating-point values of a. First computes reciprocal square roots and then
+// reciprocals of the four values.
+//
+// r0 := sqrt(a0)
+// r1 := sqrt(a1)
+// r2 := sqrt(a2)
+// r3 := sqrt(a3)
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in)
+{
+ float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+ float32x4_t sq = vrecpeq_f32(recipsq);
+ // ??? use step versions of both sqrt and recip for better accuracy?
+ return vreinterpretq_m128_f32(sq);
+}
+
+// Computes the approximation of the square root of the scalar single-precision
+// floating point value of in.
+// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in)
+{
+ float32_t value =
+ vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0));
+}
+
+// Computes the approximations of the reciprocal square roots of the four
+// single-precision floating point values of in.
+// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in)
+{
+ return vreinterpretq_m128_f32(vrsqrteq_f32(vreinterpretq_f32_m128(in)));
+}
+
+// Computes the maximums of the four single-precision, floating-point values of
+// a and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Computes the minima of the four single-precision, floating-point values of a
+// and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Computes the maximum of the two lower scalar single-precision floating point
+// values of a and b.
+// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b)
+{
+ float32_t value = vgetq_lane_f32(
+ vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Computes the minimum of the two lower scalar single-precision floating point
+// values of a and b.
+// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b)
+{
+ float32_t value = vgetq_lane_f32(
+ vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the
+// 16 unsigned 8-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the
+// 16 unsigned 8-bit integers from b.
+// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx
+FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8
+// signed 16-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8
+// signed 16-bit integers from b.
+// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// epi versions of min/max
+// Computes the pariwise maximums of the four signed 32-bit integer values of a
+// and b.
+//
+// A 128-bit parameter that can be defined with the following equations:
+// r0 := (a0 > b0) ? a0 : b0
+// r1 := (a1 > b1) ? a1 : b1
+// r2 := (a2 > b2) ? a2 : b2
+// r3 := (a3 > b3) ? a3 : b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the pariwise minima of the four signed 32-bit integer values of a
+// and b.
+//
+// A 128-bit parameter that can be defined with the following equations:
+// r0 := (a0 < b0) ? a0 : b0
+// r1 := (a1 < b1) ? a1 : b1
+// r2 := (a2 < b2) ? a2 : b2
+// r3 := (a3 < b3) ? a3 : b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit
+// integers from b.
+//
+// r0 := (a0 * b0)[31:16]
+// r1 := (a1 * b1)[31:16]
+// ...
+// r7 := (a7 * b7)[31:16]
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b)
+{
+ /* FIXME: issue with large values because of result saturation */
+ // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a),
+ // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return
+ // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1));
+ int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b));
+ int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */
+ int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b));
+ int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */
+ uint16x8x2_t r =
+ vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654));
+ return vreinterpretq_m128i_u16(r.val[1]);
+}
+
+FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b)
+{
+ const uint32x4_t lo = vmull_u16(vget_low_u16((uint16x8_t)a), vget_low_u16((uint16x8_t)b));
+ const uint32x4_t hi = vmull_u16(vget_high_u16((uint16x8_t)a), vget_high_u16((uint16x8_t)b));
+
+ return (__m128i)vcombine_u16(vshrn_n_u32(lo, 16), vshrn_n_u32(hi, 16));
+}
+
+// Computes pairwise add of each argument as single-precision, floating-point
+// values a and b.
+// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx
+FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(vpaddq_f32(
+ vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); // AArch64
+#else
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32)));
+#endif
+}
+
+// ******************************************
+// Compare operations
+// ******************************************
+
+// Compares for less than
+// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for greater than.
+//
+// r0 := (a0 > b0) ? 0xffffffff : 0x0
+// r1 := (a1 > b1) ? 0xffffffff : 0x0
+// r2 := (a2 > b2) ? 0xffffffff : 0x0
+// r3 := (a3 > b3) ? 0xffffffff : 0x0
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for greater than or equal.
+// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for less than or equal.
+//
+// r0 := (a0 <= b0) ? 0xffffffff : 0x0
+// r1 := (a1 <= b1) ? 0xffffffff : 0x0
+// r2 := (a2 <= b2) ? 0xffffffff : 0x0
+// r3 := (a3 <= b3) ? 0xffffffff : 0x0
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for equality.
+// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or
+// unsigned 8-bit integers in b for equality.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or
+// unsigned 16-bit integers in b for equality.
+// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compare packed 32-bit integers in a and b for equality, and store the results
+// in dst
+FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers
+// in b for lesser than.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers
+// in b for greater than.
+//
+// r0 := (a0 > b0) ? 0xff : 0x0
+// r1 := (a1 > b1) ? 0xff : 0x0
+// ...
+// r15 := (a15 > b15) ? 0xff : 0x0
+//
+// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers
+// in b for greater than.
+//
+// r0 := (a0 > b0) ? 0xffff : 0x0
+// r1 := (a1 > b1) ? 0xffff : 0x0
+// ...
+// r7 := (a7 > b7) ? 0xffff : 0x0
+//
+// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers
+// in b for less than.
+// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers
+// in b for greater than.
+// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the four 32-bit floats in a and b to check if any values are NaN.
+// Ordered compare between each value returns true for "orderable" and false for
+// "not orderable" (NaN).
+// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see
+// also:
+// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean
+// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics
+FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b)
+{
+ // Note: NEON does not have ordered compare builtin
+ // Need to compare a eq a and b eq b to check for NaN
+ // Do AND of results to get final
+ uint32x4_t ceqaa =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t ceqbb =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb));
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a less than operation. :
+// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important
+// note!! The documentation on MSDN is incorrect! If either of the values is a
+// NAN the docs say you will get a one, but in fact, it will return a zero!!
+FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b)
+{
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_lt_b =
+ vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_lt_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a greater than operation. :
+// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx
+FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_gt_b =
+ vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a less than or equal operation. :
+// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx
+FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_le_b =
+ vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_le_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a greater than or equal operation. :
+// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx
+FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_ge_b =
+ vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using an equality operation. :
+// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx
+FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_eq_b =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_eq_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using an inequality operation. :
+// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx
+FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b)
+{
+ // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan));
+ uint32x4_t a_neq_b = vmvnq_u32(
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+ return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_neq_b), 0) != 0) ? 1 : 0;
+}
+
+// according to the documentation, these intrinsics behave the same as the
+// non-'u' versions. We'll just alias them here.
+#define _mm_ucomilt_ss _mm_comilt_ss
+#define _mm_ucomile_ss _mm_comile_ss
+#define _mm_ucomigt_ss _mm_comigt_ss
+#define _mm_ucomige_ss _mm_comige_ss
+#define _mm_ucomieq_ss _mm_comieq_ss
+#define _mm_ucomineq_ss _mm_comineq_ss
+
+// ******************************************
+// Conversions
+// ******************************************
+
+// Converts the four single-precision, floating-point values of a to signed
+// 32-bit integer values using truncate.
+// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a)
+{
+ return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)));
+}
+
+// Converts the four signed 32-bit integer values of a to single-precision,
+// floating-point values
+// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a)
+{
+ return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a)));
+}
+
+// Converts the four unsigned 8-bit integers in the lower 32 bits to four
+// unsigned 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx
+FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a)
+{
+ uint8x16_t u8x16 = vreinterpretq_u8_s32(a); /* xxxx xxxx xxxx DCBA */
+ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */
+ return vreinterpretq_s32_u32(u32x4);
+}
+
+// Converts the four signed 16-bit integers in the lower 64 bits to four signed
+// 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb514079%28v=vs.100%29.aspx
+FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a)
+{
+ return vreinterpretq_m128i_s32(
+ vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a))));
+}
+
+// Converts the four single-precision, floating-point values of a to signed
+// 32-bit integer values.
+//
+// r0 := (int) a0
+// r1 := (int) a1
+// r2 := (int) a2
+// r3 := (int) a3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx
+// *NOTE*. The default rounding mode on SSE is 'round to even', which ArmV7-A
+// does not support! It is supported on ARMv8-A however.
+FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a)
+{
+#if defined(__aarch64__)
+ return vcvtnq_s32_f32(a);
+#else
+ uint32x4_t signmask = vdupq_n_u32(0x80000000);
+ float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a),
+ vdupq_n_f32(0.5f)); /* +/- 0.5 */
+ int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32(
+ vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/
+ int32x4_t r_trunc =
+ vcvtq_s32_f32(vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */
+ int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32(
+ vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */
+ int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone),
+ vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */
+ float32x4_t delta = vsubq_f32(
+ vreinterpretq_f32_m128(a),
+ vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */
+ uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */
+ return vreinterpretq_m128i_s32(vbslq_s32(is_delta_half, r_even, r_normal));
+#endif
+}
+
+// Moves the least significant 32 bits of a to a 32-bit integer.
+// https://msdn.microsoft.com/en-us/library/5z7a9642%28v=vs.90%29.aspx
+FORCE_INLINE int _mm_cvtsi128_si32(__m128i a)
+{
+ return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0);
+}
+
+// Extracts the low order 64-bit integer from the parameter.
+// https://msdn.microsoft.com/en-us/library/bb531384(v=vs.120).aspx
+FORCE_INLINE uint64_t _mm_cvtsi128_si64(__m128i a)
+{
+ return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0);
+}
+
+// Moves 32-bit integer a to the least significant 32 bits of an __m128 object,
+// zero extending the upper bits.
+//
+// r0 := a
+// r1 := 0x0
+// r2 := 0x0
+// r3 := 0x0
+//
+// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_cvtsi32_si128(int a)
+{
+ return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0));
+}
+
+// Applies a type cast to reinterpret four 32-bit floating point values passed
+// in as a 128-bit parameter as packed 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb514099.aspx
+FORCE_INLINE __m128i _mm_castps_si128(__m128 a)
+{
+ return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a));
+}
+
+// Applies a type cast to reinterpret four 32-bit integers passed in as a
+// 128-bit parameter as packed 32-bit floating point values.
+// https://msdn.microsoft.com/en-us/library/bb514029.aspx
+FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a)
+{
+ return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a));
+}
+
+// Loads 128-bit value. :
+// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx
+FORCE_INLINE __m128i _mm_load_si128(const __m128i *p)
+{
+ return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));
+}
+
+// Loads 128-bit value. :
+// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p)
+{
+ return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));
+}
+
+// ******************************************
+// Miscellaneous Operations
+// ******************************************
+
+// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and
+// saturates.
+// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)),
+ vqmovn_s16(vreinterpretq_s16_m128i(b))));
+}
+
+// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned
+// integers and saturates.
+//
+// r0 := UnsignedSaturate(a0)
+// r1 := UnsignedSaturate(a1)
+// ...
+// r7 := UnsignedSaturate(a7)
+// r8 := UnsignedSaturate(b0)
+// r9 := UnsignedSaturate(b1)
+// ...
+// r15 := UnsignedSaturate(b7)
+//
+// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)),
+ vqmovun_s16(vreinterpretq_s16_m128i(b))));
+}
+
+// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers
+// and saturates.
+//
+// r0 := SignedSaturate(a0)
+// r1 := SignedSaturate(a1)
+// r2 := SignedSaturate(a2)
+// r3 := SignedSaturate(a3)
+// r4 := SignedSaturate(b0)
+// r5 := SignedSaturate(b1)
+// r6 := SignedSaturate(b2)
+// r7 := SignedSaturate(b3)
+//
+// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)),
+ vqmovn_s32(vreinterpretq_s32_m128i(b))));
+}
+
+// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower
+// 8 signed or unsigned 8-bit integers in b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+// ...
+// r14 := a7
+// r15 := b7
+//
+// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b)
+{
+ int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a)));
+ int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b)));
+ int8x8x2_t result = vzip_s8(a1, b1);
+ return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));
+}
+
+// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the
+// lower 4 signed or unsigned 16-bit integers in b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+// r4 := a2
+// r5 := b2
+// r6 := a3
+// r7 := b3
+//
+// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b)
+{
+ int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b));
+ int16x4x2_t result = vzip_s16(a1, b1);
+ return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));
+}
+
+// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the
+// lower 2 signed or unsigned 32 - bit integers in b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+//
+// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b)
+{
+ int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b));
+ int32x2x2_t result = vzip_s32(a1, b1);
+ return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));
+}
+
+FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)
+{
+ int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a));
+ int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b));
+ return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l));
+}
+
+// Selects and interleaves the lower two single-precision, floating-point values
+// from a and b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+//
+// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b)
+{
+ float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b));
+ float32x2x2_t result = vzip_f32(a1, b1);
+ return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));
+}
+
+// Selects and interleaves the upper two single-precision, floating-point values
+// from a and b.
+//
+// r0 := a2
+// r1 := b2
+// r2 := a3
+// r3 := b3
+//
+// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b)
+{
+ float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b));
+ float32x2x2_t result = vzip_f32(a1, b1);
+ return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));
+}
+
+// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper
+// 8 signed or unsigned 8-bit integers in b.
+//
+// r0 := a8
+// r1 := b8
+// r2 := a9
+// r3 := b9
+// ...
+// r14 := a15
+// r15 := b15
+//
+// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b)
+{
+ int8x8_t a1 =
+ vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a)));
+ int8x8_t b1 =
+ vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b)));
+ int8x8x2_t result = vzip_s8(a1, b1);
+ return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));
+}
+
+// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the
+// upper 4 signed or unsigned 16-bit integers in b.
+//
+// r0 := a4
+// r1 := b4
+// r2 := a5
+// r3 := b5
+// r4 := a6
+// r5 := b6
+// r6 := a7
+// r7 := b7
+//
+// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b)
+{
+ int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b));
+ int16x4x2_t result = vzip_s16(a1, b1);
+ return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));
+}
+
+// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the
+// upper 2 signed or unsigned 32-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b)
+{
+ int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b));
+ int32x2x2_t result = vzip_s32(a1, b1);
+ return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));
+}
+
+// Interleaves the upper signed or unsigned 64-bit integer in a with the
+// upper signed or unsigned 64-bit integer in b.
+//
+// r0 := a1
+// r1 := b1
+FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)
+{
+ int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a));
+ int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b));
+ return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h));
+}
+
+
+
+// Extracts the selected signed or unsigned 16-bit integer from a and zero
+// extends. https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx
+// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm)
+#define _mm_extract_epi16(a, imm) \
+ ({ (vgetq_lane_s16(vreinterpretq_s16_m128i(a), (imm)) & 0x0000ffffUL); })
+
+// Inserts the least significant 16 bits of b into the selected 16-bit integer
+// of a. https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx
+// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, const int b,
+// __constrange(0,8) int imm)
+#define _mm_insert_epi16(a, b, imm) \
+ ({ \
+ vreinterpretq_m128i_s16( \
+ vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \
+ })
+
+// ******************************************
+// Crypto Extensions
+// ******************************************
+#if !defined(__ARM_FEATURE_CRYPTO) && defined(__aarch64__)
+// In the absence of crypto extensions, implement aesenc using regular neon
+// intrinsics instead. See:
+// http://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/
+// http://www.workofard.com/2017/07/ghash-for-low-end-cores/ and
+// https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52
+// for more information Reproduced with permission of the author.
+FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey)
+{
+ static const uint8_t crypto_aes_sbox[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
+ 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
+ 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
+ 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
+ 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
+ 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
+ 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
+ 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
+ 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
+ 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
+ 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
+ 0xb0, 0x54, 0xbb, 0x16};
+ static const uint8_t shift_rows[] = {0x0, 0x5, 0xa, 0xf, 0x4, 0x9,
+ 0xe, 0x3, 0x8, 0xd, 0x2, 0x7,
+ 0xc, 0x1, 0x6, 0xb};
+ static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4,
+ 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc};
+
+ uint8x16_t v;
+ uint8x16_t w = vreinterpretq_u8_m128i(EncBlock);
+
+ // shift rows
+ w = vqtbl1q_u8(w, vld1q_u8(shift_rows));
+
+ // sub bytes
+ v = vqtbl4q_u8(vld1q_u8_x4(crypto_aes_sbox), w);
+ v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0x40), w - 0x40);
+ v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0x80), w - 0x80);
+ v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0xc0), w - 0xc0);
+
+ // mix columns
+ w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b);
+ w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v);
+ w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8));
+
+ // add round key
+ return vreinterpretq_m128i_u8(w) ^ RoundKey;
+}
+#elif defined(__ARM_FEATURE_CRYPTO)
+// Implements equivalent of 'aesenc' by combining AESE (with an empty key) and
+// AESMC and then manually applying the real key as an xor operation This
+// unfortunately means an additional xor op; the compiler should be able to
+// optimise this away for repeated calls however See
+// https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a
+// for more details.
+inline __m128i _mm_aesenc_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_s32_u8(
+ vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_s32(a), uint8x16_t{})) ^
+ vreinterpretq_u8_s32(b));
+}
+#endif
+
+// ******************************************
+// Streaming Extensions
+// ******************************************
+
+// Guarantees that every preceding store is globally visible before any
+// subsequent store.
+// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_sfence(void)
+{
+ __sync_synchronize();
+}
+
+// Stores the data in a to the address p without polluting the caches. If the
+// cache line containing address p is already in the cache, the cache will be
+// updated.Address p must be 16 - byte aligned.
+// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a)
+{
+ vst1q_s32((int32_t *) p, a);
+}
+
+// Cache line containing p is flushed and invalidated from all caches in the
+// coherency domain. :
+// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx
+FORCE_INLINE void _mm_clflush(void const *p)
+{
+ // no corollary for Neon?
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma pop_macro("ALIGN_STRUCT")
+#pragma pop_macro("FORCE_INLINE")
+#endif
+
+#endif
diff --git a/parallel-rsp/arch/simd/rsp/clamp.h b/parallel-rsp/arch/simd/rsp/clamp.h
new file mode 100644
index 0000000..07cb799
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/clamp.h
@@ -0,0 +1,45 @@
+//
+// arch/x86_64/rsp/clamp.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_sclamp_acc_tomd(__m128i acc_md, __m128i acc_hi)
+{
+ __m128i l = _mm_unpacklo_epi16(acc_md, acc_hi);
+ __m128i h = _mm_unpackhi_epi16(acc_md, acc_hi);
+ return _mm_packs_epi32(l, h);
+}
+
+static inline __m128i rsp_uclamp_acc(__m128i val, __m128i acc_md, __m128i acc_hi, __m128i zero)
+{
+ __m128i clamp_mask, clamped_val;
+ __m128i hi_sign_check, md_sign_check;
+ __m128i md_negative, hi_negative;
+ __m128i tmp;
+
+ hi_negative = _mm_srai_epi16(acc_hi, 15);
+ md_negative = _mm_srai_epi16(acc_md, 15);
+
+ // We don't have to clamp if the HI part of the
+ // accumulator is sign-extended down to the MD part.
+ hi_sign_check = _mm_cmpeq_epi16(hi_negative, acc_hi);
+ md_sign_check = _mm_cmpeq_epi16(hi_negative, md_negative);
+ clamp_mask = _mm_and_si128(md_sign_check, hi_sign_check);
+
+ // Generate the value in the event we need to clamp.
+ // * hi_negative, mid_sign => xxxx
+ // * hi_negative, !mid_sign => 0000
+ // * !hi_negative, mid_sign => FFFF
+ // * !hi_negative, !mid_sign => xxxx
+ clamped_val = _mm_cmpeq_epi16(hi_negative, zero);
+
+#ifndef __SSE4_1__
+ tmp = _mm_and_si128(clamp_mask, val);
+ val = _mm_andnot_si128(clamp_mask, clamped_val);
+ return _mm_or_si128(val, tmp);
+#else
+ return _mm_blendv_epi8(clamped_val, val, clamp_mask);
+#endif
+}
diff --git a/parallel-rsp/arch/simd/rsp/rsp_common.h b/parallel-rsp/arch/simd/rsp/rsp_common.h
new file mode 100644
index 0000000..d190ba2
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/rsp_common.h
@@ -0,0 +1,158 @@
+//
+// arch/x86_64/rsp/rsp.h
+//
+// Extern declarations for host RSP functions.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __arch_rsp_h__
+#define __arch_rsp_h__
+
+#ifdef __ARM_NEON
+#define __SSSE3__
+#include "SSE2NEON.h"
+#elif defined(__SSE4_2__)
+#include
+#elif defined(__SSE4_1__)
+#include
+#elif defined(__SSSE3__)
+#include
+#elif defined(__SSE3__)
+#include
+#else
+#include
+#endif
+
+#include
+
+typedef __m128i rsp_vect_t;
+
+namespace RSP
+{
+struct CPUState;
+}
+
+// Loads and shuffles a 16x8 vector according to element.
+#ifdef __SSSE3__
+extern const uint16_t shuffle_keys[16][8];
+
+static inline __m128i rsp_vect_load_and_shuffle_operand(const uint16_t *src, unsigned element)
+{
+ __m128i operand = _mm_load_si128((__m128i *)src);
+ __m128i key = _mm_load_si128((__m128i *)shuffle_keys[element]);
+
+ return _mm_shuffle_epi8(operand, key);
+}
+#else
+__m128i rsp_vect_load_and_shuffle_operand(const uint16_t *src, unsigned element);
+#endif
+
+// Loads a vector without shuffling its elements.
+static inline __m128i rsp_vect_load_unshuffled_operand(const uint16_t *src)
+{
+ return _mm_load_si128((__m128i *)src);
+}
+
+// Writes an operand back to memory.
+static inline void rsp_vect_write_operand(uint16_t *dest, __m128i src)
+{
+ _mm_store_si128((__m128i *)dest, src);
+}
+
+static inline __m128i read_acc_lo(const uint16_t *acc)
+{
+ return rsp_vect_load_unshuffled_operand(acc + 16);
+}
+static inline __m128i read_acc_md(const uint16_t *acc)
+{
+ return rsp_vect_load_unshuffled_operand(acc + 8);
+}
+static inline __m128i read_acc_hi(const uint16_t *acc)
+{
+ return rsp_vect_load_unshuffled_operand(acc);
+}
+static inline __m128i read_vcc_lo(const uint16_t *vcc)
+{
+ return rsp_vect_load_unshuffled_operand(vcc + 8);
+}
+static inline __m128i read_vcc_hi(const uint16_t *vcc)
+{
+ return rsp_vect_load_unshuffled_operand(vcc);
+}
+static inline __m128i read_vco_lo(const uint16_t *vco)
+{
+ return rsp_vect_load_unshuffled_operand(vco + 8);
+}
+static inline __m128i read_vco_hi(const uint16_t *vco)
+{
+ return rsp_vect_load_unshuffled_operand(vco);
+}
+static inline __m128i read_vce(const uint16_t *vce)
+{
+ return rsp_vect_load_unshuffled_operand(vce + 8);
+}
+static inline void write_acc_lo(uint16_t *acc, __m128i acc_lo)
+{
+ rsp_vect_write_operand(acc + 16, acc_lo);
+}
+static inline void write_acc_md(uint16_t *acc, __m128i acc_md)
+{
+ rsp_vect_write_operand(acc + 8, acc_md);
+}
+static inline void write_acc_hi(uint16_t *acc, __m128i acc_hi)
+{
+ rsp_vect_write_operand(acc, acc_hi);
+}
+static inline void write_vcc_lo(uint16_t *vcc, __m128i vcc_lo)
+{
+ rsp_vect_write_operand(vcc + 8, vcc_lo);
+}
+static inline void write_vcc_hi(uint16_t *vcc, __m128i vcc_hi)
+{
+ rsp_vect_write_operand(vcc, vcc_hi);
+}
+static inline void write_vco_lo(uint16_t *vco, __m128i vco_lo)
+{
+ rsp_vect_write_operand(vco + 8, vco_lo);
+}
+static inline void write_vco_hi(uint16_t *vco, __m128i vco_hi)
+{
+ rsp_vect_write_operand(vco, vco_hi);
+}
+static inline void write_vce(uint16_t *vce, __m128i vce_r)
+{
+ rsp_vect_write_operand(vce + 8, vce_r);
+}
+
+// Returns scalar bitmasks for VCO/VCC/VCE.
+static inline int16_t rsp_get_flags(const uint16_t *flags)
+{
+ return (int16_t)_mm_movemask_epi8(
+ _mm_packs_epi16(_mm_load_si128((__m128i *)(flags + 8)), _mm_load_si128((__m128i *)(flags + 0))));
+}
+
+void rsp_set_flags(uint16_t *flags, uint16_t rt);
+
+// Zeroes out a vector register.
+static inline __m128i rsp_vzero(void)
+{
+ return _mm_setzero_si128();
+}
+
+extern const uint16_t vdiv_mask_table[8][8];
+
+#define HES(x) ((x) ^ 2)
+#define BES(x) ((x) ^ 3)
+#define MES(x) ((x) ^ 1)
+
+#define READ_MEM_U8(mem, addr) (reinterpret_cast(mem)[BES(addr)])
+#define READ_MEM_U16(mem, addr) (reinterpret_cast(mem)[HES(addr) >> 1])
+#define READ_MEM_U32(mem, addr) (reinterpret_cast(mem)[addr >> 2])
+
+#define WRITE_MEM_U8(mem, addr, data) (reinterpret_cast(mem)[BES(addr)] = data)
+#define WRITE_MEM_U16(mem, addr, data) (reinterpret_cast(mem)[HES(addr) >> 1] = data)
+#define WRITE_MEM_U32(mem, addr, data) (reinterpret_cast(mem)[addr >> 2] = data)
+
+#endif
diff --git a/parallel-rsp/arch/simd/rsp/rsp_core.cpp b/parallel-rsp/arch/simd/rsp/rsp_core.cpp
new file mode 100644
index 0000000..d945c1a
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/rsp_core.cpp
@@ -0,0 +1,603 @@
+//
+// arch/x86_64/rsp/rsp.c
+//
+// Declarations for host RSP functions.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "../../../state.hpp"
+#include "rsp_common.h"
+#include
+
+#ifdef __SSSE3__
+//
+// This table is used to "shuffle" the RSP vector after loading it.
+//
+alignas(64) const uint16_t shuffle_keys[16][8] = {
+ /* -- */ { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E },
+ /* -- */ { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E },
+
+ /* 0q */ { 0x0100, 0x0100, 0x0504, 0x0504, 0x0908, 0x0908, 0x0D0C, 0x0D0C },
+ /* 1q */ { 0x0302, 0x0302, 0x0706, 0x0706, 0x0B0A, 0x0B0A, 0x0F0E, 0x0F0E },
+
+ /* 0h */ { 0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908 },
+ /* 1h */ { 0x0302, 0x0302, 0x0302, 0x0302, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A },
+ /* 2h */ { 0x0504, 0x0504, 0x0504, 0x0504, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C },
+ /* 3h */ { 0x0706, 0x0706, 0x0706, 0x0706, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E },
+
+ /* 0w */ { 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 },
+ /* 1w */ { 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302 },
+ /* 2w */ { 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504 },
+ /* 3w */ { 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706 },
+ /* 4w */ { 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908 },
+ /* 5w */ { 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A },
+ /* 6w */ { 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C },
+ /* 7w */ { 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E },
+};
+#endif
+
+//
+// These tables are used to shift data loaded from DMEM.
+// In addition to shifting, they also take into account that
+// DMEM uses big-endian byte ordering, whereas vectors are
+// 2-byte little-endian.
+//
+
+// Shift left LUT; shifts in zeros from the right, one byte at a time.
+alignas(64) static const uint16_t sll_b2l_keys[16][8] = {
+ { 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
+ { 0x8000, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E },
+ { 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
+ { 0x8080, 0x8000, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C },
+
+ { 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
+ { 0x8080, 0x8080, 0x8000, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A },
+ { 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
+ { 0x8080, 0x8080, 0x8080, 0x8000, 0x0102, 0x0304, 0x0506, 0x0708 },
+
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8000, 0x0102, 0x0304, 0x0506 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8000, 0x0102, 0x0304 },
+
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8000, 0x0102 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8000 },
+};
+
+// Shift left LUT; shirts low order to high order, inserting 0x00s.
+alignas(64) static const uint16_t sll_l2b_keys[16][8] = {
+ { 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
+ { 0x0180, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0E0C },
+ { 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
+ { 0x8080, 0x0180, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A },
+
+ { 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
+ { 0x8080, 0x8080, 0x0180, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08 },
+ { 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
+ { 0x8080, 0x8080, 0x8080, 0x0180, 0x0300, 0x0502, 0x0704, 0x0906 },
+
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x0180, 0x0300, 0x0502, 0x0704 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0180, 0x0300, 0x0502 },
+
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0180, 0x0300 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001 },
+ { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0180 },
+};
+
+// Shift right LUT; shifts in zeros from the left, one byte at a time.
+alignas(64) static const uint16_t srl_b2l_keys[16][8] = {
+ { 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
+ { 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80 },
+ { 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080 },
+ { 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080 },
+
+ { 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080 },
+ { 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080 },
+ { 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080 },
+ { 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080 },
+
+ { 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080 },
+ { 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080 },
+ { 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
+ { 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
+
+ { 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
+ { 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
+ { 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
+ { 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
+};
+
+alignas(64) static const uint16_t ror_b2l_keys[16][8] = {
+ { 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
+ { 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00 },
+ { 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001 },
+ { 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102 },
+
+ { 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203 },
+ { 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304 },
+ { 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405 },
+ { 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506 },
+
+ { 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607 },
+ { 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708 },
+ { 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
+ { 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A },
+
+ { 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
+ { 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C },
+ { 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
+ { 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E },
+};
+
+// Rotate left LUT; rotates high order bytes back to low order.
+alignas(64) static const uint16_t rol_l2b_keys[16][8] = {
+ { 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
+ { 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C },
+ { 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
+ { 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A },
+
+ { 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
+ { 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08 },
+ { 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
+ { 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906 },
+
+ { 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607 },
+ { 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704 },
+ { 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405 },
+ { 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502 },
+
+ { 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203 },
+ { 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300 },
+ { 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001 },
+ { 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E },
+};
+
+// Rotate right LUT; rotates high order bytes back to low order.
+alignas(64) static const uint16_t ror_l2b_keys[16][8] = {
+ { 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
+ { 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E },
+ { 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001 },
+ { 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300 },
+
+ { 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203 },
+ { 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502 },
+ { 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405 },
+ { 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704 },
+
+ { 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607 },
+ { 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906 },
+ { 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
+ { 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08 },
+
+ { 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
+ { 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A },
+ { 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
+ { 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C },
+};
+
+#ifndef __SSSE3__
+static inline __m128i sse2_pshufb_loop8(__m128i v, const uint8_t *keys)
+{
+ alignas(16) uint8_t temp[(0x80 | 128) + 1];
+ unsigned j;
+
+ _mm_store_si128((__m128i *)temp, v);
+ temp[0x80] = 0;
+
+#if 0
+ for (j = 0; j < 16; j++)
+ temp[j + 16] = temp[keys[j]];
+#else
+ for (j = 0; j < 16; j += 4)
+ {
+ temp[j + 16] = temp[keys[j + 0]];
+ temp[j + 17] = temp[keys[j + 1]];
+ temp[j + 18] = temp[keys[j + 2]];
+ temp[j + 19] = temp[keys[j + 3]];
+ }
+#endif
+
+ return _mm_load_si128(((__m128i *)temp) + 1);
+}
+static inline __m128i sse2_pshufb(__m128i v, const uint16_t *keys)
+{
+ union {
+ const uint16_t *k16;
+ const uint8_t *k8;
+ } x;
+ x.k16 = keys;
+ return sse2_pshufb_loop8(v, x.k8);
+}
+#endif
+
+// Uses a LUT to populate flag registers.
+void rsp_set_flags(uint16_t *flags, uint16_t rt)
+{
+ unsigned i;
+
+ static const uint16_t array[16][4] = {
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, { 0xFFFF, 0x0000, 0x0000, 0x0000 }, { 0x0000, 0xFFFF, 0x0000, 0x0000 },
+ { 0xFFFF, 0xFFFF, 0x0000, 0x0000 }, { 0x0000, 0x0000, 0xFFFF, 0x0000 }, { 0xFFFF, 0x0000, 0xFFFF, 0x0000 },
+ { 0x0000, 0xFFFF, 0xFFFF, 0x0000 }, { 0xFFFF, 0xFFFF, 0xFFFF, 0x0000 }, { 0x0000, 0x0000, 0x0000, 0xFFFF },
+ { 0xFFFF, 0x0000, 0x0000, 0xFFFF }, { 0x0000, 0xFFFF, 0x0000, 0xFFFF }, { 0xFFFF, 0xFFFF, 0x0000, 0xFFFF },
+ { 0x0000, 0x0000, 0xFFFF, 0xFFFF }, { 0xFFFF, 0x0000, 0xFFFF, 0xFFFF }, { 0x0000, 0xFFFF, 0xFFFF, 0xFFFF },
+ { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
+ };
+
+ for (i = 0; i < 2; i++, rt >>= 4)
+ memcpy(flags + 8 + i * 4, array[rt & 0xF], sizeof(array[0]));
+
+ for (i = 0; i < 2; i++, rt >>= 4)
+ memcpy(flags + 0 + i * 4, array[rt & 0xF], sizeof(array[0]));
+}
+
+#ifndef __SSSE3__
+__m128i rsp_vect_load_and_shuffle_operand(const uint16_t *src, unsigned element)
+{
+ __m128i v;
+
+ switch (element)
+ {
+ case 0:
+ case 1:
+ v = _mm_load_si128((__m128i *)src);
+ return v;
+
+ // element => 0q
+ case 2:
+ v = _mm_load_si128((__m128i *)src);
+ v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(2, 2, 0, 0));
+ v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(2, 2, 0, 0));
+ return v;
+
+ // element => 1q
+ case 3:
+ v = _mm_load_si128((__m128i *)src);
+ v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3, 3, 1, 1));
+ v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(3, 3, 1, 1));
+ return v;
+
+ // element => 0h ... 3h
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ __asm__("" : "=x"(v)); /* Do not remove. */
+ v = _mm_insert_epi16(v, src[element - 4], 0);
+ v = _mm_insert_epi16(v, src[element - 0], 1);
+ v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(1, 1, 0, 0));
+ v = _mm_shuffle_epi32(v, _MM_SHUFFLE(1, 1, 0, 0));
+ return v;
+
+ // element => 0w ... 7w
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ __asm__("" : "=x"(v)); /* Do not remove. */
+ v = _mm_insert_epi16(v, src[element - 8], 0);
+ v = _mm_unpacklo_epi16(v, v);
+ v = _mm_shuffle_epi32(v, _MM_SHUFFLE(0, 0, 0, 0));
+ return v;
+ }
+
+#ifdef NDEBUG
+ __builtin_unreachable();
+#else
+ __builtin_trap();
+#endif
+}
+#endif
+
+//
+// SSSE3+ accelerated loads for group I. Byteswap big-endian to 2-byte
+// little-endian vector. Start at vector element offset, discarding any
+// wraparound as necessary.
+//
+// TODO: Reverse-engineer what happens when loads to vector elements must
+// wraparound. Do we just discard the data, as below, or does the
+// data effectively get rotated around the edge of the vector?
+//
+void rsp_vload_group1(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
+ rsp_vect_t dqm)
+{
+ __m128i data;
+
+ unsigned offset = addr & 0x7;
+ unsigned ror = offset - element;
+
+ // Always load in 8-byte chunks to emulate wraparound.
+ if (offset)
+ {
+ uint32_t aligned_addr_lo = addr & ~0x7;
+ uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF;
+ __m128i temp;
+
+ data = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_lo));
+ temp = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_hi));
+ data = _mm_unpacklo_epi64(data, temp);
+ }
+
+ else
+ data = _mm_loadl_epi64((__m128i *)(rsp->dmem + addr));
+
+ // Shift the DQM up to the point where we mux in the data.
+#ifndef __SSSE3__
+ dqm = sse2_pshufb(dqm, sll_b2l_keys[element]);
+#else
+ __m128i ekey = _mm_load_si128((__m128i *)(sll_b2l_keys[element]));
+ dqm = _mm_shuffle_epi8(dqm, ekey);
+#endif
+
+ // Align the data to the DQM so we can mask it in.
+#ifndef __SSSE3__
+ data = sse2_pshufb(data, ror_b2l_keys[ror & 0xF]);
+#else
+ ekey = _mm_load_si128((__m128i *)(ror_b2l_keys[ror & 0xF]));
+ data = _mm_shuffle_epi8(data, ekey);
+#endif
+
+ // Mask and mux in the data.
+#ifdef __SSE4_1__
+ reg = _mm_blendv_epi8(reg, data, dqm);
+#else
+ data = _mm_and_si128(dqm, data);
+ reg = _mm_andnot_si128(dqm, reg);
+ reg = _mm_or_si128(data, reg);
+#endif
+
+ _mm_store_si128((__m128i *)regp, reg);
+}
+
+//
+// SSSE3+ accelerated loads for group II.
+//
+// TODO: Reverse-engineer what happens when loads to vector elements must
+// wraparound. Do we just discard the data, as below, or does the
+// data effectively get rotated around the edge of the vector?
+//
+// TODO: Reverse-engineer what happens when element != 0.
+//
+void rsp_vload_group2(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
+ rsp_vect_t dqm)
+{
+ unsigned offset = addr & 0x7;
+ __m128i data, zero;
+
+ // Always load in 8-byte chunks to emulate wraparound.
+ if (offset)
+ {
+ uint32_t aligned_addr_lo = addr & ~0x7;
+ uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF;
+ uint64_t datalow, datahigh;
+
+ memcpy(&datalow, rsp->dmem + aligned_addr_lo, sizeof(datalow));
+ memcpy(&datahigh, rsp->dmem + aligned_addr_hi, sizeof(datahigh));
+
+ // TODO: Get rid of GNU extensions.
+ datalow = __builtin_bswap64(datalow);
+ datahigh = __builtin_bswap64(datahigh);
+ datahigh >>= ((8 - offset) << 3);
+ datalow <<= (offset << 3);
+ datalow = datahigh | datalow;
+ datalow = __builtin_bswap64(datalow);
+
+ data = _mm_loadl_epi64((__m128i *)&datalow);
+ }
+
+ else
+ data = _mm_loadl_epi64((__m128i *)(rsp->dmem + addr));
+
+ // "Unpack" the data.
+ zero = _mm_setzero_si128();
+ data = _mm_unpacklo_epi8(zero, data);
+
+#if 0
+ if (rsp->pipeline.exdf_latch.request.type != RSP_MEM_REQUEST_PACK)
+#endif
+ data = _mm_srli_epi16(data, 1);
+
+ _mm_store_si128((__m128i *)regp, data);
+}
+
+//
+// SSSE3+ accelerated loads for group IV. Byteswap big-endian to 2-byte
+// little-endian vector. Stop loading at quadword boundaries.
+//
+// TODO: Reverse-engineer what happens when loads from vector elements
+// must wraparound (i.e., the address offset is small, starting
+// element is large).
+//
+void rsp_vload_group4(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
+ rsp_vect_t dqm)
+{
+ uint32_t aligned_addr = addr & 0xFF0;
+ unsigned offset = addr & 0xF;
+ unsigned ror;
+
+ __m128i data = _mm_load_si128((__m128i *)(rsp->dmem + aligned_addr));
+
+ // TODO: Use of element is almost certainly wrong...
+ ror = 16 - element + offset;
+
+#if 0
+ if (rsp->pipeline.exdf_latch.request.type != RSP_MEM_REQUEST_QUAD)
+#endif
+ dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm);
+
+#ifndef __SSSE3__
+ data = sse2_pshufb(data, ror_b2l_keys[ror & 0xF]);
+ dqm = sse2_pshufb(dqm, ror_b2l_keys[ror & 0xF]);
+#else
+ __m128i dkey = _mm_load_si128((__m128i *)(ror_b2l_keys[ror & 0xF]));
+ data = _mm_shuffle_epi8(data, dkey);
+ dqm = _mm_shuffle_epi8(dqm, dkey);
+#endif
+
+ // Mask and mux in the data.
+#ifdef __SSE4_1__
+ data = _mm_blendv_epi8(reg, data, dqm);
+#else
+ data = _mm_and_si128(dqm, data);
+ reg = _mm_andnot_si128(dqm, reg);
+ data = _mm_or_si128(data, reg);
+#endif
+
+ _mm_store_si128((__m128i *)regp, data);
+}
+
+//
+// SSE3+ accelerated stores for group I. Byteswap 2-byte little-endian
+// vector back to big-endian. Start at vector element offset, wrapping
+// around the edge of the vector as necessary.
+//
+// TODO: Reverse-engineer what happens when stores from vector elements
+// must wraparound. Do we just stop storing the data, or do we
+// continue storing from the front of the vector, as below?
+//
+void rsp_vstore_group1(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
+ rsp_vect_t dqm)
+{
+ unsigned offset = addr & 0x7;
+ unsigned ror = element - offset;
+ __m128i data;
+
+ // Shift the DQM up to the point where we mux in the data.
+#ifndef __SSSE3__
+ dqm = sse2_pshufb(dqm, sll_l2b_keys[offset]);
+#else
+ __m128i ekey = _mm_load_si128((__m128i *)(sll_l2b_keys[offset]));
+ dqm = _mm_shuffle_epi8(dqm, ekey);
+#endif
+
+ // Rotate the reg to align with the DQM.
+#ifndef __SSSE3__
+ reg = sse2_pshufb(reg, ror_l2b_keys[ror & 0xF]);
+#else
+ ekey = _mm_load_si128((__m128i *)(ror_l2b_keys[ror & 0xF]));
+ reg = _mm_shuffle_epi8(reg, ekey);
+#endif
+
+ // Always load in 8-byte chunks to emulate wraparound.
+ if (offset)
+ {
+ uint32_t aligned_addr_lo = addr & ~0x7;
+ uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF;
+ __m128i temp;
+
+ data = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_lo));
+ temp = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_hi));
+ data = _mm_unpacklo_epi64(data, temp);
+
+ // Mask and mux in the data.
+#ifdef __SSE4_1__
+ data = _mm_blendv_epi8(data, reg, dqm);
+#else
+ data = _mm_andnot_si128(dqm, data);
+ reg = _mm_and_si128(dqm, reg);
+ data = _mm_or_si128(data, reg);
+#endif
+
+ _mm_storel_epi64((__m128i *)(rsp->dmem + aligned_addr_lo), data);
+
+ data = _mm_srli_si128(data, 8);
+ _mm_storel_epi64((__m128i *)(rsp->dmem + aligned_addr_hi), data);
+ }
+
+ else
+ {
+ data = _mm_loadl_epi64((__m128i *)(rsp->dmem + addr));
+
+ // Mask and mux in the data.
+#ifdef __SSE4_1__
+ data = _mm_blendv_epi8(data, reg, dqm);
+#else
+ data = _mm_andnot_si128(dqm, data);
+ reg = _mm_and_si128(dqm, reg);
+ data = _mm_or_si128(data, reg);
+#endif
+
+ _mm_storel_epi64((__m128i *)(rsp->dmem + addr), data);
+ }
+}
+
+//
+// SSE3+ accelerated stores for group II. Byteswap 2-byte little-endian
+// vector back to big-endian. Start at vector element offset, wrapping
+// around the edge of the vector as necessary.
+//
+// TODO: Reverse-engineer what happens when stores from vector elements
+// must wraparound. Do we just stop storing the data, or do we
+// continue storing from the front of the vector, as below?
+//
+// TODO: Reverse-engineer what happens when element != 0.
+//
+void rsp_vstore_group2(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
+ rsp_vect_t dqm)
+{
+
+ // "Pack" the data.
+#if 0
+ if (rsp->pipeline.exdf_latch.request.type != RSP_MEM_REQUEST_PACK)
+#endif
+ reg = _mm_slli_epi16(reg, 1);
+
+ reg = _mm_srai_epi16(reg, 8);
+ reg = _mm_packs_epi16(reg, reg);
+
+ // TODO: Always store in 8-byte chunks to emulate wraparound.
+ _mm_storel_epi64((__m128i *)(rsp->dmem + addr), reg);
+}
+
+//
+// SSE3+ accelerated stores for group IV. Byteswap 2-byte little-endian
+// vector back to big-endian. Stop storing at quadword boundaries.
+//
+void rsp_vstore_group4(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
+ rsp_vect_t dqm)
+{
+ uint32_t aligned_addr = addr & 0xFF0;
+ unsigned offset = addr & 0xF;
+ unsigned rol = offset;
+
+ __m128i data = _mm_load_si128((__m128i *)(rsp->dmem + aligned_addr));
+
+#if 0
+ if (rsp->pipeline.exdf_latch.request.type == RSP_MEM_REQUEST_QUAD)
+#else
+ if (0)
+#endif
+ rol -= element;
+
+ // TODO: How is this adjusted for SRV when e != 0?
+ else dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm);
+
+#ifndef __SSSE3__
+ reg = sse2_pshufb(reg, rol_l2b_keys[rol & 0xF]);
+#else
+ __m128i ekey = _mm_load_si128((__m128i *)(rol_l2b_keys[rol & 0xF]));
+ reg = _mm_shuffle_epi8(reg, ekey);
+#endif
+
+ // Mask and mux out the data, write.
+#ifdef __SSE4_1__
+ data = _mm_blendv_epi8(data, reg, dqm);
+#else
+ reg = _mm_and_si128(dqm, reg);
+ data = _mm_andnot_si128(dqm, data);
+ data = _mm_or_si128(data, reg);
+#endif
+
+ _mm_store_si128((__m128i *)(rsp->dmem + aligned_addr), data);
+}
diff --git a/parallel-rsp/arch/simd/rsp/rsp_impl.h b/parallel-rsp/arch/simd/rsp/rsp_impl.h
new file mode 100644
index 0000000..f81dfa6
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/rsp_impl.h
@@ -0,0 +1,29 @@
+#ifndef RSP_IMPL_H
+#define RSP_IMPL_H
+
+#include "clamp.h"
+#include "vabs.h"
+#include "vadd.h"
+#include "vaddc.h"
+#include "vand.h"
+#include "vch.h"
+#include "vcl.h"
+#include "vcmp.h"
+#include "vcr.h"
+#include "vdivh.h"
+#include "vmac.h"
+#include "vmov.h"
+#include "vmrg.h"
+#include "vmul.h"
+#include "vmulh.h"
+#include "vmull.h"
+#include "vmulm.h"
+#include "vmuln.h"
+#include "vor.h"
+#include "vrcpsq.h"
+#include "vrsq.h"
+#include "vsub.h"
+#include "vsubc.h"
+#include "vxor.h"
+
+#endif
diff --git a/parallel-rsp/arch/simd/rsp/vabs.h b/parallel-rsp/arch/simd/rsp/vabs.h
new file mode 100644
index 0000000..999ef76
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vabs.h
@@ -0,0 +1,19 @@
+//
+// arch/x86_64/rsp/vabs.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vabs(__m128i vs, __m128i vt, __m128i *acc_lo)
+{
+ __m128i vs_zero = _mm_cmpeq_epi16(vs, _mm_setzero_si128());
+ __m128i sign_lt = _mm_srai_epi16(vs, 15);
+ __m128i vd = _mm_andnot_si128(vs_zero, vt);
+
+ // Careful: if VT = 0x8000 and VS is negative,
+ // acc_lo will be 0x8000 but vd will be 0x7FFF.
+ vd = _mm_xor_si128(vd, sign_lt);
+ *acc_lo = _mm_sub_epi16(vd, sign_lt);
+ return _mm_subs_epi16(vd, sign_lt);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vadd.h b/parallel-rsp/arch/simd/rsp/vadd.h
new file mode 100644
index 0000000..6c588ab
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vadd.h
@@ -0,0 +1,22 @@
+//
+// arch/x86_64/rsp/vadd.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vadd(__m128i vs, __m128i vt, __m128i carry, __m128i *acc_lo)
+{
+ __m128i vd, minimum, maximum;
+
+ // VCC uses unsaturated arithmetic.
+ vd = _mm_add_epi16(vs, vt);
+ *acc_lo = _mm_sub_epi16(vd, carry);
+
+ // VD is the signed sum of the two sources and the carry. Since we
+ // have to saturate the sum of all three, we have to be clever.
+ minimum = _mm_min_epi16(vs, vt);
+ maximum = _mm_max_epi16(vs, vt);
+ minimum = _mm_subs_epi16(minimum, carry);
+ return _mm_adds_epi16(minimum, maximum);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vaddc.h b/parallel-rsp/arch/simd/rsp/vaddc.h
new file mode 100644
index 0000000..29f04fa
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vaddc.h
@@ -0,0 +1,19 @@
+//
+// arch/x86_64/rsp/vaddc.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vaddc(__m128i vs, __m128i vt, __m128i zero, __m128i *sn)
+{
+ __m128i sat_sum, unsat_sum;
+
+ sat_sum = _mm_adds_epu16(vs, vt);
+ unsat_sum = _mm_add_epi16(vs, vt);
+
+ *sn = _mm_cmpeq_epi16(sat_sum, unsat_sum);
+ *sn = _mm_cmpeq_epi16(*sn, zero);
+
+ return unsat_sum;
+}
diff --git a/parallel-rsp/arch/simd/rsp/vand.h b/parallel-rsp/arch/simd/rsp/vand.h
new file mode 100644
index 0000000..52a2958
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vand.h
@@ -0,0 +1,17 @@
+//
+// arch/x86_64/rsp/vand.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vand(__m128i vs, __m128i vt)
+{
+ return _mm_and_si128(vs, vt);
+}
+
+static inline __m128i rsp_vnand(__m128i vs, __m128i vt)
+{
+ __m128i vd = _mm_and_si128(vs, vt);
+ return _mm_xor_si128(vd, _mm_set1_epi32(0xffffffffu));
+}
diff --git a/parallel-rsp/arch/simd/rsp/vch.h b/parallel-rsp/arch/simd/rsp/vch.h
new file mode 100644
index 0000000..a34f59f
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vch.h
@@ -0,0 +1,68 @@
+//
+// arch/x86_64/rsp/vch.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vch(__m128i vs, __m128i vt, __m128i zero, __m128i *ge, __m128i *le, __m128i *eq,
+ __m128i *sign, __m128i *vce)
+{
+
+ __m128i sign_negvt, vt_neg;
+ __m128i diff, diff_zero, diff_sel_mask;
+ __m128i diff_gez, diff_lez;
+
+ // sign = (vs ^ vt) < 0
+ *sign = _mm_xor_si128(vs, vt);
+ *sign = _mm_cmplt_epi16(*sign, zero);
+
+ // sign_negvt = sign ? -vt : vt
+ sign_negvt = _mm_xor_si128(vt, *sign);
+ sign_negvt = _mm_sub_epi16(sign_negvt, *sign);
+
+ // Compute diff, diff_zero:
+ diff = _mm_sub_epi16(vs, sign_negvt);
+ diff_zero = _mm_cmpeq_epi16(diff, zero);
+
+ // Compute le/ge:
+ vt_neg = _mm_cmplt_epi16(vt, zero);
+ diff_lez = _mm_cmpgt_epi16(diff, zero);
+ diff_gez = _mm_or_si128(diff_lez, diff_zero);
+ diff_lez = _mm_cmpeq_epi16(zero, diff_lez);
+
+#ifdef __SSE4_1__
+ *ge = _mm_blendv_epi8(diff_gez, vt_neg, *sign);
+ *le = _mm_blendv_epi8(vt_neg, diff_lez, *sign);
+#else
+ *ge = _mm_and_si128(*sign, vt_neg);
+ diff_gez = _mm_andnot_si128(*sign, diff_gez);
+ *ge = _mm_or_si128(*ge, diff_gez);
+
+ *le = _mm_and_si128(*sign, diff_lez);
+ diff_lez = _mm_andnot_si128(*sign, vt_neg);
+ *le = _mm_or_si128(*le, diff_lez);
+#endif
+
+ // Compute vce:
+ *vce = _mm_cmpeq_epi16(diff, *sign);
+ *vce = _mm_and_si128(*vce, *sign);
+
+ // Compute !eq:
+ *eq = _mm_or_si128(diff_zero, *vce);
+ *eq = _mm_cmpeq_epi16(*eq, zero);
+
+ // Compute result:
+#ifdef __SSE4_1__
+ diff_sel_mask = _mm_blendv_epi8(*ge, *le, *sign);
+ return _mm_blendv_epi8(vs, sign_negvt, diff_sel_mask);
+#else
+ diff_lez = _mm_and_si128(*sign, *le);
+ diff_gez = _mm_andnot_si128(*sign, *ge);
+ diff_sel_mask = _mm_or_si128(diff_lez, diff_gez);
+
+ diff_lez = _mm_and_si128(diff_sel_mask, sign_negvt);
+ diff_gez = _mm_andnot_si128(diff_sel_mask, vs);
+ return _mm_or_si128(diff_lez, diff_gez);
+#endif
+}
diff --git a/parallel-rsp/arch/simd/rsp/vcl.h b/parallel-rsp/arch/simd/rsp/vcl.h
new file mode 100644
index 0000000..1c12638
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vcl.h
@@ -0,0 +1,75 @@
+//
+// arch/x86_64/rsp/vcl.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vcl(__m128i vs, __m128i vt, __m128i zero, __m128i *ge, __m128i *le, __m128i eq, __m128i sign,
+ __m128i vce)
+{
+
+ __m128i sign_negvt, diff, ncarry, nvce, diff_zero;
+ __m128i le_case1, le_case2, le_eq, do_le;
+ __m128i ge_eq, do_ge, mux_mask;
+
+ // sign_negvt = sign ? -vt : vt
+ sign_negvt = _mm_xor_si128(vt, sign);
+ sign_negvt = _mm_sub_epi16(sign_negvt, sign);
+
+ // Compute diff, diff_zero, ncarry, and nvce:
+ // Note: diff = sign ? (vs + vt) : (vs - vt).
+ diff = _mm_sub_epi16(vs, sign_negvt);
+ ncarry = _mm_adds_epu16(vs, vt);
+ ncarry = _mm_cmpeq_epi16(diff, ncarry);
+ nvce = _mm_cmpeq_epi16(vce, zero);
+ diff_zero = _mm_cmpeq_epi16(diff, zero);
+
+ // Compute results for if (sign && ne):
+ le_case1 = _mm_and_si128(diff_zero, ncarry);
+ le_case1 = _mm_and_si128(nvce, le_case1);
+ le_case2 = _mm_or_si128(diff_zero, ncarry);
+ le_case2 = _mm_and_si128(vce, le_case2);
+ le_eq = _mm_or_si128(le_case1, le_case2);
+
+ // Compute results for if (!sign && ne):
+ ge_eq = _mm_subs_epu16(vt, vs);
+ ge_eq = _mm_cmpeq_epi16(ge_eq, zero);
+
+ // Blend everything together. Caveat: we don't update
+ // the results of ge/le if ne is false, so be careful.
+ do_le = _mm_andnot_si128(eq, sign);
+#ifdef __SSE4_1__
+ *le = _mm_blendv_epi8(*le, le_eq, do_le);
+#else
+ le_eq = _mm_and_si128(do_le, le_eq);
+ *le = _mm_andnot_si128(do_le, *le);
+ *le = _mm_or_si128(le_eq, *le);
+#endif
+
+ do_ge = _mm_or_si128(sign, eq);
+#ifdef __SSE4_1__
+ *ge = _mm_blendv_epi8(ge_eq, *ge, do_ge);
+#else
+ *ge = _mm_and_si128(do_ge, *ge);
+ ge_eq = _mm_andnot_si128(do_ge, ge_eq);
+ *ge = _mm_or_si128(ge_eq, *ge);
+#endif
+
+ // Mux the result based on the value of sign.
+#ifdef __SSE4_1__
+ mux_mask = _mm_blendv_epi8(*ge, *le, sign);
+#else
+ do_le = _mm_and_si128(sign, *le);
+ do_ge = _mm_andnot_si128(sign, *ge);
+ mux_mask = _mm_or_si128(do_le, do_ge);
+#endif
+
+#ifdef __SSE4_1__
+ return _mm_blendv_epi8(vs, sign_negvt, mux_mask);
+#else
+ sign_negvt = _mm_and_si128(mux_mask, sign_negvt);
+ vs = _mm_andnot_si128(mux_mask, vs);
+ return _mm_or_si128(sign_negvt, vs);
+#endif
+}
diff --git a/parallel-rsp/arch/simd/rsp/vcmp.h b/parallel-rsp/arch/simd/rsp/vcmp.h
new file mode 100644
index 0000000..2a09022
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vcmp.h
@@ -0,0 +1,82 @@
+//
+// arch/x86_64/rsp/vcmp.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_veq(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
+{
+ __m128i equal = _mm_cmpeq_epi16(vs, vt);
+
+ *le = _mm_andnot_si128(eq, equal);
+
+#ifdef __SSE4_1__
+ return _mm_blendv_epi8(vt, vs, *le);
+#else
+ vs = _mm_and_si128(*le, vs);
+ vt = _mm_andnot_si128(*le, vt);
+ return _mm_or_si128(vs, vt);
+#endif
+}
+
+static inline __m128i rsp_vge(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
+{
+ __m128i equal = _mm_cmpeq_epi16(vs, vt);
+
+ __m128i gt = _mm_cmpgt_epi16(vs, vt);
+ __m128i equalsign = _mm_and_si128(eq, sign);
+
+ equal = _mm_andnot_si128(equalsign, equal);
+ *le = _mm_or_si128(gt, equal);
+
+#ifdef __SSE4_1__
+ return _mm_blendv_epi8(vt, vs, *le);
+#else
+ vs = _mm_and_si128(*le, vs);
+ vt = _mm_andnot_si128(*le, vt);
+ return _mm_or_si128(vs, vt);
+#endif
+}
+
+static inline __m128i rsp_vlt(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
+{
+ __m128i equal = _mm_cmpeq_epi16(vs, vt);
+ __m128i lt = _mm_cmplt_epi16(vs, vt);
+
+ equal = _mm_and_si128(eq, equal);
+ equal = _mm_and_si128(sign, equal);
+ *le = _mm_or_si128(lt, equal);
+
+#ifdef __SSE4_1__
+ return _mm_blendv_epi8(vt, vs, *le);
+#else
+ vs = _mm_and_si128(*le, vs);
+ vt = _mm_andnot_si128(*le, vt);
+ return _mm_or_si128(vs, vt);
+#endif
+}
+
+static inline __m128i rsp_vne(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
+{
+ __m128i equal = _mm_cmpeq_epi16(vs, vt);
+ __m128i nequal = _mm_cmpeq_epi16(equal, zero);
+
+ *le = _mm_and_si128(eq, equal);
+ *le = _mm_or_si128(*le, nequal);
+
+#ifdef INTENSE_DEBUG
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VS[%d] = %d\n", i, reinterpret_cast(&vs)[i]);
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VT[%d] = %d\n", i, reinterpret_cast(&vt)[i]);
+#endif
+
+#ifdef __SSE4_1__
+ return _mm_blendv_epi8(vt, vs, *le);
+#else
+ vs = _mm_and_si128(*le, vs);
+ vt = _mm_andnot_si128(*le, vt);
+ return _mm_or_si128(vs, vt);
+#endif
+}
diff --git a/parallel-rsp/arch/simd/rsp/vcr.h b/parallel-rsp/arch/simd/rsp/vcr.h
new file mode 100644
index 0000000..0649feb
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vcr.h
@@ -0,0 +1,51 @@
+//
+// arch/x86_64/rsp/vcr.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vcr(__m128i vs, __m128i vt, __m128i zero, __m128i *ge, __m128i *le)
+{
+ __m128i diff_sel_mask, diff_gez, diff_lez;
+ __m128i sign, sign_notvt;
+
+#ifdef INTENSE_DEBUG
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VS[%d] = %d\n", i, reinterpret_cast(&vs)[i]);
+
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VT[%d] = %d\n", i, reinterpret_cast(&vt)[i]);
+#endif
+
+ // sign = (vs ^ vt) < 0
+ sign = _mm_xor_si128(vs, vt);
+ sign = _mm_srai_epi16(sign, 15);
+
+ // Compute le
+ diff_lez = _mm_and_si128(vs, sign);
+ diff_lez = _mm_add_epi16(diff_lez, vt);
+ *le = _mm_srai_epi16(diff_lez, 15);
+
+ // Compute ge
+ diff_gez = _mm_or_si128(vs, sign);
+ diff_gez = _mm_min_epi16(diff_gez, vt);
+ *ge = _mm_cmpeq_epi16(diff_gez, vt);
+
+ // sign_notvt = sn ? ~vt : vt
+ sign_notvt = _mm_xor_si128(vt, sign);
+
+ // Compute result:
+#ifdef __SSE4_1__
+ diff_sel_mask = _mm_blendv_epi8(*ge, *le, sign);
+ return _mm_blendv_epi8(vs, sign_notvt, diff_sel_mask);
+#else
+ diff_sel_mask = _mm_sub_epi16(*le, *ge);
+ diff_sel_mask = _mm_and_si128(diff_sel_mask, sign);
+ diff_sel_mask = _mm_add_epi16(diff_sel_mask, *ge);
+
+ zero = _mm_sub_epi16(sign_notvt, vs);
+ zero = _mm_and_si128(zero, diff_sel_mask);
+ return _mm_add_epi16(zero, vs);
+#endif
+}
diff --git a/parallel-rsp/arch/simd/rsp/vdivh.h b/parallel-rsp/arch/simd/rsp/vdivh.h
new file mode 100644
index 0000000..384c888
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vdivh.h
@@ -0,0 +1,17 @@
+//
+// arch/x86_64/rsp/vrcp.c
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+inline __m128i rsp_vdivh(RSP::CPUState *rsp, unsigned src, unsigned e, unsigned dest, unsigned de)
+{
+
+ // Get the element from VT.
+ rsp->cp2.div_in = rsp->cp2.regs[src].e[e & 0x7];
+
+ // Write out the upper part of the result.
+ rsp->cp2.regs[dest].e[de & 0x7] = rsp->cp2.div_out;
+ return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmac.h b/parallel-rsp/arch/simd/rsp/vmac.h
new file mode 100644
index 0000000..5180bae
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmac.h
@@ -0,0 +1,67 @@
+//
+// arch/x86_64/rsp/vmacf.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+template
+static inline __m128i rsp_vmacf_vmacu(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
+ __m128i *acc_hi)
+{
+ __m128i overflow_hi_mask, overflow_md_mask;
+ __m128i lo, md, hi, carry, overflow_mask;
+
+ // Get the product and shift it over
+ // being sure to save the carries.
+ lo = _mm_mullo_epi16(vs, vt);
+ hi = _mm_mulhi_epi16(vs, vt);
+
+ md = _mm_slli_epi16(hi, 1);
+ carry = _mm_srli_epi16(lo, 15);
+ hi = _mm_srai_epi16(hi, 15);
+ md = _mm_or_si128(md, carry);
+ lo = _mm_slli_epi16(lo, 1);
+
+ // Tricky part: start accumulating everything.
+ // Get/keep the carry as we'll add it in later.
+ overflow_mask = _mm_adds_epu16(*acc_lo, lo);
+ *acc_lo = _mm_add_epi16(*acc_lo, lo);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // Add in the carry. If the middle portion is
+ // already 0xFFFF and we have a carry, we have
+ // to carry the all the way up to hi.
+ md = _mm_sub_epi16(md, overflow_mask);
+ carry = _mm_cmpeq_epi16(md, zero);
+ carry = _mm_and_si128(carry, overflow_mask);
+ hi = _mm_sub_epi16(hi, carry);
+
+ // Accumulate the middle portion.
+ overflow_mask = _mm_adds_epu16(*acc_md, md);
+ *acc_md = _mm_add_epi16(*acc_md, md);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // Finish up the accumulation of the... accumulator.
+ *acc_hi = _mm_add_epi16(*acc_hi, hi);
+ *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
+
+ // VMACU
+ if (VMACU)
+ {
+ overflow_hi_mask = _mm_srai_epi16(*acc_hi, 15);
+ overflow_md_mask = _mm_srai_epi16(*acc_md, 15);
+ md = _mm_or_si128(overflow_md_mask, *acc_md);
+ overflow_mask = _mm_cmpgt_epi16(*acc_hi, zero);
+ md = _mm_andnot_si128(overflow_hi_mask, md);
+ return _mm_or_si128(overflow_mask, md);
+ }
+
+ // VMACF
+ else
+ return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmov.h b/parallel-rsp/arch/simd/rsp/vmov.h
new file mode 100644
index 0000000..be5856e
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmov.h
@@ -0,0 +1,18 @@
+//
+// arch/x86_64/rsp/vmov.c
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+inline __m128i rsp_vmov(RSP::CPUState *rsp, unsigned src, unsigned e, unsigned dest, unsigned de)
+{
+ uint16_t data;
+
+ // Get the element from VT.
+ data = rsp->cp2.regs[src].e[e & 0x7];
+
+ // Write out the upper part of the result.
+ rsp->cp2.regs[dest].e[de & 0x7] = data;
+ return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmrg.h b/parallel-rsp/arch/simd/rsp/vmrg.h
new file mode 100644
index 0000000..e346e40
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmrg.h
@@ -0,0 +1,17 @@
+//
+// arch/x86_64/rsp/vmrg.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vmrg(__m128i vs, __m128i vt, __m128i le)
+{
+#ifdef __SSE4_1__
+ return _mm_blendv_epi8(vt, vs, le);
+#else
+ vs = _mm_and_si128(le, vs);
+ vt = _mm_andnot_si128(le, vt);
+ return _mm_or_si128(vs, vt);
+#endif
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmudh.h b/parallel-rsp/arch/simd/rsp/vmudh.h
new file mode 100644
index 0000000..8fc8285
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmudh.h
@@ -0,0 +1,14 @@
+//
+// arch/x86_64/rsp/vmudh.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vmudh(__m128i vs, __m128i vt, __m128i *acc_md, __m128i *acc_hi)
+{
+ *acc_md = _mm_mullo_epi16(vs, vt);
+ *acc_hi = _mm_mulhi_epi16(vs, vt);
+
+ return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmul.h b/parallel-rsp/arch/simd/rsp/vmul.h
new file mode 100644
index 0000000..91404b1
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmul.h
@@ -0,0 +1,49 @@
+//
+// arch/x86_64/rsp/vmul.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+//
+// TODO: CHECK ME.
+//
+
+template
+static inline __m128i rsp_vmulf_vmulu(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
+ __m128i *acc_hi)
+{
+ __m128i lo, hi, round, sign1, sign2, eq, neq, neg;
+
+ lo = _mm_mullo_epi16(vs, vt);
+ round = _mm_cmpeq_epi16(zero, zero);
+ sign1 = _mm_srli_epi16(lo, 15);
+ lo = _mm_add_epi16(lo, lo);
+ round = _mm_slli_epi16(round, 15);
+ hi = _mm_mulhi_epi16(vs, vt);
+ sign2 = _mm_srli_epi16(lo, 15);
+ *acc_lo = _mm_add_epi16(round, lo);
+ sign1 = _mm_add_epi16(sign1, sign2);
+
+ hi = _mm_slli_epi16(hi, 1);
+ neq = eq = _mm_cmpeq_epi16(vs, vt);
+ *acc_md = _mm_add_epi16(hi, sign1);
+
+ neg = _mm_srai_epi16(*acc_md, 15);
+
+ // VMULU
+ if (VMULU)
+ {
+ *acc_hi = _mm_andnot_si128(eq, neg);
+ hi = _mm_or_si128(*acc_md, neg);
+ return _mm_andnot_si128(*acc_hi, hi);
+ }
+
+ // VMULF
+ else
+ {
+ eq = _mm_and_si128(eq, neg);
+ *acc_hi = _mm_andnot_si128(neq, neg);
+ return _mm_add_epi16(*acc_md, eq);
+ }
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmulh.h b/parallel-rsp/arch/simd/rsp/vmulh.h
new file mode 100644
index 0000000..a5cc66c
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmulh.h
@@ -0,0 +1,41 @@
+//
+// arch/x86_64/rsp/vmulh.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+template
+static inline __m128i rsp_vmadh_vmudh(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
+ __m128i *acc_hi)
+{
+ __m128i lo, hi, overflow_mask;
+
+ lo = _mm_mullo_epi16(vs, vt);
+ hi = _mm_mulhi_epi16(vs, vt);
+
+ // VMADH
+ if (VMADH)
+ {
+ // Tricky part: start accumulate everything.
+ // Get/keep the carry as we'll add it in later.
+ overflow_mask = _mm_adds_epu16(*acc_md, lo);
+ *acc_md = _mm_add_epi16(*acc_md, lo);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ hi = _mm_sub_epi16(hi, overflow_mask);
+ *acc_hi = _mm_add_epi16(*acc_hi, hi);
+ }
+
+ // VMUDH
+ else
+ {
+ *acc_lo = zero;
+ *acc_md = lo;
+ *acc_hi = hi;
+ }
+
+ return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmull.h b/parallel-rsp/arch/simd/rsp/vmull.h
new file mode 100644
index 0000000..1ec74d5
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmull.h
@@ -0,0 +1,56 @@
+//
+// arch/x86_64/rsp/vmadl.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+template
+static inline __m128i rsp_vmadl_vmudl(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
+ __m128i *acc_hi)
+{
+ __m128i hi, overflow_mask;
+
+ hi = _mm_mulhi_epu16(vs, vt);
+
+ // VMADL
+ if (VMADL)
+ {
+
+ // Tricky part: start accumulate everything.
+ // Get/keep the carry as we'll add it in later.
+ overflow_mask = _mm_adds_epu16(*acc_lo, hi);
+ *acc_lo = _mm_add_epi16(*acc_lo, hi);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+ hi = _mm_sub_epi16(zero, overflow_mask);
+
+ // Check for overflow of the upper sum.
+ //
+ // TODO: Since hi can only be {0,1}, we should
+ // be able to generalize this for performance.
+ overflow_mask = _mm_adds_epu16(*acc_md, hi);
+ *acc_md = _mm_add_epi16(*acc_md, hi);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // Finish up the accumulation of the... accumulator.
+ // Since the product was unsigned, only worry about
+ // positive overflow (i.e.: borrowing not possible).
+ *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
+
+ return rsp_uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero);
+ }
+
+ // VMUDL
+ else
+ {
+ *acc_lo = hi;
+ *acc_md = zero;
+ *acc_hi = zero;
+
+ return hi;
+ }
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmulm.h b/parallel-rsp/arch/simd/rsp/vmulm.h
new file mode 100644
index 0000000..80fb82b
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmulm.h
@@ -0,0 +1,67 @@
+//
+// arch/x86_64/rsp/vmulm.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+template
+static inline __m128i rsp_vmadm_vmudm(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
+ __m128i *acc_hi)
+{
+ __m128i lo, hi, sign, overflow_mask;
+
+ lo = _mm_mullo_epi16(vs, vt);
+ hi = _mm_mulhi_epu16(vs, vt);
+
+ // What we're really want to do is unsigned vs * signed vt.
+ // However, we have no such instructions to do so.
+ //
+ // There's a trick to "fix" an unsigned product, though:
+ // If vt was negative, take the upper 16-bits of the product
+ // and subtract vs.
+ sign = _mm_srai_epi16(vs, 15);
+ vt = _mm_and_si128(vt, sign);
+ hi = _mm_sub_epi16(hi, vt);
+
+ // VMADM
+ if (VMADM)
+ {
+ // Tricky part: start accumulate everything.
+ // Get/keep the carry as we'll add it in later.
+ overflow_mask = _mm_adds_epu16(*acc_lo, lo);
+ *acc_lo = _mm_add_epi16(*acc_lo, lo);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // This is REALLY clever. Since the product results from
+ // two 16-bit components, one positive and one negative,
+ // we don't have to worry about carrying the 1 (we can
+ // only borrow) past 32-bits. So we can just add it here.
+ hi = _mm_sub_epi16(hi, overflow_mask);
+
+ // Check for overflow of the upper sum.
+ overflow_mask = _mm_adds_epu16(*acc_md, hi);
+ *acc_md = _mm_add_epi16(*acc_md, hi);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // Finish up the accumulation of the... accumulator.
+ *acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15));
+ *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
+
+ return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
+ }
+
+ // VMUDM
+ else
+ {
+ *acc_lo = lo;
+ *acc_md = hi;
+ *acc_hi = _mm_srai_epi16(hi, 15);
+
+ return hi;
+ }
+}
diff --git a/parallel-rsp/arch/simd/rsp/vmuln.h b/parallel-rsp/arch/simd/rsp/vmuln.h
new file mode 100644
index 0000000..c7dadcd
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vmuln.h
@@ -0,0 +1,89 @@
+//
+// arch/x86_64/rsp/vmuln.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+template
+static inline __m128i rsp_vmadn_vmudn(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
+ __m128i *acc_hi)
+{
+ __m128i lo, hi, sign, overflow_mask;
+
+#ifdef INTENSE_DEBUG
+ if (VMADN)
+ {
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "ACC LO[%u] = %d\n", i, reinterpret_cast(acc_lo)[i]);
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "ACC MD[%u] = %d\n", i, reinterpret_cast(acc_md)[i]);
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "ACC HI[%u] = %d\n", i, reinterpret_cast(acc_hi)[i]);
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VS[%u] = %d\n", i, reinterpret_cast(&vs)[i]);
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VT[%u] = %d\n", i, reinterpret_cast(&vt)[i]);
+ }
+#endif
+
+ lo = _mm_mullo_epi16(vs, vt);
+ hi = _mm_mulhi_epu16(vs, vt);
+
+ // What we're really want to do is unsigned vs * signed vt.
+ // However, we have no such instructions to do so.
+ //
+ // There's a trick to "fix" an unsigned product, though:
+ // If vt was negative, take the upper 16-bits of the product
+ // and subtract vs.
+ sign = _mm_srai_epi16(vt, 15);
+ vs = _mm_and_si128(vs, sign);
+ hi = _mm_sub_epi16(hi, vs);
+
+ // VMADN
+ if (VMADN)
+ {
+ // Tricky part: start accumulate everything.
+ // Get/keep the carry as we'll add it in later.
+ overflow_mask = _mm_adds_epu16(*acc_lo, lo);
+ *acc_lo = _mm_add_epi16(*acc_lo, lo);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // This is REALLY clever. Since the product results from
+ // two 16-bit components, one positive and one negative,
+ // we don't have to worry about carrying the 1 (we can
+ // only borrow) past 32-bits. So we can just add it here.
+ hi = _mm_sub_epi16(hi, overflow_mask);
+
+ // Check for overflow of the upper sum.
+ overflow_mask = _mm_adds_epu16(*acc_md, hi);
+ *acc_md = _mm_add_epi16(*acc_md, hi);
+
+ overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
+ overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
+
+ // Finish up the accumulation of the... accumulator.
+ *acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15));
+ *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
+#ifdef INTENSE_DEBUG
+ auto ret = rsp_uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero);
+ for (unsigned i = 0; i < 8; i++)
+ fprintf(stderr, "VD[%u] = %d\n", i, reinterpret_cast(&ret)[i]);
+ return ret;
+#else
+ return rsp_uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero);
+#endif
+ }
+
+ // VMUDN
+ else
+ {
+ *acc_lo = lo;
+ *acc_md = hi;
+ *acc_hi = _mm_srai_epi16(hi, 15);
+
+ return lo;
+ }
+}
diff --git a/parallel-rsp/arch/simd/rsp/vor.h b/parallel-rsp/arch/simd/rsp/vor.h
new file mode 100644
index 0000000..dd46883
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vor.h
@@ -0,0 +1,17 @@
+//
+// arch/x86_64/rsp/vor.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vor(__m128i vs, __m128i vt)
+{
+ return _mm_or_si128(vs, vt);
+}
+
+static inline __m128i rsp_vnor(__m128i vs, __m128i vt)
+{
+ __m128i vd = _mm_or_si128(vs, vt);
+ return _mm_xor_si128(vd, _mm_set1_epi32(0xffffffffu));
+}
diff --git a/parallel-rsp/arch/simd/rsp/vrcpsq.h b/parallel-rsp/arch/simd/rsp/vrcpsq.h
new file mode 100644
index 0000000..38a2feb
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vrcpsq.h
@@ -0,0 +1,81 @@
+//
+// arch/x86_64/rsp/vrcpsq.c
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "../../../rsp/reciprocal.h"
+
+template
+inline __m128i rsp_vrcp_vrsq(RSP::CPUState *rsp, int dp, unsigned src, unsigned e, unsigned dest, unsigned de)
+{
+ uint32_t dp_input, sp_input;
+ int32_t input, result;
+
+ int16_t vt;
+
+ int32_t input_mask, data;
+ unsigned shift, idx;
+
+ // Get the element from VT.
+ vt = rsp->cp2.regs[src].e[e & 0x7];
+
+ dp_input = ((uint32_t)rsp->cp2.div_in << 16) | (uint16_t)vt;
+ sp_input = vt;
+
+ input = (dp) ? dp_input : sp_input;
+ input_mask = input >> 31;
+ data = input ^ input_mask;
+
+ if (input > -32768)
+ data -= input_mask;
+
+ // Handle edge cases.
+ if (data == 0)
+ result = 0x7fffFFFFU;
+
+ else if (input == -32768)
+ result = 0xffff0000U;
+
+ // Main case: compute the reciprocal.
+ else
+ {
+
+ // TODO: Clean this up.
+#ifdef _MSC_VER
+ unsigned long bsf_index;
+ _BitScanReverse(&bsf_index, data);
+ shift = 31 - bsf_index;
+#else
+ shift = __builtin_clz(data);
+#endif
+
+ // VRSQ
+ if (VRSQ)
+ {
+ idx = (((unsigned long long)data << shift) & 0x7FC00000U) >> 22;
+ idx = ((idx | 0x200) & 0x3FE) | (shift % 2);
+ result = rsp_reciprocal_rom[idx];
+
+ result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1);
+ }
+
+ // VRCP
+ else
+ {
+ idx = (((unsigned long long)data << shift) & 0x7FC00000U) >> 22;
+ result = rsp_reciprocal_rom[idx];
+
+ result = ((0x10000 | result) << 14) >> (31 - shift);
+ }
+
+ result = result ^ input_mask;
+ }
+
+ // Write out the results.
+ rsp->cp2.div_out = result >> 16;
+ rsp->cp2.regs[dest].e[de & 0x7] = result;
+
+ return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vrsq.h b/parallel-rsp/arch/simd/rsp/vrsq.h
new file mode 100644
index 0000000..7ffad6e
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vrsq.h
@@ -0,0 +1,93 @@
+//
+// arch/x86_64/rsp/vrsq.c
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "../../../rsp/reciprocal.h"
+#include
+
+// Mask table for vrsq(LH) functions.
+alignas(16) static const uint16_t vrsq_mask_table[8][8] = {
+ { 0xffff, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0xffff, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0xffff, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0xffff, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0xffff, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0xffff, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0xffff, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0xffff }
+};
+
+inline __m128i rsp_vrsq(RSP::CPUState *rsp, int dp, unsigned src, unsigned e, unsigned dest, unsigned de)
+{
+ uint32_t dp_input, sp_input;
+ int32_t input, result;
+ int16_t vt;
+
+ int32_t input_mask, data;
+ unsigned shift, idx;
+
+ // Get the element from VT.
+ vt = rsp->cp2.regs[src].e[e & 0x7];
+
+ dp_input = ((uint32_t)rsp->cp2.div_in << 16) | (uint16_t)vt;
+ sp_input = vt;
+
+ input = (dp) ? dp_input : sp_input;
+ input_mask = input >> 31;
+ data = input ^ input_mask;
+
+ if (input > -32768)
+ data -= input_mask;
+
+ // Handle edge cases.
+ if (data == 0)
+ result = 0x7fffFFFFU;
+
+ else if (input == -32768)
+ result = 0xffff0000U;
+
+ // Main case: compute the reciprocal.
+ else
+ {
+
+ //TODO: Clean this up.
+#ifdef _MSC_VER
+ unsigned long bsf_index;
+ _BitScanReverse(&bsf_index, data);
+ shift = 31 - bsf_index;
+#else
+ shift = __builtin_clz(data);
+#endif
+
+ idx = (((unsigned long long)data << shift) & 0x7FC00000U) >> 22;
+ idx = ((idx | 0x200) & 0x3FE) | (shift % 2);
+ result = rsp_reciprocal_rom[idx];
+
+ result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1);
+ result = result ^ input_mask;
+ }
+
+ // Write out the results.
+ rsp->cp2.div_out = result >> 16;
+ rsp->cp2.regs[dest].e[de & 0x7] = result;
+
+ return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
+}
+
+inline __m128i rsp_vrsqh(RSP::CPUState *rsp, unsigned src, unsigned e, unsigned dest, unsigned de)
+{
+ __m128i vd, vd_mask, b_result;
+
+ int16_t elements[8];
+
+ // Get the element from VT.
+ memcpy(elements, rsp->cp2.regs + src, sizeof(elements));
+ rsp->cp2.div_in = elements[e];
+
+ // Write out the upper part of the result.
+ vd_mask = _mm_load_si128((__m128i *)vrsq_mask_table[de]);
+ vd = _mm_load_si128((__m128i *)(rsp->cp2.regs + dest));
+ vd = _mm_andnot_si128(vd_mask, vd);
+
+ b_result = _mm_set1_epi16(rsp->cp2.div_out);
+ b_result = _mm_and_si128(vd_mask, b_result);
+ return _mm_or_si128(b_result, vd);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vsub.h b/parallel-rsp/arch/simd/rsp/vsub.h
new file mode 100644
index 0000000..a4f9f6f
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vsub.h
@@ -0,0 +1,23 @@
+//
+// arch/x86_64/rsp/vsub.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vsub(__m128i vs, __m128i vt, __m128i carry, __m128i *acc_lo)
+{
+ __m128i unsat_diff, sat_diff, overflow, vd;
+
+ // acc_lo uses saturated arithmetic.
+ unsat_diff = _mm_sub_epi16(vt, carry);
+ sat_diff = _mm_subs_epi16(vt, carry);
+
+ *acc_lo = _mm_sub_epi16(vs, unsat_diff);
+ vd = _mm_subs_epi16(vs, sat_diff);
+
+ // VD is the signed diff of the two sources and the carry. Since we
+ // have to saturate the diff of all three, we have to be clever.
+ overflow = _mm_cmpgt_epi16(sat_diff, unsat_diff);
+ return _mm_adds_epi16(vd, overflow);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vsubc.h b/parallel-rsp/arch/simd/rsp/vsubc.h
new file mode 100644
index 0000000..7271774
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vsubc.h
@@ -0,0 +1,20 @@
+//
+// arch/x86_64/rsp/vsubc.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vsubc(__m128i vs, __m128i vt, __m128i zero, __m128i *eq, __m128i *sn)
+{
+ __m128i equal, sat_udiff, sat_udiff_zero;
+
+ sat_udiff = _mm_subs_epu16(vs, vt);
+ equal = _mm_cmpeq_epi16(vs, vt);
+ sat_udiff_zero = _mm_cmpeq_epi16(sat_udiff, zero);
+
+ *eq = _mm_cmpeq_epi16(equal, zero);
+ *sn = _mm_andnot_si128(equal, sat_udiff_zero);
+
+ return _mm_sub_epi16(vs, vt);
+}
diff --git a/parallel-rsp/arch/simd/rsp/vxor.h b/parallel-rsp/arch/simd/rsp/vxor.h
new file mode 100644
index 0000000..452dc96
--- /dev/null
+++ b/parallel-rsp/arch/simd/rsp/vxor.h
@@ -0,0 +1,17 @@
+//
+// arch/x86_64/rsp/vxor.h
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+static inline __m128i rsp_vxor(__m128i vs, __m128i vt)
+{
+ return _mm_xor_si128(vs, vt);
+}
+
+static inline __m128i rsp_vnxor(__m128i vs, __m128i vt)
+{
+ __m128i vd = _mm_xor_si128(vs, vt);
+ return _mm_xor_si128(vd, _mm_set1_epi32(0xffffffffu));
+}
diff --git a/parallel-rsp/build_android_aarch64.sh b/parallel-rsp/build_android_aarch64.sh
new file mode 100755
index 0000000..388774d
--- /dev/null
+++ b/parallel-rsp/build_android_aarch64.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+if [ -z $ANDROID_HOME ]; then
+ echo "Please define ANDROID_HOME environment variable to where Android SDK is installed, usually ~/Android/Sdk."
+ exit 1
+fi
+
+mkdir -p build-android-aarch64
+cd build-android-aarch64
+cmake .. -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk-bundle/build/cmake/android.toolchain.cmake" \
+ -DANDROID_ABI=arm64-v8a \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DANDROID_PLATFORM=android-26 \
+ -DPARALLEL_RSP_DEBUG_JIT=OFF
+cmake --build . --parallel
+cd ..
diff --git a/parallel-rsp/build_native.sh b/parallel-rsp/build_native.sh
new file mode 100755
index 0000000..b952e77
--- /dev/null
+++ b/parallel-rsp/build_native.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+mkdir -p build-native
+cd build-native
+cmake .. -DCMAKE_BUILD_TYPE=Release -DPARALLEL_RSP_DEBUG_JIT=OFF
+cmake --build . --parallel
+cd ..
diff --git a/parallel-rsp/compare_test_results.sh b/parallel-rsp/compare_test_results.sh
new file mode 100755
index 0000000..e9fc7bd
--- /dev/null
+++ b/parallel-rsp/compare_test_results.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+./build_android_aarch64.sh || exit 1
+cd build-android-aarch64
+echo "Running Android test suite ..."
+ctest --no-label-summary --verbose >android-aarch64.log || exit 1
+cd ..
+
+./build_native.sh || exit 1
+cd build-native
+echo "Running native test suite ..."
+ctest --no-label-summary --verbose >native.log || exit 1
+cd ..
+
+echo "Comparing output ..."
+echo "=============================="
+diff -Naur build-native/native.log build-android-aarch64/android-aarch64.log
+echo "=============================="
diff --git a/parallel-rsp/cpu_state.hpp b/parallel-rsp/cpu_state.hpp
new file mode 100644
index 0000000..1b07bc1
--- /dev/null
+++ b/parallel-rsp/cpu_state.hpp
@@ -0,0 +1,5 @@
+#ifndef RSP_CPU_STATE_HPP
+#define RSP_CPU_STATE_HPP
+
+
+#endif
\ No newline at end of file
diff --git a/parallel-rsp/debug-toolchain/Makefile b/parallel-rsp/debug-toolchain/Makefile
new file mode 100644
index 0000000..745e28e
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/Makefile
@@ -0,0 +1,6 @@
+RSP_TEST = main
+
+PROGRAM = $(RSP_TEST)
+MIPS_OBJ = $(RSP_TEST).o
+
+include Makefile.mips
diff --git a/parallel-rsp/debug-toolchain/Makefile.mips b/parallel-rsp/debug-toolchain/Makefile.mips
new file mode 100644
index 0000000..36f2d41
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/Makefile.mips
@@ -0,0 +1,40 @@
+####
+## Basic Makefile for RSP-MIPS
+##
+######
+
+TARGET_ELF = $(PROGRAM).elf
+TARGET_BIN = $(PROGRAM).bin
+TARGET_GLOBAL_BIN = $(PROGRAM).global.bin
+MIPS_LD_SCRIPT = rsp-mips.ld
+
+MIPS_OBJCOPY = mipsel-linux-gnu-objcopy
+MIPS_CC = mipsel-linux-gnu-gcc
+MIPS_AS = mipsel-linux-gnu-as
+MIPS_LD = mipsel-linux-gnu-ld
+CRT_OBJ = start.o rsp-mips.o
+
+all: $(TARGET_BIN) $(TARGET_GLOBAL_BIN)
+
+crt-obj: $(CRT_OBJ)
+
+$(TARGET_BIN): $(TARGET_ELF)
+ $(MIPS_OBJCOPY) -j .text $< $(TARGET_BIN) -O binary
+
+$(TARGET_GLOBAL_BIN): $(TARGET_ELF)
+ $(MIPS_OBJCOPY) -j .data $< $(TARGET_GLOBAL_BIN) -O binary
+
+$(TARGET_ELF): $(MIPS_OBJ) $(CRT_OBJ)
+ $(MIPS_LD) -T $(MIPS_LD_SCRIPT) -o $@ $(CRT_OBJ) $(MIPS_OBJ) -EB
+
+%.o: %.s
+ $(MIPS_AS) -o $@ $< -EB -mabi=eabi -march=mips1
+
+%.o: %.c rsp-mips.h
+ $(MIPS_CC) -c -o $@ $< -Os -EB -march=mips1 -mabi=eabi -mno-abicalls -std=gnu99 -nostdlib
+
+clean:
+ rm -f $(MIPS_OBJ) $(CRT_OBJ) $(TARGET_ELF) $(TARGET_HEX) $(TARGET_GLOBAL_HEX) $(TARGET_BIN) $(TARGET_GLOBAL_BIN)
+
+.PHONY: all clean tools
+
diff --git a/parallel-rsp/debug-toolchain/add.s b/parallel-rsp/debug-toolchain/add.s
new file mode 100644
index 0000000..e62e1ce
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/add.s
@@ -0,0 +1,13 @@
+.text
+.global main
+main:
+ li $t0, 40
+ li $t1, -20
+ add $t2, $t0, $t1
+ addu $t3, $t0, $t1
+
+ li $t0, -5
+ li $t1, -4
+ add $t2, $t0, $t1
+ addu $t3, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/addi.s b/parallel-rsp/debug-toolchain/addi.s
new file mode 100644
index 0000000..e8f80db
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/addi.s
@@ -0,0 +1,9 @@
+.text
+.global main
+main:
+ li $a0, 17
+ addi $t0, $a0, -8
+ addi $t1, $a0, 8
+ addiu $t2, $a0, -8
+ addiu $t3, $a0, 8
+ break
diff --git a/parallel-rsp/debug-toolchain/and.s b/parallel-rsp/debug-toolchain/and.s
new file mode 100644
index 0000000..4b95e09
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/and.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, 17
+ li $t1, 5
+ and $t2, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/andi.s b/parallel-rsp/debug-toolchain/andi.s
new file mode 100644
index 0000000..57efbec
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/andi.s
@@ -0,0 +1,6 @@
+.text
+.global main
+main:
+ li $a0, -1
+ andi $t0, $a0, 50000
+ break
diff --git a/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-both-taken.s b/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-both-taken.s
new file mode 100644
index 0000000..c129979
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-both-taken.s
@@ -0,0 +1,20 @@
+# This works on the Lightning JIT, but hangs the reference.
+
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ li $t1, 1
+ li $t2, 2
+ li $t3, 0
+ beq $t0, $t1, taken0 # This will be taken.
+ beq $t0, $t1, taken1 # This will also be taken.
+ li $t3, 3 # This will not be executed.
+
+taken0:
+ li $t6, 5 # This will be executed, the second branch then kicks in and runs taken1 path.
+ break
+taken1:
+ li $t4, 4 # This will be executed.
+ break
diff --git a/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-first-taken.s b/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-first-taken.s
new file mode 100644
index 0000000..483c49d
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-first-taken.s
@@ -0,0 +1,18 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ li $t1, 1
+ li $t2, 2
+ li $t3, 0
+ beq $t0, $t1, taken0 # This will be taken.
+ beq $t0, $t2, taken1 # Will not be taken.
+ li $t3, 3
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-second-taken.s b/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-second-taken.s
new file mode 100644
index 0000000..138c5be
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/beq-impossible-delay-slot-second-taken.s
@@ -0,0 +1,18 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ li $t1, 1
+ li $t2, 2
+ li $t3, 0
+ beq $t0, $t2, taken0 # This will not be taken, should be ignored.
+ beq $t0, $t1, taken1 # This will be taken.
+ li $t3, 3
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bgez.s b/parallel-rsp/debug-toolchain/bgez.s
new file mode 100644
index 0000000..da0a27b
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bgez.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, -1
+ bgez $t0, taken1 # This will not be taken.
+ li $t2, 10
+
+ li $t0, 0
+ bgez $t0, taken1 # This will be taken.
+ li $t2, 20
+
+ li $t0, 1
+ bgez $t0, taken1 # This will be taken.
+ li $t2, 30
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bgezal.s b/parallel-rsp/debug-toolchain/bgezal.s
new file mode 100644
index 0000000..0b71f01
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bgezal.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, -1
+ bgezal $t0, taken1 # This will not be taken.
+ li $t2, 10
+
+ li $t0, 0
+ bgezal $t0, taken1 # This will be taken.
+ li $t2, 20
+
+ li $t0, 1
+ bgezal $t0, taken1 # This will be taken.
+ li $t2, 30
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bgtz.s b/parallel-rsp/debug-toolchain/bgtz.s
new file mode 100644
index 0000000..5f7f9fe
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bgtz.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, -1
+ bgtz $t0, taken1 # This will not be taken.
+ li $t2, 10
+
+ li $t0, 0
+ bgtz $t0, taken1 # This will not be taken.
+ li $t2, 20
+
+ li $t0, 1
+ bgtz $t0, taken1 # This will be taken.
+ li $t2, 30
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/blez.s b/parallel-rsp/debug-toolchain/blez.s
new file mode 100644
index 0000000..bcb583b
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/blez.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ blez $t0, taken1 # This will not be taken.
+ li $t2, 10
+
+ li $t0, 0
+ blez $t0, taken1 # This will be taken.
+ li $t2, 20
+
+ li $t0, 0
+ blez $t0, taken1 # This will be taken.
+ li $t2, 30
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bltz.s b/parallel-rsp/debug-toolchain/bltz.s
new file mode 100644
index 0000000..f931233
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bltz.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ bltz $t0, taken1 # This will not be taken.
+ li $t2, 10
+
+ li $t0, 0
+ bltz $t0, taken1 # This will not be taken.
+ li $t2, 20
+
+ li $t0, -1
+ bltz $t0, taken1 # This will be taken.
+ li $t2, 30
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bltzal.s b/parallel-rsp/debug-toolchain/bltzal.s
new file mode 100644
index 0000000..8d096e4
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bltzal.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ bltzal $t0, taken1 # This will not be taken.
+ li $t2, 10
+
+ li $t0, 0
+ bltzal $t0, taken1 # This will not be taken.
+ li $t2, 20
+
+ li $t0, -1
+ bltzal $t0, taken1 # This will be taken.
+ li $t2, 30
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bne.s b/parallel-rsp/debug-toolchain/bne.s
new file mode 100644
index 0000000..aab8d85
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bne.s
@@ -0,0 +1,20 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ li $t1, 1
+ li $t2, 2
+ li $t3, 0
+ bne $t0, $t1, taken0 # This will not be taken.
+ nop
+
+ bne $t0, $t2, taken1 # Will be taken.
+ li $t3, 3
+
+taken0:
+ li $t4, 5
+ break
+taken1:
+ li $t4, 4
+ break
diff --git a/parallel-rsp/debug-toolchain/bug-shl-into-branch.s b/parallel-rsp/debug-toolchain/bug-shl-into-branch.s
new file mode 100644
index 0000000..98972bb
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/bug-shl-into-branch.s
@@ -0,0 +1,15 @@
+.text
+.global main
+main:
+ li $t1, ((0x50000000) << 5) & 0xffffffff
+ li $t0, 0x50000000
+ sll $t0, $t0, 5
+ bne $t0, $t1, error
+ nop
+
+ li $t2, 1
+ break
+
+error:
+ li $t2, 2
+ break
diff --git a/parallel-rsp/debug-toolchain/cop0.s b/parallel-rsp/debug-toolchain/cop0.s
new file mode 100644
index 0000000..3342545
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/cop0.s
@@ -0,0 +1,14 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 100
+ mtc0 $t0, $1
+ bgez $t0, bar
+ mfc0 $t1, $1
+ li $t1, 200 # Should not execute.
+ break
+
+bar:
+ li $t2, 400
+ break
diff --git a/parallel-rsp/debug-toolchain/cop2-basic.s b/parallel-rsp/debug-toolchain/cop2-basic.s
new file mode 100644
index 0000000..e44afea
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/cop2-basic.s
@@ -0,0 +1,16 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 10
+ li $t2, 10
+ nop
+ .word (0x12 << 26) | (4 << 21) | (2 << 11) | (8 << 16) | (4 << 7)
+ .word (0x12 << 26) | (0 << 21) | (2 << 11) | (9 << 16) | (4 << 7)
+ #mtc2 $t0, $2, 4
+ #mfc2 $t1, $2, 4
+
+ ctc2 $t2, $2
+ cfc2 $t3, $2
+
+ break
diff --git a/parallel-rsp/debug-toolchain/cop2-ls.s b/parallel-rsp/debug-toolchain/cop2-ls.s
new file mode 100644
index 0000000..81f4a00
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/cop2-ls.s
@@ -0,0 +1,15 @@
+.data
+buffer:
+.hword 10, 20, 30, 40, 50, 60, 70, 80
+.hword 20, 30, 40, 50, 60, 70, 80, 90
+
+.text
+.set noreorder
+.global main
+main:
+ la $t0, buffer
+ # lqv 2, 0, 1(t0)
+ .word (0x32 << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (1 << 0) | (8 << 21)
+ # sqv 2, 0, 2(t0)
+ .word (0x3a << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (2 << 0) | (8 << 21)
+ break
diff --git a/parallel-rsp/debug-toolchain/cop2-vector.s b/parallel-rsp/debug-toolchain/cop2-vector.s
new file mode 100644
index 0000000..68792c8
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/cop2-vector.s
@@ -0,0 +1,18 @@
+.data
+buffer:
+.hword 10, 20, 30, 40, 50, 60, 70, 80
+.hword 20, 30, 40, 50, 60, 70, 80, 90
+
+.text
+.set noreorder
+.global main
+main:
+ la $t0, buffer
+ # lqv 2, 0, 0(t0)
+ .word (0x32 << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (0 << 0) | (8 << 21)
+ # lqv 3, 0, 1(t0)
+ .word (0x32 << 26) | (4 << 11) | (3 << 16) | (0 << 7) | (1 << 0) | (8 << 21)
+
+ .word (0x25 << 25) | (4 << 6) | (2 << 11) | (3 << 16) | (17 << 0) | (0 << 21)
+ # vsub v4, v2, v3, 0
+ break
diff --git a/parallel-rsp/debug-toolchain/delay-slot-before-break.s b/parallel-rsp/debug-toolchain/delay-slot-before-break.s
new file mode 100644
index 0000000..f1e1dfe
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/delay-slot-before-break.s
@@ -0,0 +1,15 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ blez $t0, foo
+ break
+
+ nop
+ nop
+ nop
+ nop
+
+foo:
+ break
diff --git a/parallel-rsp/debug-toolchain/delay-slot-before-new-block-illegal.s b/parallel-rsp/debug-toolchain/delay-slot-before-new-block-illegal.s
new file mode 100644
index 0000000..f1c7dcf
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/delay-slot-before-new-block-illegal.s
@@ -0,0 +1,21 @@
+.text
+.set noreorder
+.global main
+.align 10
+main:
+ li $t0, 1
+ .rept 126
+ nop
+ .endr
+ bgtz $t0, foobar
+ # New block begins here,
+ j foobar2
+ li $t2, 2 # This should not execute
+
+foobar:
+ li $t3, 3 # This should execute, then we move to foobar2
+ break
+
+foobar2:
+ li $t4, 4 # This executes.
+ break
diff --git a/parallel-rsp/debug-toolchain/delay-slot-before-new-block-not-taken.s b/parallel-rsp/debug-toolchain/delay-slot-before-new-block-not-taken.s
new file mode 100644
index 0000000..9d814e6
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/delay-slot-before-new-block-not-taken.s
@@ -0,0 +1,19 @@
+.text
+.set noreorder
+.global main
+.align 10
+main:
+ li $t0, 0
+ .rept 126
+ nop
+ .endr
+ bgtz $t0, foobar
+ # New block begins here,
+ # last instruction will be bgtz which needs to promote its delay slot
+ # into a new block.
+ # First instruction of any block have to handle potential latent delay slots like these.
+ li $t1, 1
+ li $t2, 2 # This should execute
+
+foobar:
+ break
diff --git a/parallel-rsp/debug-toolchain/delay-slot-before-new-block.s b/parallel-rsp/debug-toolchain/delay-slot-before-new-block.s
new file mode 100644
index 0000000..25ed563
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/delay-slot-before-new-block.s
@@ -0,0 +1,19 @@
+.text
+.set noreorder
+.global main
+.align 10
+main:
+ li $t0, 1
+ .rept 126
+ nop
+ .endr
+ bgtz $t0, foobar
+ # New block begins here,
+ # last instruction will be bgtz which needs to promote its delay slot
+ # into a new block.
+ # First instruction of any block have to handle potential latent delay slots like these.
+ li $t1, 1
+ li $t2, 2 # This should not execute
+
+foobar:
+ break
diff --git a/parallel-rsp/debug-toolchain/j.s b/parallel-rsp/debug-toolchain/j.s
new file mode 100644
index 0000000..44fdeb7
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/j.s
@@ -0,0 +1,20 @@
+.text
+.set noreorder
+.global main
+main:
+ j indelay
+ nop
+
+ j die # Test to make sure this becomes a conditional branch.
+
+indelay:
+ j notdie
+ li $t0, 1
+
+die:
+ li $t0, 0x10000
+
+notdie:
+ li $t1, 2
+ break
+
diff --git a/parallel-rsp/debug-toolchain/jal-into-indirect-delay-slot.s b/parallel-rsp/debug-toolchain/jal-into-indirect-delay-slot.s
new file mode 100644
index 0000000..52ee0e0
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/jal-into-indirect-delay-slot.s
@@ -0,0 +1,19 @@
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ bgtz $0, dummy
+ jal callsite
+ li $t5, 10
+
+ jr $s5
+callsite:
+ lw $t2, 184($0)
+ li $t1, 10
+ break
+
+dummy:
+ nop
+ break
+
diff --git a/parallel-rsp/debug-toolchain/jal.s b/parallel-rsp/debug-toolchain/jal.s
new file mode 100644
index 0000000..6ba23cc
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/jal.s
@@ -0,0 +1,21 @@
+.text
+.set noreorder
+.global main
+main:
+ jal indelay
+ nop
+
+ jal die # Test to make sure this becomes a conditional branch.
+
+indelay:
+ jal notdie
+ move $t2, $ra
+ li $t0, 1
+
+die:
+ li $t0, 0x10000
+
+notdie:
+ li $t1, 2
+ break
+
diff --git a/parallel-rsp/debug-toolchain/jalr.s b/parallel-rsp/debug-toolchain/jalr.s
new file mode 100644
index 0000000..fb87de6
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/jalr.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ la $t5, notdie
+ la $ra, indelay
+ jalr $a0, $ra
+ move $ra, $a0
+
+ j die # Test to make sure this becomes a conditional branch.
+
+indelay:
+ jalr $a0, $t5
+ move $t0, $a0
+
+die:
+ li $t0, 0x10000
+
+notdie:
+ li $t1, 2
+ break
+
diff --git a/parallel-rsp/debug-toolchain/jr.s b/parallel-rsp/debug-toolchain/jr.s
new file mode 100644
index 0000000..8d26cac
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/jr.s
@@ -0,0 +1,22 @@
+.text
+.set noreorder
+.global main
+main:
+ la $t5, notdie
+ la $ra, indelay
+ jr $ra
+ nop
+
+ j die # Test to make sure this becomes a conditional branch.
+
+indelay:
+ jr $t5
+ li $t0, 1
+
+die:
+ li $t0, 0x10000
+
+notdie:
+ li $t1, 2
+ break
+
diff --git a/parallel-rsp/debug-toolchain/lb.s b/parallel-rsp/debug-toolchain/lb.s
new file mode 100644
index 0000000..90ff5fd
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lb.s
@@ -0,0 +1,11 @@
+.data
+.byte 0, 0, 0
+foobar:
+.byte 0x72, 0x91
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lb $t0, 1($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lbu.s b/parallel-rsp/debug-toolchain/lbu.s
new file mode 100644
index 0000000..2c6a4a4
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lbu.s
@@ -0,0 +1,11 @@
+.data
+.byte 0, 0, 0
+foobar:
+.byte 0x72, 0x91
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lbu $t0, 1($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lh-unaligned.s b/parallel-rsp/debug-toolchain/lh-unaligned.s
new file mode 100644
index 0000000..31401c7
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lh-unaligned.s
@@ -0,0 +1,12 @@
+.data
+.byte 0, 0, 0, 0
+foobar:
+.byte 0
+.byte 0x92, 0x70
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lh $t0, 1($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lh.s b/parallel-rsp/debug-toolchain/lh.s
new file mode 100644
index 0000000..eae8a71
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lh.s
@@ -0,0 +1,11 @@
+.data
+.byte 0, 0, 0, 0
+foobar:
+.byte 0x92, 0x70
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lh $t0, 0($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lhu-unaligned.s b/parallel-rsp/debug-toolchain/lhu-unaligned.s
new file mode 100644
index 0000000..7ec62b5
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lhu-unaligned.s
@@ -0,0 +1,12 @@
+.data
+.byte 0, 0, 0, 0
+foobar:
+.byte 0
+.byte 0x92, 0x70
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lhu $t0, 1($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lhu.s b/parallel-rsp/debug-toolchain/lhu.s
new file mode 100644
index 0000000..20f2f1e
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lhu.s
@@ -0,0 +1,11 @@
+.data
+.byte 0, 0, 0, 0
+foobar:
+.byte 0x92, 0x70
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lhu $t0, 0($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lui.s b/parallel-rsp/debug-toolchain/lui.s
new file mode 100644
index 0000000..bfb79d6
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lui.s
@@ -0,0 +1,5 @@
+.text
+.global main
+main:
+ lui $t0, 50000
+ break
diff --git a/parallel-rsp/debug-toolchain/lw-unaligned-in-branch-delay.s b/parallel-rsp/debug-toolchain/lw-unaligned-in-branch-delay.s
new file mode 100644
index 0000000..eabe3a5
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lw-unaligned-in-branch-delay.s
@@ -0,0 +1,20 @@
+.data
+foo:
+.byte 0
+.byte 0xaa, 0xbb, 0xcc, 0xdd
+
+.text
+.set noreorder
+.global main
+main:
+ li $t0, 1
+ la $t1, foo
+ bgtz $t0, taken1
+ lw $t1, 1($t1)
+
+taken0:
+ li $t5, 100
+ break
+
+taken1:
+ break
diff --git a/parallel-rsp/debug-toolchain/lw-unaligned.s b/parallel-rsp/debug-toolchain/lw-unaligned.s
new file mode 100644
index 0000000..dc42013
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lw-unaligned.s
@@ -0,0 +1,15 @@
+.data
+.byte 0, 0, 0, 0
+foobar:
+.word 12345678
+.word 30
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lw $t0, 0($t1)
+ lw $t1, 1($t1)
+ lw $t2, 2($t1)
+ lw $t3, 3($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/lw.s b/parallel-rsp/debug-toolchain/lw.s
new file mode 100644
index 0000000..13c40a3
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/lw.s
@@ -0,0 +1,12 @@
+.data
+.byte 0, 0, 0, 0
+foobar:
+.word 12345678
+.word 30
+
+.text
+.global main
+main:
+ la $t1, foobar
+ lw $t0, 4($t1)
+ break
diff --git a/parallel-rsp/debug-toolchain/main.c b/parallel-rsp/debug-toolchain/main.c
new file mode 100644
index 0000000..9cce06c
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/main.c
@@ -0,0 +1,21 @@
+#include "rsp-mips.h"
+
+u8 data[4] = { 0x10, 0x20, 0x30, 0x40 };
+
+__attribute__((noinline))
+int load_byte(int i)
+{
+ return data[i];
+}
+
+int count = 3;
+
+int main(void)
+{
+ int res = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ res += load_byte(i);
+ }
+ rsp_debug_break(res, res, res, res);
+}
diff --git a/parallel-rsp/debug-toolchain/nor.s b/parallel-rsp/debug-toolchain/nor.s
new file mode 100644
index 0000000..74f30c7
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/nor.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, 17
+ li $t1, 5
+ nor $t2, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/or.s b/parallel-rsp/debug-toolchain/or.s
new file mode 100644
index 0000000..736c61f
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/or.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, 8
+ li $t1, 50
+ or $t2, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/ori.s b/parallel-rsp/debug-toolchain/ori.s
new file mode 100644
index 0000000..3b16501
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/ori.s
@@ -0,0 +1,6 @@
+.text
+.global main
+main:
+ li $a0, 500
+ ori $t0, $a0, 50000
+ break
diff --git a/parallel-rsp/debug-toolchain/rsp-mips.h b/parallel-rsp/debug-toolchain/rsp-mips.h
new file mode 100644
index 0000000..db6d8ab
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/rsp-mips.h
@@ -0,0 +1,17 @@
+#ifndef __RSP_MIPS_H
+#define __RSP_MIPS_H
+
+typedef signed char s8;
+typedef unsigned char u8;
+typedef signed short s16;
+typedef unsigned short u16;
+typedef signed int s32;
+typedef unsigned int u32;
+typedef signed long long s64;
+typedef unsigned long long u64;
+typedef u32 size_t;
+
+void rsp_break(void);
+void rsp_debug_break(u32 a, u32 b, u32 c, u32 d);
+
+#endif
diff --git a/parallel-rsp/debug-toolchain/rsp-mips.ld b/parallel-rsp/debug-toolchain/rsp-mips.ld
new file mode 100644
index 0000000..0e322e5
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/rsp-mips.ld
@@ -0,0 +1,9 @@
+SECTIONS {
+ ENTRY(rsp_mips_start)
+ . = 0x00400000;
+ .text : { start.o (.text); * (.text*); }
+
+ . = 0x00700000;
+ .data : { * (.data); * (.rodata*); * (.sbss); * (.scommon); }
+ .bss : { * (.bss); }
+}
diff --git a/parallel-rsp/debug-toolchain/rsp-mips.s b/parallel-rsp/debug-toolchain/rsp-mips.s
new file mode 100644
index 0000000..da47eda
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/rsp-mips.s
@@ -0,0 +1,20 @@
+.text
+.section .text
+
+.global rsp_break
+.ent rsp_break
+.type rsp_break, @function
+rsp_break:
+ break
+ jr $ra
+.end rsp_break
+.size rsp_break, .-rsp_break
+
+.global rsp_debug_break
+.ent rsp_debug_break
+.type rsp_debug_break, @function
+rsp_debug_break:
+ break
+ jr $ra
+.end rsp_debug_break
+.size rsp_debug_break, .-rsp_debug_break
diff --git a/parallel-rsp/debug-toolchain/sb.s b/parallel-rsp/debug-toolchain/sb.s
new file mode 100644
index 0000000..a98ace6
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sb.s
@@ -0,0 +1,21 @@
+.data
+foobar:
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+
+.text
+.global main
+main:
+ li $t0, 0xaabbccdd
+ la $t1, foobar
+ sb $t0, 0($t1)
+ sb $t0, 1($t1)
+ sb $t0, 3($t1)
+ break
+
diff --git a/parallel-rsp/debug-toolchain/sh-unaligned.s b/parallel-rsp/debug-toolchain/sh-unaligned.s
new file mode 100644
index 0000000..b3eabb1
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sh-unaligned.s
@@ -0,0 +1,20 @@
+.data
+foobar:
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+
+.text
+.global main
+main:
+ li $t0, 0xaabbccdd
+ la $t1, foobar
+ sh $t0, 0($t1)
+ sh $t0, 3($t1)
+ break
+
diff --git a/parallel-rsp/debug-toolchain/sh.s b/parallel-rsp/debug-toolchain/sh.s
new file mode 100644
index 0000000..c6cf3ee
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sh.s
@@ -0,0 +1,21 @@
+.data
+foobar:
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+
+.text
+.global main
+main:
+ li $t0, 0xaabbccdd
+ la $t1, foobar
+ sh $t0, 0($t1)
+ sh $t0, 2($t1)
+ sh $t0, 6($t1)
+ break
+
diff --git a/parallel-rsp/debug-toolchain/sll.s b/parallel-rsp/debug-toolchain/sll.s
new file mode 100644
index 0000000..2eed3ae
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sll.s
@@ -0,0 +1,6 @@
+.text
+.global main
+main:
+ li $t0, 40
+ sll $t0, $t0, 20
+ break
diff --git a/parallel-rsp/debug-toolchain/sllv.s b/parallel-rsp/debug-toolchain/sllv.s
new file mode 100644
index 0000000..ab27fb1
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sllv.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, 40
+ li $t1, 20
+ sllv $t0, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/slt.s b/parallel-rsp/debug-toolchain/slt.s
new file mode 100644
index 0000000..5b57f9e
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/slt.s
@@ -0,0 +1,12 @@
+.text
+.global main
+main:
+ li $a0, 17
+ li $a1, 5
+ li $a2, -17
+ li $a3, -5
+ slt $t0, $a0, $a1
+ slt $t1, $a3, $a0
+ slt $t2, $a2, $a3
+ slt $t3, $a2, $a1
+ break
diff --git a/parallel-rsp/debug-toolchain/slti.s b/parallel-rsp/debug-toolchain/slti.s
new file mode 100644
index 0000000..0ffc2de
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/slti.s
@@ -0,0 +1,10 @@
+.text
+.global main
+main:
+ li $a0, 100000
+ li $a1, -100000
+ slti $t0, $a0, -40
+ slti $t1, $a0, 40
+ slti $t2, $a1, -40
+ slti $t3, $a1, 40
+ break
diff --git a/parallel-rsp/debug-toolchain/sltiu.s b/parallel-rsp/debug-toolchain/sltiu.s
new file mode 100644
index 0000000..1d1d798
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sltiu.s
@@ -0,0 +1,10 @@
+.text
+.global main
+main:
+ li $a0, 100000
+ li $a1, -100000
+ sltiu $t0, $a0, -40
+ sltiu $t1, $a0, 40
+ sltiu $t2, $a1, -40
+ sltiu $t3, $a1, 40
+ break
diff --git a/parallel-rsp/debug-toolchain/sltu.s b/parallel-rsp/debug-toolchain/sltu.s
new file mode 100644
index 0000000..cd43b20
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sltu.s
@@ -0,0 +1,12 @@
+.text
+.global main
+main:
+ li $a0, 17
+ li $a1, 5
+ li $a2, -17
+ li $a3, -5
+ sltu $t0, $a0, $a1
+ sltu $t1, $a3, $a0
+ sltu $t2, $a2, $a3
+ sltu $t3, $a2, $a1
+ break
diff --git a/parallel-rsp/debug-toolchain/sra.s b/parallel-rsp/debug-toolchain/sra.s
new file mode 100644
index 0000000..ed2e58a
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sra.s
@@ -0,0 +1,6 @@
+.text
+.global main
+main:
+ li $t0, -15254
+ sra $t0, $t0, 20
+ break
diff --git a/parallel-rsp/debug-toolchain/srav.s b/parallel-rsp/debug-toolchain/srav.s
new file mode 100644
index 0000000..e4072b0
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/srav.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, -15254
+ li $t1, 20
+ srav $t0, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/srl.s b/parallel-rsp/debug-toolchain/srl.s
new file mode 100644
index 0000000..466c756
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/srl.s
@@ -0,0 +1,6 @@
+.text
+.global main
+main:
+ li $t0, -15254
+ srl $t0, $t0, 20
+ break
diff --git a/parallel-rsp/debug-toolchain/srlv.s b/parallel-rsp/debug-toolchain/srlv.s
new file mode 100644
index 0000000..33b6fb8
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/srlv.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, -15254
+ li $t1, 20
+ srlv $t0, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/start.s b/parallel-rsp/debug-toolchain/start.s
new file mode 100644
index 0000000..214ae7e
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/start.s
@@ -0,0 +1,28 @@
+###
+##
+# Entry point and setup for our RSP
+##
+
+.equ RAM_SIZE, 4096
+
+.text
+.align 2
+.section .text
+.global rsp_mips_start
+.extern main
+.ent rsp_mips_start
+.type rsp_mips_start, @function
+
+rsp_mips_start:
+ nop
+redo:
+ li $a0, 0 # argc = 0, it will never be used anyways on this stuff. :D
+ li $a1, 0 # argv = 0
+ li $sp, (0x00700000 + RAM_SIZE - 4) # Set up stack.
+
+ jal main
+ j redo
+
+.end rsp_mips_start
+.size rsp_mips_start, .-rsp_mips_start
+
diff --git a/parallel-rsp/debug-toolchain/sub.s b/parallel-rsp/debug-toolchain/sub.s
new file mode 100644
index 0000000..f898f41
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sub.s
@@ -0,0 +1,14 @@
+.text
+.global main
+main:
+ li $t0, 40
+ li $t1, -20
+ sub $t2, $t0, $t1
+ subu $t3, $t0, $t1
+
+ li $t0, -5
+ li $t1, -4
+ sub $t2, $t0, $t1
+ subu $t3, $t0, $t1
+
+ break
diff --git a/parallel-rsp/debug-toolchain/sw-unaligned.s b/parallel-rsp/debug-toolchain/sw-unaligned.s
new file mode 100644
index 0000000..044b5d7
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sw-unaligned.s
@@ -0,0 +1,22 @@
+.data
+foobar:
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+
+.text
+.global main
+main:
+ li $t0, 0xaabbccdd
+ la $t1, foobar
+ sw $t0, 0($t1)
+ sw $t0, 5($t1)
+ sw $t0, 10($t1)
+ sw $t0, 15($t1)
+ break
+
diff --git a/parallel-rsp/debug-toolchain/sw.s b/parallel-rsp/debug-toolchain/sw.s
new file mode 100644
index 0000000..ef4d8d5
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/sw.s
@@ -0,0 +1,21 @@
+.data
+foobar:
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+.word 0
+
+.text
+.global main
+main:
+ li $t0, 0xaabbccdd
+ la $t1, foobar
+ sw $t0, 0($t1)
+ sw $t0, 4($t1)
+ sw $t0, 12($t1)
+ break
+
diff --git a/parallel-rsp/debug-toolchain/unconditional-delay-slot-before-break.s b/parallel-rsp/debug-toolchain/unconditional-delay-slot-before-break.s
new file mode 100644
index 0000000..87660ae
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/unconditional-delay-slot-before-break.s
@@ -0,0 +1,14 @@
+.text
+.set noreorder
+.global main
+main:
+ jal foo
+ break
+
+ nop
+ nop
+ nop
+ nop
+
+foo:
+ break
diff --git a/parallel-rsp/debug-toolchain/xor.s b/parallel-rsp/debug-toolchain/xor.s
new file mode 100644
index 0000000..86a88c4
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/xor.s
@@ -0,0 +1,7 @@
+.text
+.global main
+main:
+ li $t0, 17
+ li $t1, 5
+ xor $t2, $t0, $t1
+ break
diff --git a/parallel-rsp/debug-toolchain/xori.s b/parallel-rsp/debug-toolchain/xori.s
new file mode 100644
index 0000000..bc7573a
--- /dev/null
+++ b/parallel-rsp/debug-toolchain/xori.s
@@ -0,0 +1,6 @@
+.text
+.global main
+main:
+ li $a0, 500
+ xori $t0, $a0, 50000
+ break
diff --git a/parallel-rsp/debug_jit.cpp b/parallel-rsp/debug_jit.cpp
new file mode 100644
index 0000000..c767240
--- /dev/null
+++ b/parallel-rsp/debug_jit.cpp
@@ -0,0 +1,94 @@
+#include "debug_jit.hpp"
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+namespace JIT
+{
+
+struct DebugBlock::Impl
+{
+ Impl() = default;
+ Impl(Impl &&) = delete;
+ void operator=(Impl &&) = delete;
+ ~Impl();
+
+ void *dylib = nullptr;
+ Func block = nullptr;
+ string name, soname;
+
+ bool compile(uint64_t hash, const std::string &source);
+};
+
+DebugBlock::DebugBlock(const unordered_map &)
+{
+}
+
+DebugBlock::~DebugBlock()
+{
+}
+
+DebugBlock::Impl::~Impl()
+{
+ if (dylib)
+ dlclose(dylib);
+
+ remove(soname.c_str());
+ remove(name.c_str());
+}
+
+bool DebugBlock::compile(uint64_t hash, const std::string &source)
+{
+ impl = unique_ptr(new Impl);
+ bool ret = impl->compile(hash, source);
+ if (ret)
+ block = impl->block;
+ return ret;
+}
+
+bool DebugBlock::Impl::compile(uint64_t hash, const std::string &source)
+{
+ name = "/tmp/";
+ name += to_string(hash);
+ soname = name;
+ name += ".c";
+ soname += ".so";
+
+ FILE *file = fopen(name.c_str(), "w");
+ if (!file)
+ return false;
+
+ fputs(source.c_str(), file);
+ fclose(file);
+
+ char command[256];
+ if (sizeof(size_t) == 8)
+ {
+ sprintf(command, "gcc -o %s %s -shared -fpic -O0 -g -std=c99 -Wl,--unresolved-symbols=ignore-all",
+ soname.c_str(),
+ name.c_str());
+ }
+ else if (sizeof(size_t) == 4)
+ {
+ sprintf(command, "gcc -m32 -o %s %s -shared -fpic -O0 -g -std=c99 -Wl,--unresolved-symbols=ignore-all",
+ soname.c_str(),
+ name.c_str());
+ }
+ int ret = system(command);
+ if (ret != 0)
+ return false;
+
+ dylib = dlopen(soname.c_str(), RTLD_LOCAL | RTLD_LAZY);
+ if (!dylib)
+ return false;
+
+ block = reinterpret_cast(dlsym(dylib, "block_entry"));
+ if (!dylib)
+ return false;
+ return true;
+}
+
+} // namespace JIT
diff --git a/parallel-rsp/debug_jit.hpp b/parallel-rsp/debug_jit.hpp
new file mode 100644
index 0000000..4c923e6
--- /dev/null
+++ b/parallel-rsp/debug_jit.hpp
@@ -0,0 +1,31 @@
+#ifndef DEBUG_JIT_HPP__
+#define DEBUG_JIT_HPP__
+
+#include
+#include
+#include
+#include
+
+namespace JIT
+{
+using Func = void (*)(void *, void *);
+class DebugBlock
+{
+public:
+ DebugBlock(const std::unordered_map &symbol_table);
+ ~DebugBlock();
+
+ bool compile(uint64_t hash, const std::string &source);
+ Func get_func() const
+ {
+ return block;
+ }
+
+private:
+ struct Impl;
+ std::unique_ptr impl;
+ Func block = nullptr;
+};
+} // namespace JIT
+
+#endif
diff --git a/parallel-rsp/debug_rsp.cpp b/parallel-rsp/debug_rsp.cpp
new file mode 100644
index 0000000..7545937
--- /dev/null
+++ b/parallel-rsp/debug_rsp.cpp
@@ -0,0 +1,1433 @@
+#include "debug_rsp.hpp"
+#include "rsp_disasm.hpp"
+#include
+
+using namespace std;
+
+#define TRACE
+
+extern "C"
+{
+#ifdef INTENSE_DEBUG
+ static uint64_t hash_imem(const uint8_t *data, size_t size)
+ {
+ uint64_t h = 0xcbf29ce484222325ull;
+ size_t i;
+ for (i = 0; i < size; i++)
+ h = (h * 0x100000001b3ull) ^ data[i];
+
+ if (h == BREAKVAL)
+ breakme();
+
+ return h;
+ }
+
+ void RSP_DEBUG(RSP::CPUState *rsp, const char *tag, unsigned pc, unsigned value)
+ {
+ uint64_t hash = hash_imem((const uint8_t *)rsp->cp2.regs, sizeof(rsp->cp2.regs));
+ fprintf(DUMP_FILE, "%s (PC: %u): %u, %llu\n", tag, pc, value, hash);
+ if (value)
+ fprintf(DUMP_FILE, " DMEM HASH: 0x%016llx\n", hash_imem((const uint8_t *)rsp->dmem, 0x1000));
+ }
+#endif
+}
+
+namespace RSP
+{
+CPU::CPU()
+#ifndef DEBUG_JIT
+ : jit_engine(symbol_table)
+#endif
+{
+ init_symbol_table();
+}
+
+CPU::~CPU()
+{
+}
+
+void CPU::init_symbol_table()
+{
+#define S(sym) symbol_table["RSP_" #sym] = reinterpret_cast(RSP_##sym)
+ S(EXIT);
+ S(CALL);
+ S(RETURN);
+ S(REPORT_PC);
+
+#ifdef INTENSE_DEBUG
+ S(DEBUG);
+#endif
+ S(MFC0);
+ S(MTC0);
+
+ S(MTC2);
+ S(MFC2);
+ S(CFC2);
+ S(CTC2);
+
+ S(LBV);
+ S(LSV);
+ S(LLV);
+ S(LDV);
+ S(LQV);
+ S(LRV);
+ S(LPV);
+ S(LUV);
+ S(LHV);
+ S(LTV);
+
+ S(SBV);
+ S(SSV);
+ S(SLV);
+ S(SDV);
+ S(SQV);
+ S(SRV);
+ S(SPV);
+ S(SUV);
+ S(SHV);
+ S(SFV);
+ S(STV);
+
+ S(VMULF);
+ S(VMULU);
+ S(VMUDL);
+ S(VMUDM);
+ S(VMUDN);
+ S(VMUDH);
+ S(VMACF);
+ S(VMACU);
+ //S(VMACQ);
+ S(VMADL);
+ S(VMADM);
+ S(VMADN);
+ S(VMADH);
+ S(VADD);
+ S(VSUB);
+ S(VABS);
+ S(VADDC);
+ S(VSUBC);
+ S(VSAR);
+ S(VLT);
+ S(VEQ);
+ S(VNE);
+ S(VGE);
+ S(VCL);
+ S(VCH);
+ S(VCR);
+ S(VMRG);
+ S(VAND);
+ S(VNAND);
+ S(VOR);
+ S(VNOR);
+ S(VXOR);
+ S(VNXOR);
+ S(VRCP);
+ S(VRCPL);
+ S(VRCPH);
+ S(VMOV);
+ S(VRSQ);
+ S(VRSQL);
+ S(VRSQH);
+ S(VNOP);
+#undef S
+}
+
+void CPU::invalidate_imem()
+{
+ for (unsigned i = 0; i < CODE_BLOCKS; i++)
+ if (memcmp(cached_imem + i * CODE_BLOCK_WORDS, state.imem + i * CODE_BLOCK_WORDS, CODE_BLOCK_SIZE))
+ state.dirty_blocks |= (0x3 << i) >> 1;
+}
+
+void CPU::invalidate_code()
+{
+ if (!state.dirty_blocks)
+ return;
+
+ for (unsigned i = 0; i < CODE_BLOCKS; i++)
+ {
+ if (state.dirty_blocks & (1 << i))
+ {
+ memset(blocks + i * CODE_BLOCK_WORDS, 0, CODE_BLOCK_WORDS * sizeof(blocks[0]));
+ memcpy(cached_imem + i * CODE_BLOCK_WORDS, state.imem + i * CODE_BLOCK_WORDS, CODE_BLOCK_SIZE);
+ }
+ }
+
+ state.dirty_blocks = 0;
+}
+
+// Need super-fast hash here.
+uint64_t CPU::hash_imem(unsigned pc, unsigned count) const
+{
+ size_t size = count;
+
+ // FNV-1.
+ const auto *data = state.imem + pc;
+ uint64_t h = 0xcbf29ce484222325ull;
+ h = (h * 0x100000001b3ull) ^ pc;
+ h = (h * 0x100000001b3ull) ^ count;
+ for (size_t i = 0; i < size; i++)
+ h = (h * 0x100000001b3ull) ^ data[i];
+ return h;
+}
+
+unsigned CPU::analyze_static_end(unsigned pc, unsigned end)
+{
+ // Scans through IMEM and finds the logical "end" of the instruction stream.
+ unsigned max_static_pc = pc;
+ unsigned count = end - pc;
+
+ for (unsigned i = 0; i < count; i++)
+ {
+ uint32_t instr = state.imem[pc + i];
+ uint32_t type = instr >> 26;
+ uint32_t target;
+
+ bool forward_goto;
+ if (pc + i + 1 >= max_static_pc)
+ {
+ forward_goto = false;
+ max_static_pc = pc + i + 1;
+ }
+ else
+ forward_goto = true;
+
+ // VU
+ if ((instr >> 25) == 0x25)
+ continue;
+
+ switch (type)
+ {
+ case 000:
+ switch (instr & 63)
+ {
+ case 010:
+ // JR always terminates either by returning or exiting.
+ // We execute the next instruction via delay slot and exit.
+ // Unless we can branch past the JR
+ // (max_static_pc will be higher than expected),
+ // this will be the static end.
+ if (!forward_goto)
+ {
+ max_static_pc = max(pc + i + 2, max_static_pc);
+ goto end;
+ }
+ break;
+
+ case 015:
+ // BREAK always terminates.
+ if (!forward_goto)
+ goto end;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 001: // REGIMM
+ switch ((instr >> 16) & 31)
+ {
+ case 000: // BLTZ
+ case 001: // BGEZ
+ case 021: // BGEZAL
+ case 020: // BLTZAL
+ target = (pc + i + 1 + instr) & 0x3ff;
+ if (target >= pc && target < end) // goto
+ max_static_pc = max(max_static_pc, target + 1);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 002:
+ // J is resolved by goto.
+ target = instr & 0x3ff;
+ if (target >= pc && target < end) // goto
+ {
+ // J is a static jump, so if we aren't branching
+ // past this instruction and we're branching backwards,
+ // we can end the block here.
+ if (!forward_goto && target < end)
+ {
+ max_static_pc = max(pc + i + 2, max_static_pc);
+ goto end;
+ }
+ else
+ max_static_pc = max(max_static_pc, target + 1);
+ }
+ else if (!forward_goto)
+ {
+ // If we have static branch outside our block,
+ // we terminate the block.
+ max_static_pc = max(pc + i + 2, max_static_pc);
+ goto end;
+ }
+ break;
+
+ case 004: // BEQ
+ case 005: // BNE
+ case 006: // BLEZ
+ case 007: // BGTZ
+ target = (pc + i + 1 + instr) & 0x3ff;
+ if (target >= pc && target < end) // goto
+ max_static_pc = max(max_static_pc, target + 1);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+end:
+ unsigned ret = min(max_static_pc, end);
+ return ret;
+}
+
+Func CPU::jit_region(uint64_t hash, unsigned pc, unsigned count)
+{
+ full_code.clear();
+ body.clear();
+ full_code.reserve(16 * 1024);
+ body.reserve(16 * 1024);
+
+ // Local branch delays resolve to within the block, so we can use goto.
+ bool pending_local_branch_delay = false;
+ bool pending_branch_delay = false;
+ bool pending_call = false;
+ bool pending_indirect_call = false;
+ bool pending_return = false;
+
+ bool pipe_pending_local_branch_delay = false;
+ bool pipe_pending_branch_delay = false;
+ bool pipe_pending_call = false;
+ bool pipe_pending_indirect_call = false;
+ bool pipe_pending_return = false;
+
+ uint32_t branch_delay = 0;
+ uint32_t pipe_branch_delay = 0;
+ char buf[256];
+#define APPEND(...) \
+ do \
+ { \
+ sprintf(buf, __VA_ARGS__); \
+ body += buf; \
+ } while (0)
+#define APPEND_RD_NOT_R0(...) \
+ if (rd != 0) \
+ do \
+ { \
+ APPEND(__VA_ARGS__); \
+ } while (0)
+#define APPEND_RT_NOT_R0(...) \
+ if (rt != 0) \
+ do \
+ { \
+ APPEND(__VA_ARGS__); \
+ } while (0)
+
+#define DISASM(...) \
+ do \
+ { \
+ APPEND("// "); \
+ APPEND(__VA_ARGS__); \
+ } while (0)
+
+#define PIPELINE_BRANCH() \
+ do \
+ { \
+ pending_local_branch_delay = pipe_pending_local_branch_delay; \
+ pending_branch_delay = pipe_pending_branch_delay; \
+ pending_call = pipe_pending_call; \
+ pending_indirect_call = pipe_pending_indirect_call; \
+ pending_return = pipe_pending_return; \
+ branch_delay = pipe_branch_delay; \
+ pipe_pending_local_branch_delay = false; \
+ pipe_pending_branch_delay = false; \
+ pipe_pending_call = false; \
+ pipe_pending_indirect_call = false; \
+ pipe_pending_return = false; \
+ pipe_branch_delay = 0; \
+ APPEND("ADVANCE_DELAY_SLOT();\n"); \
+ } while (0)
+
+#define PROMOTE_LOCAL_DELAY_SLOT() \
+ do \
+ { \
+ APPEND("if (pipe_branch) {\n"); \
+ APPEND(" STATE->has_delay_slot = 1;\n"); \
+ APPEND(" STATE->branch_target = %u;\n", pipe_branch_delay * 4); \
+ APPEND("}\n"); \
+ } while (0)
+
+#define PROMOTE_DELAY_SLOT() \
+ do \
+ { \
+ if (pipe_pending_local_branch_delay) \
+ PROMOTE_LOCAL_DELAY_SLOT(); \
+ else if (pipe_pending_branch_delay) \
+ { \
+ APPEND(" PROMOTE_DELAY_SLOT();\n"); \
+ } \
+ } while (0)
+
+ // Statically checks if we need to handle branch delay slots.
+ // Only relevant if the last instruction did anything branch related.
+ // Double branch delays are technically undefined, but I assume it works like this.
+#define CHECK_BRANCH_DELAY() \
+ do \
+ { \
+ if (pending_call && !pipe_pending_local_branch_delay && !pipe_pending_branch_delay) \
+ { \
+ APPEND("if (LIKELY(branch)) {\n"); \
+ APPEND(" RSP_CALL(opaque, 0x%03x, 0x%03x);\n", branch_delay * 4, ((pc + i + 1) << 2) & (IMEM_SIZE - 1)); \
+ APPEND("}\n"); \
+ } \
+ else if (pending_indirect_call && !pipe_pending_local_branch_delay && !pipe_pending_branch_delay) \
+ { \
+ APPEND("if (LIKELY(branch)) {\n"); \
+ APPEND(" RSP_CALL(opaque, (branch_delay << 2) & %u, 0x%03x);\n", IMEM_SIZE - 1, \
+ ((pc + i + 1) << 2) & (IMEM_SIZE - 1)); \
+ APPEND("}\n"); \
+ } \
+ else if (pending_return && !pipe_pending_local_branch_delay && !pipe_pending_branch_delay) \
+ { \
+ APPEND("if (LIKELY(branch)) {\n"); \
+ APPEND(" if (RSP_RETURN(opaque, (branch_delay << 2) & %u)) return;\n", IMEM_SIZE - 1); \
+ APPEND(" STATE->pc = (branch_delay << 2) & %u;\n", IMEM_SIZE - 1); \
+ APPEND(" EXIT(MODE_CONTINUE);\n"); \
+ APPEND("}\n"); \
+ } \
+ else if (pending_local_branch_delay) \
+ { \
+ if (pipe_pending_local_branch_delay || pipe_pending_branch_delay) \
+ { \
+ APPEND("if (branch && pipe_branch) {\n"); \
+ APPEND(" STATE->pc = %u;\n", branch_delay * 4); \
+ APPEND(" PROMOTE_DELAY_SLOT();\n"); \
+ APPEND(" EXIT(MODE_CONTINUE);\n"); \
+ APPEND("} else if (branch) {\n"); \
+ APPEND(" goto pc_%03x;\n", branch_delay * 4); \
+ APPEND("}\n"); \
+ } \
+ else \
+ { \
+ APPEND("if (branch) goto pc_%03x;\n", branch_delay * 4); \
+ } \
+ } \
+ else if (pending_branch_delay) \
+ { \
+ APPEND("if (branch) {\n"); \
+ APPEND(" STATE->pc = (branch_delay << 2) & %u;\n", IMEM_SIZE - 1); \
+ PROMOTE_DELAY_SLOT(); \
+ APPEND(" EXIT(MODE_CONTINUE);\n"); \
+ APPEND("}\n"); \
+ } \
+ pending_call = false; \
+ pending_indirect_call = false; \
+ pending_return = false; \
+ pending_branch_delay = false; \
+ pending_local_branch_delay = false; \
+ } while (0)
+
+#define CHECK_INHERIT_BRANCH_DELAY() \
+ do \
+ { \
+ APPEND("if (UNLIKELY(STATE->has_delay_slot)) {\n"); \
+ APPEND(" STATE->pc = STATE->branch_target;\n"); \
+ APPEND(" STATE->has_delay_slot = 0;\n"); \
+ PROMOTE_DELAY_SLOT(); \
+ APPEND(" EXIT(MODE_CONTINUE);\n"); \
+ APPEND("}\n"); \
+ } while (0)
+
+#define EXIT_WITH_DELAY(mode) \
+ do \
+ { \
+ if (pending_local_branch_delay) \
+ { \
+ APPEND("STATE->pc = branch ? %u : %u;\n", branch_delay * 4, ((pc + i + 1) << 2) & (IMEM_SIZE - 1)); \
+ APPEND("EXIT(%s);\n", #mode); \
+ } \
+ else if (pending_branch_delay) \
+ { \
+ APPEND("STATE->pc = branch ? ((branch_delay << 2) & %u) : %u;\n", IMEM_SIZE - 1, \
+ ((pc + i + 1) << 2) & (IMEM_SIZE - 1)); \
+ APPEND("EXIT(%s);\n", #mode); \
+ } \
+ else \
+ { \
+ APPEND("if (UNLIKELY(STATE->has_delay_slot)) {\n"); \
+ APPEND(" STATE->pc = STATE->branch_target;\n"); \
+ APPEND(" STATE->has_delay_slot = 0;\n"); \
+ APPEND(" EXIT(%s);\n", #mode); \
+ APPEND("} else {\n"); \
+ APPEND(" STATE->pc = %u;\n", ((pc + i + 1) << 2) & (IMEM_SIZE - 1)); \
+ APPEND(" EXIT(%s);\n", #mode); \
+ APPEND("}\n"); \
+ } \
+ } while (0)
+
+ auto set_pc = [&](uint32_t next_pc) {
+ next_pc &= (IMEM_SIZE >> 2) - 1;
+ if (next_pc >= pc && next_pc < (pc + count))
+ {
+ pipe_pending_local_branch_delay = true;
+ pipe_branch_delay = next_pc;
+ }
+ else
+ {
+ pipe_pending_branch_delay = true;
+ pipe_branch_delay = next_pc;
+ APPEND("pipe_branch_delay = %u;\n", next_pc);
+ }
+ };
+
+ auto set_pc_indirect = [&](uint32_t reg) {
+ pipe_pending_branch_delay = true;
+ APPEND("BRANCH_INDIRECT((r%u & 0xfff) >> 2);\n", reg);
+ };
+
+ APPEND("unsigned branch = 0;\n");
+ APPEND("unsigned branch_delay = 0;\n");
+ APPEND("unsigned pipe_branch = 0;\n");
+ APPEND("unsigned pipe_branch_delay = 0;\n");
+ APPEND("unsigned cp0_result;\n");
+ APPEND("unsigned addr;\n");
+ APPEND("unsigned *dmem = STATE->dmem;\n");
+ for (unsigned i = 0; i < count; i++)
+ {
+ uint32_t instr = state.imem[pc + i];
+ APPEND("pc_%03x:\n", (pc + i) * 4);
+#ifdef TRACE
+ APPEND("RSP_REPORT_PC(STATE, %u, %u);\n", (pc + i) * 4, instr);
+#endif
+ PIPELINE_BRANCH();
+
+ uint32_t type = instr >> 26;
+ uint32_t rd, rs, rt, shift, imm;
+ int16_t simm;
+
+ if ((instr >> 25) == 0x25)
+ {
+ // VU instruction.
+ uint32_t op = instr & 63;
+ uint32_t vd = (instr >> 6) & 31;
+ uint32_t vs = (instr >> 11) & 31;
+ uint32_t vt = (instr >> 16) & 31;
+ uint32_t e = (instr >> 21) & 15;
+
+ static const char *ops[64] = {
+ "VMULF", "VMULU", nullptr, nullptr, "VMUDL", "VMUDM", "VMUDN", "VMUDH", "VMACF", "VMACU", nullptr,
+ nullptr, "VMADL", "VMADM", "VMADN", "VMADH", "VADD", "VSUB", nullptr, "VABS", "VADDC", "VSUBC",
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "VSAR", nullptr, nullptr, "VLT",
+ "VEQ", "VNE", "VGE", "VCL", "VCH", "VCR", "VMRG", "VAND", "VNAND", "VOR", "VNOR",
+ "VXOR", "VNXOR", nullptr, nullptr, "VRCP", "VRCPL", "VRCPH", "VMOV", "VRSQ", "VRSQL", "VRSQH",
+ "VNOP", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ };
+ auto vop = ops[op];
+ if (vop)
+ {
+ APPEND("RSP_%s(STATE, %u, %u, %u, %u);\n", vop, vd, vs, vt, e);
+ DISASM("%s v%u, v%u, v%u[%u]\n", vop, vd, vs, vt, e);
+ }
+ else
+ {
+ APPEND("RSP_RESERVED(STATE, %u, %u, %u, %u);\n", vd, vs, vt, e);
+ DISASM("RSP_RESERVED v%u, v%u, v%u[%u]\n", vd, vs, vt, e);
+ //fprintf(DUMP_FILE, "Unimplemented COP2 op %u.\n", op);
+ }
+
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"CP2\", %u, 0);\n", op);
+#endif
+ }
+ else
+ {
+ // Everything else.
+ switch (type)
+ {
+ case 000:
+ {
+ rd = (instr & 0xffff) >> 11;
+ rt = (instr >> 16) & 31;
+ shift = (instr >> 6) & 31;
+ rs = instr >> 21;
+
+ switch (instr & 63)
+ {
+ case 000: // SLL
+ APPEND_RD_NOT_R0("r%u = r%u << %u;\n", rd, rt, shift);
+
+ if (instr)
+ DISASM("sll %s, %s, %u\n", register_name(rd), register_name(rt), shift);
+ else
+ DISASM("nop\n");
+ break;
+
+ case 002: // SRL
+ APPEND_RD_NOT_R0("r%u = r%u >> %u;\n", rd, rt, shift);
+ DISASM("srl %s, %s, %u\n", register_name(rd), register_name(rt), shift);
+ break;
+
+ case 003: // SRA
+ APPEND_RD_NOT_R0("r%u = (int)r%u >> (int)%u;\n", rd, rt, shift);
+ DISASM("sra %s, %s, %u\n", register_name(rd), register_name(rt), shift);
+ break;
+
+ case 004: // SLLV
+ APPEND_RD_NOT_R0("r%u = r%u << MASK_SA(r%u);\n", rd, rt, rs);
+ DISASM("sllv %s, %s, $%u\n", register_name(rd), register_name(rt), rs);
+ break;
+
+ case 006: // SRLV
+ APPEND_RD_NOT_R0("r%u = r%u >> MASK_SA(r%u);\n", rd, rt, rs);
+ DISASM("srlv %s, %s, $%u\n", register_name(rd), register_name(rt), rs);
+ break;
+
+ case 007: // SRAV
+ APPEND_RD_NOT_R0("r%u = (int)r%u >> (int)MASK_SA(r%u);\n", rd, rt, rs);
+ DISASM("srav %s, %s, $%u\n", register_name(rd), register_name(rt), rs);
+ break;
+
+ case 011: // JALR
+ if (rd != 0)
+ {
+ APPEND("r%u = %u;\n", rd, ((pc + i + 2) << 2) & 0xffc);
+ }
+ set_pc_indirect(rs);
+ pipe_pending_indirect_call = true;
+ DISASM("jalr %s\n", register_name(rs));
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"JALR\", pipe_branch_delay * 4, 0);\n");
+#endif
+ break;
+ case 010: // JR
+ set_pc_indirect(rs);
+ pipe_pending_return = true;
+ DISASM("jr %s\n", register_name(rs));
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"JR\", pipe_branch_delay * 4, 0);\n");
+#endif
+ break;
+
+ case 015: // BREAK
+ EXIT_WITH_DELAY(MODE_BREAK);
+ break;
+
+ case 040: // ADD
+ case 041: // ADDU
+ APPEND_RD_NOT_R0("r%u = r%u + r%u;\n", rd, rs, rt);
+ DISASM("add %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 042: // SUB
+ case 043: // SUBU
+ APPEND_RD_NOT_R0("r%u = r%u - r%u;\n", rd, rs, rt);
+ DISASM("sub %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 044: // AND
+ APPEND_RD_NOT_R0("r%u = r%u & r%u;\n", rd, rs, rt);
+ DISASM("and %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 045: // OR
+ APPEND_RD_NOT_R0("r%u = r%u | r%u;\n", rd, rs, rt);
+ DISASM("or %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 046: // XOR
+ APPEND_RD_NOT_R0("r%u = r%u ^ r%u;\n", rd, rs, rt);
+ DISASM("xor %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 047: // NOR
+ APPEND_RD_NOT_R0("r%u = ~(r%u | r%u);\n", rd, rs, rt);
+ DISASM("nor %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 052: // SLT
+ APPEND_RD_NOT_R0("r%u = (int)r%u < (int)r%u;\n", rd, rs, rt);
+ DISASM("slt %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ case 053: // SLTU
+ APPEND_RD_NOT_R0("r%u = r%u < r%u;\n", rd, rs, rt);
+ DISASM("sltu %s, %s, %s\n", register_name(rd), register_name(rs), register_name(rt));
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case 001: // REGIMM
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ switch (rt)
+ {
+ case 020: // BLTZAL
+ APPEND("r31 = %u;\n", ((pc + i + 2) << 2) & 0xffc);
+ rs = (instr >> 21) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF((int)r%u < 0);\n", rs);
+ DISASM("bltzal %s, 0x%x\n", register_name(rs), ((pc + i + 1 + instr) << 2) & 0xffc);
+ break;
+
+ case 000: // BLTZ
+ rs = (instr >> 21) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF((int)r%u < 0);\n", rs);
+ DISASM("bltz %s, 0x%x\n", register_name(rs), ((pc + i + 1 + instr) << 2) & 0xffc);
+ break;
+
+ case 021: // BGEZAL
+ APPEND("r31 = %u;\n", ((pc + i + 2) << 2) & 0xffc);
+ rs = (instr >> 21) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF((int)r%u >= 0);\n", rs);
+ DISASM("bgezal %s, 0x%x\n", register_name(rs), ((pc + i + 1 + instr) << 2) & 0xffc);
+ break;
+
+ case 001: // BGEZ
+ rs = (instr >> 21) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF((int)r%u >= 0);\n", rs);
+ DISASM("bgez %s, 0x%x\n", register_name(rs), ((pc + i + 1 + instr) << 2) & 0xffc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 003: // JAL
+ APPEND("r31 = %u;\n", ((pc + i + 2) << 2) & 0xffc);
+ imm = instr & 0x3ff;
+ set_pc(imm);
+ pipe_pending_call = true;
+ APPEND("BRANCH();\n");
+ DISASM("jal 0x%x\n", (instr & 0x3ff) << 2);
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"JAL\", %u, 0);\n", pipe_branch_delay * 4);
+#endif
+ break;
+
+ case 002: // J
+ imm = instr & 0x3ff;
+ set_pc(imm);
+ APPEND("BRANCH();\n");
+ DISASM("j 0x%x\n", (instr & 0x3ff) << 2);
+ break;
+
+ case 004: // BEQ
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF(r%u == r%u);\n", rs, rt);
+ DISASM("beq %s, %s, 0x%x\n", register_name(rs), register_name(rt), ((pc + i + 1 + instr) & 0x3ff) << 2);
+ break;
+
+ case 005: // BNE
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF(r%u != r%u);\n", rs, rt);
+ DISASM("bne %s, %s, 0x%x\n", register_name(rs), register_name(rt), ((pc + i + 1 + instr) & 0x3ff) << 2);
+ break;
+
+ case 006: // BLEZ
+ rs = (instr >> 21) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF((int)r%u <= 0);\n", rs);
+ DISASM("blez %s, 0x%x\n", register_name(rs), ((pc + i + 1 + instr) & 0x3ff) << 2);
+ break;
+
+ case 007: // BGTZ
+ rs = (instr >> 21) & 31;
+ set_pc(pc + i + 1 + instr);
+ APPEND("BRANCH_IF((int)r%u > 0);\n", rs);
+ DISASM("bgtz %s, 0x%x\n", register_name(rs), ((pc + i + 1 + instr) & 0x3ff) << 2);
+ break;
+
+ case 010:
+ case 011: // ADDI
+ simm = instr;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = (int)r%u + %d;\n", rt, rs, simm);
+
+ if (rs != 0)
+ DISASM("addi %s, %s, %d\n", register_name(rt), register_name(rs), simm);
+ else
+ DISASM("li %s, %d\n", register_name(rt), simm);
+ break;
+
+ case 012: // SLTI
+ simm = instr;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = (int)r%u < %d;\n", rt, rs, simm);
+ DISASM("slti %s, %s, %d\n", register_name(rt), register_name(rs), simm);
+ break;
+
+ case 013: // SLTIU
+ imm = instr & 0xffff;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = r%u < %u;\n", rt, rs, imm);
+ DISASM("sltiu %s, %s, %u\n", register_name(rt), register_name(rs), imm);
+ break;
+
+ case 014: // ANDI
+ imm = instr & 0xffff;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = r%u & %u;\n", rt, rs, imm);
+ DISASM("andi %s, %s, 0x%x\n", register_name(rt), register_name(rs), imm);
+ break;
+
+ case 015: // ORI
+ imm = instr & 0xffff;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = r%u | %u;\n", rt, rs, imm);
+ DISASM("ori %s, %s, 0x%x\n", register_name(rt), register_name(rs), imm);
+ break;
+
+ case 016: // XORI
+ imm = instr & 0xffff;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = r%u ^ %u;\n", rt, rs, imm);
+ DISASM("xori %s, %s, 0x%x\n", register_name(rt), register_name(rs), imm);
+ break;
+
+ case 017: // LUI
+ imm = instr & 0xffff;
+ rt = (instr >> 16) & 31;
+ APPEND_RT_NOT_R0("r%u = %uu << 16u;\n", rt, imm);
+ DISASM("lui %s, 0x%x\n", register_name(rt), imm);
+ break;
+
+ case 020: // COP0
+ rd = (instr >> 11) & 31;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ switch (rs)
+ {
+ case 000: // MFC0
+ APPEND("cp0_result = RSP_MFC0(STATE, %u, %u);\n", rt, rd);
+ DISASM("mfc0 %u, %u\n", rt, rd);
+
+ APPEND("if (UNLIKELY(cp0_result != MODE_CONTINUE)) {\n");
+ EXIT_WITH_DELAY(cp0_result);
+ APPEND("}\n");
+ break;
+
+ case 004: // MTC0
+ APPEND("cp0_result = RSP_MTC0(STATE, %u, %u);\n", rd, rt);
+ DISASM("mtc0 %u, %u\n", rd, rt);
+
+ APPEND("if (UNLIKELY(cp0_result != MODE_CONTINUE)) {\n");
+ EXIT_WITH_DELAY(cp0_result);
+ APPEND("}\n");
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 022: // COP2
+ rd = (instr >> 11) & 31;
+ rs = (instr >> 21) & 31;
+ rt = (instr >> 16) & 31;
+ imm = (instr >> 7) & 15;
+ switch (rs)
+ {
+ case 000: // MFC2
+ APPEND("RSP_MFC2(STATE, %u, %u, %u);\n", rt, rd, imm);
+ DISASM("mfc2 %u, %u, %u\n", rt, rd, imm);
+ break;
+
+ case 002: // CFC2
+ APPEND("RSP_CFC2(STATE, %u, %u);\n", rt, rd);
+ DISASM("cfc2 %u, %u\n", rt, rd);
+ break;
+
+ case 004: // MTC2
+ APPEND("RSP_MTC2(STATE, %u, %u, %u);\n", rt, rd, imm);
+ DISASM("mtc2 %u, %u, %u\n", rt, rd, imm);
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"MTC2\", %u, 0);\n", 0);
+#endif
+ break;
+
+ case 006: // CTC2
+ APPEND("RSP_CTC2(STATE, %u, %u);\n", rt, rd);
+ DISASM("ctc2 %u, %u\n", rt, rd);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 040: // LB
+ simm = instr;
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ if (rt != 0)
+ {
+ APPEND("r%u = (signed char)READ_MEM_U8(dmem, (r%u + (%d)) & 0xfff);\n", rt, rs, simm);
+ }
+ DISASM("lb %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 041: // LH
+ simm = instr;
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ if (rt != 0)
+ {
+ APPEND("addr = (r%u + (%d)) & 0xfff;\n", rs, simm);
+ APPEND("if (UNLIKELY(addr & 1))\n");
+ APPEND(" r%u = (signed short)READ_MEM_U16_UNALIGNED(dmem, addr);\n", rt);
+ APPEND("else\n");
+ APPEND(" r%u = (signed short)READ_MEM_U16(dmem, addr);\n", rt);
+ }
+ DISASM("lh %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 043: // LW
+ simm = instr;
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ if (rt != 0)
+ {
+ APPEND("addr = (r%u + (%d)) & 0xfff;\n", rs, simm);
+ APPEND("if (UNLIKELY(addr & 3))\n");
+ APPEND(" r%u = READ_MEM_U32_UNALIGNED(dmem, addr);\n", rt);
+ APPEND("else\n");
+ APPEND(" r%u = READ_MEM_U32(dmem, addr);\n", rt);
+ }
+ DISASM("lw %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 044: // LBU
+ simm = instr;
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ if (rt != 0)
+ {
+ APPEND("r%u = READ_MEM_U8(dmem, (r%u + (%d)) & 0xfff);\n", rt, rs, simm);
+ }
+ DISASM("lbu %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 045: // LHU
+ simm = instr;
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ if (rt != 0)
+ {
+
+ APPEND("addr = (r%u + (%d)) & 0xfff;\n", rs, simm);
+ APPEND("if (UNLIKELY(addr & 1))\n");
+ APPEND(" r%u = READ_MEM_U16_UNALIGNED(dmem, addr);\n", rt);
+ APPEND("else\n");
+ APPEND(" r%u = READ_MEM_U16(dmem, addr);\n", rt);
+ }
+ DISASM("lhu %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 050: // SB
+ simm = instr;
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ APPEND("WRITE_MEM_U8(dmem, ((r%u + (%d)) & 0xfff), r%u);\n", rs, simm, rt);
+ DISASM("sb %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 051: // SH
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ simm = instr;
+ APPEND("addr = (r%u + (%d)) & 0xfff;\n", rs, simm);
+ APPEND("if (UNLIKELY(addr & 1))\n");
+ APPEND(" WRITE_MEM_U16_UNALIGNED(dmem, addr, r%u);\n", rt);
+ APPEND("else\n");
+ APPEND(" WRITE_MEM_U16(dmem, addr, r%u);\n", rt);
+ DISASM("sh %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 053: // SW
+ rt = (instr >> 16) & 31;
+ rs = (instr >> 21) & 31;
+ simm = instr;
+ APPEND("addr = (r%u + (%d)) & 0xfff;\n", rs, simm);
+ APPEND("if (UNLIKELY(addr & 3))\n");
+ APPEND(" WRITE_MEM_U32_UNALIGNED(dmem, addr, r%u);\n", rt);
+ APPEND("else\n");
+ APPEND(" WRITE_MEM_U32(dmem, addr, r%u);\n", rt);
+ DISASM("sw %s, %d(%s)\n", register_name(rt), simm, register_name(rs));
+ break;
+
+ case 062: // LWC2
+ {
+ rt = (instr >> 16) & 31;
+ simm = instr;
+ // Sign extend.
+ simm <<= 9;
+ simm >>= 9;
+ rs = (instr >> 21) & 31;
+ rd = (instr >> 11) & 31;
+ imm = (instr >> 7) & 15;
+ static const char *lwc2_ops[32] = {
+ "LBV", "LSV", "LLV", "LDV", "LQV", "LRV", "LPV", "LUV", "LHV", nullptr, nullptr,
+ "LTV", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ };
+ auto *op = lwc2_ops[rd];
+ if (op)
+ {
+ APPEND("RSP_%s(STATE, %u, %u, %d, %u);\n", op, rt, imm, simm, rs);
+ DISASM("%s %u, %u, %d, %u\n", op, rt, imm, simm, rs);
+ }
+
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"LWC2\", %u, %u);\n", (pc + i + 1) << 2, instr);
+#endif
+ break;
+ }
+
+ case 072: // SWC2
+ {
+ rt = (instr >> 16) & 31;
+ simm = instr;
+ // Sign extend.
+ simm <<= 9;
+ simm >>= 9;
+ rs = (instr >> 21) & 31;
+ rd = (instr >> 11) & 31;
+ imm = (instr >> 7) & 15;
+ static const char *swc2_ops[32] = {
+ "SBV", "SSV", "SLV", "SDV", "SQV", "SRV", "SPV", "SUV", "SHV", "SFV", nullptr,
+ "STV", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ };
+ auto *op = swc2_ops[rd];
+ if (op)
+ {
+ APPEND("RSP_%s(STATE, %u, %u, %d, %u);\n", op, rt, imm, simm, rs);
+ DISASM("%s %u, %u, %d, %u\n", op, rt, imm, simm, rs);
+ }
+
+#ifdef INTENSE_DEBUG
+ APPEND("RSP_DEBUG(STATE, \"SWC2\", %u, %u);\n", (pc + i + 1) << 2, instr);
+#endif
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (i == 0)
+ CHECK_INHERIT_BRANCH_DELAY();
+ else
+ CHECK_BRANCH_DELAY();
+ APPEND("\n");
+ }
+
+ // Falling off end of block.
+ APPEND("STATE->pc = %u;\n", ((pc + count) << 2) & (IMEM_SIZE - 1));
+ PROMOTE_DELAY_SLOT();
+ APPEND("EXIT(MODE_CONTINUE);\n");
+
+ // Emit helper code.
+ full_code += R"DELIM(
+struct cpu_state
+{
+ unsigned pc;
+ unsigned dirty_blocks;
+ unsigned has_delay_slot;
+ unsigned branch_target;
+ unsigned sr[33];
+ unsigned *dmem;
+ unsigned *imem;
+};
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+#define MASK_SA(x) ((x) & 31)
+
+enum ReturnMode {
+ MODE_ENTER = 0,
+ MODE_CONTINUE = 1,
+ MODE_BREAK = 2,
+ MODE_DMA_READ = 3,
+ MODE_CHECK_FLAGS = 4
+};
+#define r0 0
+#define ADVANCE_DELAY_SLOT() do { \
+ branch = pipe_branch; \
+ pipe_branch = 0; \
+ branch_delay = pipe_branch_delay; \
+} while(0)
+
+#define BRANCH() pipe_branch = 1
+#define BRANCH_IF(x) if (x) BRANCH()
+#define BRANCH_INDIRECT(pc) do { \
+ pipe_branch_delay = pc; \
+ pipe_branch = 1; \
+} while(0)
+
+#define PROMOTE_DELAY_SLOT() do { \
+ if (pipe_branch) { \
+ STATE->has_delay_slot = 1; \
+ STATE->branch_target = pipe_branch_delay * 4; \
+ } \
+} while(0)
+
+extern int RSP_MFC0(struct cpu_state *STATE, unsigned rt, unsigned rd);
+extern int RSP_MTC0(struct cpu_state *STATE, unsigned rd, unsigned rt);
+
+extern void RSP_MTC2(struct cpu_state *STATE, unsigned rt, unsigned vd, unsigned e);
+extern void RSP_MFC2(struct cpu_state *STATE, unsigned rt, unsigned vs, unsigned e);
+extern void RSP_CFC2(struct cpu_state *STATE, unsigned rt, unsigned rd);
+extern void RSP_CTC2(struct cpu_state *STATE, unsigned rt, unsigned rd);
+
+extern void RSP_REPORT_PC(struct cpu_state *STATE, unsigned pc, unsigned instr);
+
+#define DECL_LS(op) \
+ extern void RSP_##op(struct cpu_state *STATE, unsigned rt, unsigned element, int offset, unsigned base)
+
+DECL_LS(LBV);
+DECL_LS(LSV);
+DECL_LS(LLV);
+DECL_LS(LDV);
+DECL_LS(LQV);
+DECL_LS(LRV);
+DECL_LS(LPV);
+DECL_LS(LUV);
+DECL_LS(LHV);
+DECL_LS(LTV);
+
+DECL_LS(SBV);
+DECL_LS(SSV);
+DECL_LS(SLV);
+DECL_LS(SDV);
+DECL_LS(SQV);
+DECL_LS(SRV);
+DECL_LS(SPV);
+DECL_LS(SUV);
+DECL_LS(SHV);
+DECL_LS(SFV);
+DECL_LS(STV);
+
+extern void RSP_CALL(void *opaque, unsigned target, unsigned ret);
+extern int RSP_RETURN(void *opaque, unsigned pc);
+extern void RSP_EXIT(void *opaque, enum ReturnMode mode);
+#define EXIT(mode) RSP_EXIT(opaque, mode)
+
+extern void RSP_DEBUG(struct cpu_state *STATE, const char *tag, unsigned pc, unsigned value);
+
+#define DECL_COP2(op) \
+ extern void RSP_##op(struct cpu_state *STATE, unsigned vd, unsigned vs, unsigned vt, unsigned e)
+DECL_COP2(VMULF);
+DECL_COP2(VMULU);
+DECL_COP2(VMUDL);
+DECL_COP2(VMUDM);
+DECL_COP2(VMUDN);
+DECL_COP2(VMUDH);
+DECL_COP2(VMACF);
+DECL_COP2(VMACU);
+//DECL_COP2(VMACQ);
+DECL_COP2(VMADL);
+DECL_COP2(VMADM);
+DECL_COP2(VMADN);
+DECL_COP2(VMADH);
+DECL_COP2(VADD);
+DECL_COP2(VSUB);
+DECL_COP2(VABS);
+DECL_COP2(VADDC);
+DECL_COP2(VSUBC);
+DECL_COP2(VSAR);
+DECL_COP2(VLT);
+DECL_COP2(VEQ);
+DECL_COP2(VNE);
+DECL_COP2(VGE);
+DECL_COP2(VCL);
+DECL_COP2(VCH);
+DECL_COP2(VCR);
+DECL_COP2(VMRG);
+DECL_COP2(VAND);
+DECL_COP2(VNAND);
+DECL_COP2(VOR);
+DECL_COP2(VNOR);
+DECL_COP2(VXOR);
+DECL_COP2(VNXOR);
+DECL_COP2(VRCP);
+DECL_COP2(VRCPL);
+DECL_COP2(VRCPH);
+DECL_COP2(VMOV);
+DECL_COP2(VRSQ);
+DECL_COP2(VRSQL);
+DECL_COP2(VRSQH);
+DECL_COP2(VNOP);
+DECL_COP2(RESERVED);
+
+#define HES(x) ((x) ^ 2)
+#define BES(x) ((x) ^ 3)
+#define MES(x) ((x) ^ 1)
+
+#define READ_MEM_U8(mem, addr) \
+ (((const unsigned char*)(mem))[BES(addr)])
+#define READ_MEM_U16(mem, addr) \
+ (((const unsigned short*)(mem))[HES(addr) >> 1])
+#define READ_MEM_U32(mem, addr) \
+ (((const unsigned*)(mem))[addr >> 2])
+
+#define READ_MEM_U16_UNALIGNED(mem, addr) \
+ (READ_MEM_U8(mem, addr) << 8) | READ_MEM_U8(mem, (addr + 1) & 0xfff)
+
+#define READ_MEM_U32_UNALIGNED(mem, addr) \
+ (READ_MEM_U8(mem, addr) << 24) | (READ_MEM_U8(mem, (addr + 1) & 0xfff) << 16) | \
+ (READ_MEM_U8(mem, (addr + 2) & 0xfff) << 8) | READ_MEM_U8(mem, (addr + 3) & 0xfff)
+
+#define WRITE_MEM_U8(mem, addr, data) \
+ (((unsigned char*)(mem))[BES(addr)] = data)
+
+#define WRITE_MEM_U16_UNALIGNED(mem, addr, data) do { \
+ WRITE_MEM_U8(mem, addr, data >> 8); \
+ WRITE_MEM_U8(mem, (addr + 1) & 0xfff, data & 0xff); \
+} while(0)
+
+#define WRITE_MEM_U32_UNALIGNED(mem, addr, data) do { \
+ WRITE_MEM_U8(mem, addr, data >> 24); \
+ WRITE_MEM_U8(mem, (addr + 1) & 0xfff, (data >> 16) & 0xff); \
+ WRITE_MEM_U8(mem, (addr + 2) & 0xfff, (data >> 8) & 0xff); \
+ WRITE_MEM_U8(mem, (addr + 3) & 0xfff, data & 0xff); \
+} while(0)
+
+#define WRITE_MEM_U16(mem, addr, data) \
+ (((unsigned short*)(mem))[HES(addr) >> 1] = data)
+#define WRITE_MEM_U32(mem, addr, data) \
+ (((unsigned*)(mem))[addr >> 2] = data)
+
+)DELIM";
+ full_code += "void block_entry(void *opaque, struct cpu_state *STATE)\n";
+ full_code += "{\n";
+
+ for (unsigned i = 1; i < 32; i++)
+ {
+ char buf[32];
+ sprintf(buf, "#define r%u (STATE->sr[%u])\n", i, i);
+ full_code += buf;
+ }
+
+ // Emit fixup code.
+
+ full_code += body;
+ full_code += "}\n";
+
+#ifdef DEBUG_JIT
+ unique_ptr block(new Block(symbol_table));
+#else
+ unique_ptr block(new Block(jit_engine));
+#endif
+ if (!block->compile(hash, full_code))
+ return nullptr;
+
+ auto ret = block->get_func();
+ cached_blocks[pc][hash] = move(block);
+ return ret;
+}
+
+void CPU::print_registers()
+{
+#define DUMP_FILE stdout
+ fprintf(DUMP_FILE, "RSP state:\n");
+ fprintf(DUMP_FILE, " PC: 0x%03x\n", state.pc);
+ for (unsigned i = 1; i < 32; i++)
+ fprintf(DUMP_FILE, " SR[%s] = 0x%08x\n", register_name(i), state.sr[i]);
+ fprintf(DUMP_FILE, "\n");
+ for (unsigned i = 0; i < 32; i++)
+ {
+ fprintf(DUMP_FILE, " VR[%02u] = { 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x }\n", i,
+ state.cp2.regs[i].e[0], state.cp2.regs[i].e[1], state.cp2.regs[i].e[2], state.cp2.regs[i].e[3],
+ state.cp2.regs[i].e[4], state.cp2.regs[i].e[5], state.cp2.regs[i].e[6], state.cp2.regs[i].e[7]);
+ }
+
+ fprintf(DUMP_FILE, "\n");
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ static const char *strings[] = { "ACC_HI", "ACC_MD", "ACC_LO" };
+ fprintf(DUMP_FILE, " %s = { 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x }\n", strings[i],
+ state.cp2.acc.e[8 * i + 0], state.cp2.acc.e[8 * i + 1], state.cp2.acc.e[8 * i + 2],
+ state.cp2.acc.e[8 * i + 3], state.cp2.acc.e[8 * i + 4], state.cp2.acc.e[8 * i + 5],
+ state.cp2.acc.e[8 * i + 6], state.cp2.acc.e[8 * i + 7]);
+ }
+
+ fprintf(DUMP_FILE, "\n");
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ static const char *strings[] = { "VCO", "VCC", "VCE" };
+ uint16_t flags = rsp_get_flags(state.cp2.flags[i].e);
+ fprintf(DUMP_FILE, " %s = 0x%04x\n", strings[i], flags);
+ }
+
+ fprintf(DUMP_FILE, "\n");
+ fprintf(DUMP_FILE, " Div Out = 0x%04x\n", state.cp2.div_out);
+ fprintf(DUMP_FILE, " Div In = 0x%04x\n", state.cp2.div_in);
+ fprintf(DUMP_FILE, " DP flag = 0x%04x\n", state.cp2.dp_flag);
+}
+
+void CPU::exit(ReturnMode mode)
+{
+#ifdef __GNUC__
+ // On Windows, setjmp/longjmp crashes since it uses exception unwinding semantics
+ // and our JIT-ed LLVM code does not emit that kind of information, so we have to use a non-standard unwinding mechanism.
+ // FWIW, this should also be the fastest possible way of doing it.
+ return_mode = mode;
+ __builtin_longjmp(env, 1);
+#else
+#error "Need __builtin_setjmp/longjmp support alternative for other compilers ..."
+#endif
+}
+
+void CPU::call(uint32_t target, uint32_t ret)
+{
+ if (call_stack_ptr < CALL_STACK_SIZE)
+ call_stack[call_stack_ptr++] = ret;
+ enter(target);
+}
+
+int CPU::ret(uint32_t pc)
+{
+ if (call_stack_ptr == 0)
+ return 0;
+
+ uint32_t ret = call_stack[--call_stack_ptr];
+ return ret == pc;
+}
+
+extern "C"
+{
+ void RSP_CALL(void *cpu, unsigned target, unsigned ret)
+ {
+ static_cast(cpu)->call(target, ret);
+ }
+
+ void RSP_RETURN(void *cpu, unsigned pc)
+ {
+ static_cast(cpu)->ret(pc);
+ }
+
+ void RSP_EXIT(void *cpu, int mode)
+ {
+ static_cast(cpu)->exit(static_cast(mode));
+ }
+
+ void RSP_REPORT_PC(void *cpu, unsigned pc, unsigned instr)
+ {
+ auto *state = static_cast(cpu);
+ auto disasm = disassemble(pc, instr);
+ puts(disasm.c_str());
+
+ for (unsigned i = 0; i < 32; i++)
+ {
+ if (i == 0)
+ printf(" ");
+ else
+ printf("[%s = 0x%08x] ", register_name(i), state->sr[i]);
+ if ((i & 7) == 7)
+ printf("\n");
+ }
+ printf("\n");
+ }
+}
+
+void CPU::enter(uint32_t pc)
+{
+ pc &= IMEM_SIZE - 1;
+ uint32_t word_pc = pc >> 2;
+ auto &block = blocks[word_pc];
+
+ if (!block)
+ {
+ unsigned end = (pc + (CODE_BLOCK_SIZE * 2)) >> CODE_BLOCK_SIZE_LOG2;
+ end <<= CODE_BLOCK_SIZE_LOG2 - 2;
+ end = min(end, unsigned(IMEM_SIZE >> 2));
+ end = analyze_static_end(word_pc, end);
+
+ uint64_t hash = hash_imem(word_pc, end - word_pc);
+ auto itr = cached_blocks[word_pc].find(hash);
+ if (itr != cached_blocks[word_pc].end())
+ {
+ block = itr->second->get_func();
+ //fprintf(stdout, "jit reuse");
+ }
+ else
+ {
+ //static unsigned count;
+ //fprintf(DUMP_FILE, "JIT region #%u\n", ++count);
+ block = jit_region(hash, word_pc, end - word_pc);
+ //fprintf(stdout, "jit compile");
+ }
+ }
+ //fprintf(stdout, "jit execute");
+ block(this, &state);
+}
+
+ReturnMode CPU::run()
+{
+ for (;;)
+ {
+ invalidate_code();
+ call_stack_ptr = 0;
+
+#ifdef __GNUC__
+ // On Windows, setjmp/longjmp crashes since it uses exception unwinding semantics
+ // and our JIT-ed LLVM code does not emit that kind of information, so we have to use a non-standard unwinding mechanism.
+ // FWIW, this should also be the fastest possible way of doing it.
+ int setjmp_ret = __builtin_setjmp(env);
+ auto ret = setjmp_ret ? return_mode : MODE_ENTER;
+#else
+#error "Need __builtin_setjmp/longjmp support alternative for other compilers ..."
+#endif
+
+ switch (ret)
+ {
+ case MODE_ENTER:
+ enter(state.pc);
+ break;
+
+ case MODE_BREAK:
+ *state.cp0.cr[CP0_REGISTER_SP_STATUS] |= SP_STATUS_BROKE | SP_STATUS_HALT;
+ if (*state.cp0.cr[CP0_REGISTER_SP_STATUS] & SP_STATUS_INTR_BREAK)
+ *state.cp0.irq |= 1;
+#ifndef PARALLEL_INTEGRATION
+ print_registers();
+#endif
+ return MODE_BREAK;
+
+ case MODE_CHECK_FLAGS:
+ case MODE_DMA_READ:
+ return ret;
+
+ default:
+ break;
+ }
+ }
+}
+} // namespace RSP
diff --git a/parallel-rsp/debug_rsp.hpp b/parallel-rsp/debug_rsp.hpp
new file mode 100644
index 0000000..30ebd88
--- /dev/null
+++ b/parallel-rsp/debug_rsp.hpp
@@ -0,0 +1,102 @@
+#ifndef RSP_HPP__
+#define RSP_HPP__
+
+#include
+#include
+#include
+#include
+#include
+
+#include "debug_jit.hpp"
+#include "llvm_jit.hpp"
+#include "rsp_op.hpp"
+#include "state.hpp"
+
+namespace RSP
+{
+#ifdef DEBUG_JIT
+using Block = JIT::DebugBlock;
+#else
+using Block = JIT::Block;
+#endif
+using Func = JIT::Func;
+
+
+class alignas(64) CPU
+{
+public:
+ CPU();
+ ~CPU();
+
+ CPU(CPU &&) = delete;
+ void operator=(CPU &&) = delete;
+
+ void set_dmem(uint32_t *dmem)
+ {
+ state.dmem = dmem;
+ }
+
+ void set_imem(uint32_t *imem)
+ {
+ state.imem = imem;
+ }
+
+ void set_rdram(uint32_t *rdram)
+ {
+ state.rdram = rdram;
+ }
+
+ void invalidate_imem();
+
+ CPUState &get_state()
+ {
+ return state;
+ }
+
+ ReturnMode run();
+
+ void enter(uint32_t pc);
+ void call(uint32_t target, uint32_t ret);
+ int ret(uint32_t pc);
+ void exit(ReturnMode mode);
+
+ void print_registers();
+
+private:
+ CPUState state;
+ Func blocks[IMEM_WORDS] = {};
+ std::unordered_map symbol_table;
+#ifndef DEBUG_JIT
+ JIT::LLVMEngine jit_engine;
+#endif
+ std::unordered_map> cached_blocks[IMEM_WORDS];
+
+ void invalidate_code();
+ uint64_t hash_imem(unsigned pc, unsigned count) const;
+ Func jit_region(uint64_t hash, unsigned pc, unsigned count);
+
+ std::string full_code;
+ std::string body;
+
+ void init_symbol_table();
+
+ alignas(64) uint32_t cached_imem[IMEM_WORDS] = {};
+
+ // Platform specific.
+#ifdef __GNUC__
+ intptr_t env[64];
+ // We're reading this after setjmp returns so need to make sure the read happens when we expect it to.
+ volatile ReturnMode return_mode;
+#else
+#error "Need __builtin_setjmp/longjmp support alternative for other compilers ..."
+#endif
+
+#define CALL_STACK_SIZE 32
+ uint32_t call_stack[CALL_STACK_SIZE] = {};
+ unsigned call_stack_ptr = 0;
+
+ unsigned analyze_static_end(unsigned pc, unsigned end);
+};
+} // namespace RSP
+
+#endif
diff --git a/parallel-rsp/format_all.sh b/parallel-rsp/format_all.sh
new file mode 100755
index 0000000..6cefc30
--- /dev/null
+++ b/parallel-rsp/format_all.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+for file in arch/*/*/*.{cpp,h} *.{cpp,hpp,h} rsp/*.{cpp,h}
+do
+ echo "Formatting file: $file ..."
+ clang-format -style=file -i $file
+done
diff --git a/parallel-rsp/jit_allocator.cpp b/parallel-rsp/jit_allocator.cpp
new file mode 100644
index 0000000..921f6b5
--- /dev/null
+++ b/parallel-rsp/jit_allocator.cpp
@@ -0,0 +1,109 @@
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include
+#else
+#include
+#endif
+#include
+#include
+
+#include "jit_allocator.hpp"
+
+namespace RSP
+{
+namespace JIT
+{
+static constexpr bool huge_va = std::numeric_limits::max() > 0x100000000ull;
+// On 64-bit systems, we will never allocate more than one block, this is important since we must ensure that
+// relative jumps are reachable in 32-bits.
+// We won't actually allocate 1 GB on 64-bit, but just reserve VA space for it, which we have basically an infinite amount of.
+static constexpr size_t block_size = huge_va ? (1024 * 1024 * 1024) : (2 * 1024 * 1024);
+Allocator::~Allocator()
+{
+#ifdef _WIN32
+ for (auto &block : blocks)
+ VirtualFree(block.code, 0, MEM_RELEASE);
+#else
+ for (auto &block : blocks)
+ munmap(block.code, block.size);
+#endif
+}
+
+static size_t align_page(size_t offset)
+{
+ return (offset + 4095) & ~size_t(4095);
+}
+
+static bool commit_read_write(void *ptr, size_t size)
+{
+#ifdef _WIN32
+ return VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) == ptr;
+#else
+ return mprotect(ptr, size, PROT_READ | PROT_WRITE) == 0;
+#endif
+}
+
+static bool commit_execute(void *ptr, size_t size)
+{
+#ifdef _WIN32
+ DWORD old_protect;
+ return VirtualProtect(ptr, align_page(size), PAGE_EXECUTE, &old_protect) != 0;
+#else
+ return mprotect(ptr, size, PROT_EXEC) == 0;
+#endif
+}
+
+bool Allocator::commit_code(void *code, size_t size)
+{
+ return commit_execute(code, size);
+}
+
+void *Allocator::allocate_code(size_t size)
+{
+ size = align_page(size);
+ if (blocks.empty())
+ blocks.push_back(reserve_block(std::max(size, block_size)));
+
+ auto *block = &blocks.back();
+ if (!block->code)
+ return nullptr;
+
+ block->offset = align_page(block->offset);
+ if (block->offset + size > block->size)
+ block = nullptr;
+
+ if (!block)
+ {
+ if (huge_va)
+ abort();
+ blocks.push_back(reserve_block(std::max(size, block_size)));
+ block = &blocks.back();
+ }
+
+ if (!block || !block->code)
+ return nullptr;
+
+ void *ret = block->code + block->offset;
+ block->offset += size;
+
+ if (!commit_read_write(ret, size))
+ return nullptr;
+ return ret;
+}
+
+Allocator::Block Allocator::reserve_block(size_t size)
+{
+ Block block;
+#ifdef _WIN32
+ block.code = static_cast(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
+ block.size = size;
+ return block;
+#else
+ block.code = static_cast(mmap(nullptr, size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE,
+ -1, 0));
+ block.size = size;
+ return block;
+#endif
+}
+}
+}
diff --git a/parallel-rsp/jit_allocator.hpp b/parallel-rsp/jit_allocator.hpp
new file mode 100644
index 0000000..a7768a8
--- /dev/null
+++ b/parallel-rsp/jit_allocator.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+
+namespace RSP
+{
+namespace JIT
+{
+class Allocator
+{
+public:
+ Allocator() = default;
+ ~Allocator();
+ void operator=(const Allocator &) = delete;
+ Allocator(const Allocator &) = delete;
+
+ void *allocate_code(size_t size);
+ static bool commit_code(void *code, size_t size);
+
+private:
+ struct Block
+ {
+ uint8_t *code = nullptr;
+ size_t size = 0;
+ size_t offset = 0;
+ };
+ std::vector blocks;
+
+ static Block reserve_block(size_t size);
+};
+}
+}
diff --git a/parallel-rsp/lightning/.gitattributes b/parallel-rsp/lightning/.gitattributes
new file mode 100644
index 0000000..e8495d5
--- /dev/null
+++ b/parallel-rsp/lightning/.gitattributes
@@ -0,0 +1 @@
+ChangeLog merge=merge-changelog
diff --git a/parallel-rsp/lightning/.gitignore b/parallel-rsp/lightning/.gitignore
new file mode 100644
index 0000000..62ca42a
--- /dev/null
+++ b/parallel-rsp/lightning/.gitignore
@@ -0,0 +1,33 @@
++*
+autom4te.cache
+aclocal.m4
+depcomp
+INSTALL
+Makefile
+Makefile.in
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+install-sh
+libtool
+lightning-*.tar.*
+ltmain.sh
+missing
+size
+stamp-h1
+test-driver
+check/.deps
+doc/.deps
+lib/.deps
+m4/libtool.m4
+m4/lt~obsolete.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+doc/mdate-sh
+doc/texinfo.tex
+lightning.pc
diff --git a/parallel-rsp/lightning/.gitrepo b/parallel-rsp/lightning/.gitrepo
new file mode 100644
index 0000000..fe7174d
--- /dev/null
+++ b/parallel-rsp/lightning/.gitrepo
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+ remote = https://git.savannah.gnu.org/git/lightning.git
+ branch = master
+ commit = b0b8eb5e856c0d29053dc842e1919a2eb58c8cda
+ parent = 9f797430963d9cf0fcef7d963466f9cac7026de2
+ method = merge
+ cmdver = 0.4.1
diff --git a/parallel-rsp/lightning/AUTHORS b/parallel-rsp/lightning/AUTHORS
new file mode 100644
index 0000000..2097c63
--- /dev/null
+++ b/parallel-rsp/lightning/AUTHORS
@@ -0,0 +1,14 @@
+Paulo Cesar Pereira de Andrade
+
+Paolo Bonzini
+
+PPC assembler by Ian Piumarta
+
+i386 assembler by Ian Piumarta
+and Gwenole Beauchesne
+
+x86-64 backend by Matthew Flatt
+
+Major PPC contributions by Laurent Michel
+
+Major SPARC contributions by Ludovic Courtes
diff --git a/parallel-rsp/lightning/COPYING b/parallel-rsp/lightning/COPYING
new file mode 100644
index 0000000..4432540
--- /dev/null
+++ b/parallel-rsp/lightning/COPYING
@@ -0,0 +1,676 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
+
diff --git a/parallel-rsp/lightning/COPYING.DOC b/parallel-rsp/lightning/COPYING.DOC
new file mode 100644
index 0000000..1a86456
--- /dev/null
+++ b/parallel-rsp/lightning/COPYING.DOC
@@ -0,0 +1,355 @@
+ GNU Free Documentation License
+ Version 1.1, March 2000
+
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+written document "free" in the sense of freedom: to assure everyone
+the effective freedom to copy and redistribute it, with or without
+modifying it, either commercially or noncommercially. Secondarily,
+this License preserves for the author and publisher a way to get
+credit for their work, while not being considered responsible for
+modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work that contains a
+notice placed by the copyright holder saying it can be distributed
+under the terms of this License. The "Document", below, refers to any
+such manual or work. Any member of the public is a licensee, and is
+addressed as "you".
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (For example, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, whose contents can be viewed and edited directly and
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup has been designed to thwart or discourage
+subsequent modification by readers is not Transparent. A copy that is
+not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML designed for human modification. Opaque formats include
+PostScript, PDF, proprietary formats that can be read and edited only
+by proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML produced by some word processors for output
+purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies of the Document numbering more than 100,
+and the Document's license notice requires Cover Texts, you must enclose
+the copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a publicly-accessible computer-network location containing a complete
+Transparent copy of the Document, free of added material, which the
+general network-using public has access to download anonymously at no
+charge using public-standard network protocols. If you use the latter
+option, you must take reasonably prudent steps, when you begin
+distribution of Opaque copies in quantity, to ensure that this
+Transparent copy will remain thus accessible at the stated location
+until at least one year after the last time you distribute an Opaque
+copy (directly or through your agents or retailers) of that edition to
+the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has less than five).
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section entitled "History", and its title, and add to
+ it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. In any section entitled "Acknowledgements" or "Dedications",
+ preserve the section's title, and preserve in the section all the
+ substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section as "Endorsements"
+ or to conflict in title with any Invariant Section.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections entitled "History"
+in the various original documents, forming one section entitled
+"History"; likewise combine any sections entitled "Acknowledgements",
+and any sections entitled "Dedications". You must delete all sections
+entitled "Endorsements."
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, does not as a whole count as a Modified Version
+of the Document, provided no compilation copyright is claimed for the
+compilation. Such a compilation is called an "aggregate", and this
+License does not apply to the other self-contained works thus compiled
+with the Document, on account of their being thus compiled, if they
+are not themselves derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one quarter
+of the entire aggregate, the Document's Cover Texts may be placed on
+covers that surround only the Document within the aggregate.
+Otherwise they must appear on covers around the whole aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License provided that you also include the
+original English version of this License. In case of a disagreement
+between the translation and the original English version of this
+License, the original English version will prevail.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.1
+ or any later version published by the Free Software Foundation;
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have no Invariant Sections, write "with no Invariant Sections"
+instead of saying which ones are invariant. If you have no
+Front-Cover Texts, write "no Front-Cover Texts" instead of
+"Front-Cover Texts being LIST"; likewise for Back-Cover Texts.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/parallel-rsp/lightning/COPYING.LESSER b/parallel-rsp/lightning/COPYING.LESSER
new file mode 100644
index 0000000..fc8a5de
--- /dev/null
+++ b/parallel-rsp/lightning/COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/parallel-rsp/lightning/ChangeLog b/parallel-rsp/lightning/ChangeLog
new file mode 100644
index 0000000..76cac91
--- /dev/null
+++ b/parallel-rsp/lightning/ChangeLog
@@ -0,0 +1,4148 @@
+2020-23-01 Paulo Andrade
+
+ * lib/lightning.c: Add a proper fix to the condition of considering
+ a register dead at entry of a block when it modifies the register
+ !after! a branch to a target where it is live.
+ The correction is just to split blocks on branches. It uses an
+ extra label per branch, but makes following the code simpler and
+ avoid costly searches.
+
+2020-22-01 Paulo Andrade
+
+ * lib/lightning.c: Correct a special condition of a register
+ only assigned in a block, and incorrectly marked as dead before
+ a jump where the register is live.
+
+2019-10-04 Paulo Andrade
+
+ * check/lightning.c, include/lightning/jit_private.h,
+ include/lightning/jit_x86.h, lib/jit_x86-cpu.c, lib/jit_x86-sz.c,
+ lib/jit_x86.c: Correct issues with MinGW64 that defines _WIN32
+ and needs long long for jit_word_t.
+
+2019-09-16 Paulo Andrade
+
+ * lib/lightning.c: Do not add registers that are never modified
+ to the set of registers to scan for live range, what might
+ consume a lot of cpu time, doing nothing.
+
+2019-09-16 Marc Nieper-WiÃkirchen
+
+ * include/lightning/jit_x86.h, lib/jit_x86.c: Correct x86_64
+ backend, made %r12 a callee-save register as dictated by the
+ System V AMD64 ABI.
+
+2019-09-16 Paulo Andrade
+
+ * Makefile.am: Do not force CFLAGS for the get_jit_size target.
+ * check/lightning.c: Drop __ppc__ check.
+ * include/lightning.h.in: Drop __ppc__ check. Add new
+ jit_flag_vararg flag, for special case in powerpc 32 bit using
+ the SYSV abi, and need to pass an extra argument during code
+ generation.
+ * include/lightning/jit_ppc.c: Drop __ppc_ check. Remove the
+ ABI_ELFv2 macro, as it now directly checks for the _CALL_ELF
+ value when/if appropriate.
+ * include/lightning/jit_private.h: Drop __ppc_ check. Check for
+ _CALL_AIXDESC to define extra data to handle function
+ descriptors.
+ * lib/jit_ppc-cpu.c: Update to check for _CALL_SYSV; assume
+ !_CALL_SYSV == (_CALL_AIX || _CALL_LINUX). Significant code
+ rework for the SYSV abi.
+ * lib/jit_ppc-sz.c: Update for the SYSV abi.
+ * lib/jit_ppc.c: Update for the SYSV abi. Add matching va_list
+ type. Drop __ppc__ check.
+ * lib/jit_size.c: Drop __ppc_ check.
+ * lib/lightning.c: Drop __ppc__ check. Add proper check for
+ __powerpc__ and _CALL_AIXDESC to manage function descriptors.
+ * lib/size.c: Update to drop __pppc_ check and SYSV abi.
+
+2019-08-30 Paulo Andrade
+
+ * lib/jit_mips-cpu.c: Use JALR to get the same effect as JR, as
+ in mips32r6 JR generates an illegal instruction. Thanks to
+ Bruno Haible for providing a patch and the information, reported at
+ https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925129
+ * THANKS: update.
+
+2019-08-29 Marc Nieper-WiÃkirchen
+
+ * include/lightning/jit_private.h: Move definition of offsetof
+ from the public header file here.
+
+ * configure.ac, include/Makefile.am, include/lightning.h,
+ include/lightning.h.in: Generate lightning.h from lightning.in.h
+ and remove the dependence on config.h from the public header file.
+
+2019-06-04 Paulo Andrade
+
+ * include/lightning/jit_riscv.h, lib/jit_riscv-cpu.c,
+ lib/jit_riscv-fpu.c, lib/jit_riscv-sz.c, lib/jit_riscv.c:
+ Implement riscv port. Only 64 bit Linux supported. Built on
+ Fedora 28 image.
+
+ * check/all.tst, check/float.tst, configure.ac, include/lightning.h,
+ include/lightning/Makefile.am, include/lightning/jit_private.h,
+ lib/Makefile.am, lib/jit_disasm.c, lib/jit_size.c, lib/lightning.c:
+ Minor updates for the new riscv port.
+
+2019-06-04 Paulo Andrade
+
+ * lib/jit_alpha.c lib/jit_ia64.c lib/jit_mips.c lib/jit_sparc.c:
+ Correct assertion of _jitc->regarg after emiting an instruction.
+ jit_carry may be set, but not an argument to the current instruction.
+
+2019-06-01 Paulo Andrade
+
+ * lib/lightning.c: Correct assertion on jit_unget_reg when the
+ argument is jit_carry, and jit_carry was not used in the
+ instruction.
+
+2019-06-01 Paulo Andrade
+
+ * include/lightning/jit_private.h: Remove no longer need
+ setmask field of jit_block_t and blockmask from jit_compiler_t.
+
+ * lib/lightning.c: Rework of register live and unknown state
+ information during jit generation. It no longer recurses nor
+ do dangerous bit unset of registers in unknown state. The
+ only pitfall known, that must be taken care now is that jmpr
+ (or jmpi to not a jit node) is treated as a function call, as
+ otherwise it would need to consider all registers live, and
+ spill/reload during all jit generation.
+
+2018-12-28 Paulo Andrade
+
+ * lib/jit_disasm.c: Release bfd handle. Thanks for patch to
+ Marc Nieper-Wißkirchen.
+
+2018-08-30 Paulo Andrade
+
+ * lib/jit_disasm.c: Add hints to select hppa disassembler.
+
+ * lib/jit_hppa-cpu.c: Correct address of vastart when all
+ argument registers were used as non vararg arguments.
+
+ * lib/jit_hppa-fpu.c: Disable load/store of rv,ix,rb where
+ rv is the value, ix is an register or integer offset and rb
+ is a base register. These should be better tested, as they do
+ not work on all environments (fail on qemu-hppa).
+
+2018-04-20 Paulo Andrade
+
+ * include/lightning/jit_private.h: Add new register classes to
+ flag float registers and double only registers, required for sparc64
+ where only low 32 bit fpr registers can be used for single precision
+ operations.
+ Add new 128 bit jit_regset_t type for sparc64 register set.
+
+ * include/lightning/jit_sparc.h, lib/jit_sparc-cpu.c, lib/jit_sparc-fpu.c,
+ lib/jit_sparc-sz.c, lib/jit_sparc.c: Update for 64 bits sparc.
+
+ * lib/lightning.c: Update for new jit_regset_t required for sparc64.
+
+2018-02-26 Paulo Andrade
+
+ * check/lightning.c, include/lightning.h: Add the new jit_va_push
+ interface. That should be called when passing a va_list to a C
+ function. This is required because on Alpha a va_list is passed
+ by value, and lightning does not know about data types, so, cannot
+ understand it is pushing a va_list as argument.
+
+ * lib/jit_names.c, lib/lightning.c: Minor changes for the new
+ jit_code_va_push.
+
+ * check/cva_list.c: Update only test case using jit_va_push, to
+ pass a va_list to a C function.
+
+ doc/body.texi: Better documentation of the varargs interface.
+
+ * jit_alpha.c, jit_alpha-cpu.c: Update to properly push a
+ C va_list and correctly calculate varargs offset.
+
+ * lib/jit_aarch64-sz.c, lib/jit_aarch64.c, lib/jit_alpha-sz.c,
+ lib/jit_arm-sz.c, lib/jit_arm.c, lib/jit_hppa-sz.c, lib/jit_hppa.c,
+ lib/jit_ia64-sz.c, lib/jit_ia64.c, lib/jit_mips-sz.c, lib/jit_mips.c,
+ lib/jit_ppc-sz.c, lib/jit_ppc.c, lib/jit_s390-sz.c, lib/jit_s390.c,
+ lib/jit_sparc-sz.c, lib/jit_sparc.c, lib/jit_x86-sz.c, lib/jit_x86.c:
+ Update for the new jit_va_push interface.
+
+2018-02-22 Paulo Andrade
+
+ * lib/jit_alpha-cpu.c: Always set t12 to the address of the
+ current function, to properly work on all systems. Previously
+ the shortcut did only work on Tru64. For Linux and glibc the
+ change is required.
+
+2018-02-22 Paulo Andrade
+
+ * lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+ lib/jit_mips.c, lib/jit_ppc.c, lib/jit_sparc.c, lib/jit_x86.c:
+ Correct wrong logic in usage of jit_live in jit_retr. The
+ problem is that if a temporary is required during epilog,
+ the return register might be allocated, so, jit_live must always
+ be used.
+
+2018-01-31 Paulo Andrade
+
+ * lib/lightning.c: Avoid deep recursions when computing live
+ register ranges.
+
+2018-01-31 Paulo Andrade
+
+ * lib/jit_mips-cpu.c: Correct frame size and varargs
+ initialization for the n32 abi.
+ * lib/jit_mips.c, lib/jit_mips-fpu.c: Correct 32 bit abis
+ in big-endian.
+
+2017-09-13 Paulo Andrade
+
+ * configure.ac: Add check for binutils 2.29 prototype to the
+ disassembler function.
+ * lib/jit_disasm.c: Adapt for binutils 2.29 change.
+
+2017-06-09 Paulo Andrade
+
+ * include/lightning/jit_private.h, lib/lightning.c: Add a
+ second pass from start when computing register live ranges.
+ This should be used temporarily, and is required for certain
+ loop constructs, with several consecutive blocks not referencing
+ a live register.
+
+2016-05-05 Paulo Andrade
+
+ * lib/lightning.c: Correct wrong movr simplification,
+ remove no longer needed code to set return registers live
+ and update live register set when reaching a label boundary,
+ but do not descend if the block has been already visited.
+ The later need some tuning for complex code generation, where
+ it will still have issues.
+
+2015-11-30 Paulo Andrade
+
+ * doc/body.texi: Change documentation to no longer say
+ it is a variant of the Fibonacci sequence, and document
+ a proper implementation.
+ Thanks to Jon Arintok for pointing out that the Fibonacci
+ sequence generation was incorrect. It was documented, but
+ still confusing.
+
+ * check/fib.tst, check/fib.ok, check/bp.tst, check/bp.ok,
+ doc/ifib.c, doc/rbif.c: Implement a proper Fibonacci
+ sequence implementation.
+
+2015-07-03 Paulo Andrade
+
+ * lib/jit_mips-cpu.c: Correct definition of htonr_ul.
+ Correct prolog/epilog/va* routines to work on o64 abi.
+
+ * lib/jit_mips-fpu.c: Correct load of double literal
+ argument when not using a data buffer.
+ Remove alignment correction in vaarg_d if using the
+ new mips abi.
+
+ * lib/jit_mips.c: Correct code to allow creating variadic
+ jit functions when using the new mips abi.
+
+ * lib/jit_rewind.c: Minor adjust for rewind when using
+ the new mips abi, if there are varargs arguments in
+ registers.
+
+2015-06-06 Paulo Andrade
+
+ * lib/jit_ia64-cpu.c: Search backward for the last output
+ register used, otherwise would stop too early if a float
+ argument used the slot.
+ Correct offset of first va_list argument, and use proper
+ va_list abi.
+
+ * lib/jit_ia64-fpu.c: Add new functions to move a gpr
+ to a fpr register, to counterpart the ones that move a
+ fpr to a gpr. These are required to properly implement
+ jit_getarg*_{f,d} on complex prototypes, or variadic
+ jit functions.
+
+ * lib/jit_ia64-sz.c: Update for support to jit variadic
+ functions.
+
+ * lib/jit_ia64.c: Implement proper abi for variadic
+ jit functions.
+
+2015-06-04 Paulo Andrade
+
+ * lib/jit_rewind.c: New file implementing generic functions
+ to "rewind", or rewrite IR code sequences.
+
+ * include/lightning.h: Add several new codes, that previously
+ were a function call, that would synthesize the operation.
+ Now, there is a code for the operation, and a new flag to
+ know an operation is synthesized.
+
+ * include/lightning/jit_private.h: Add several new macros to
+ help construct synthesized IR code sequences.
+
+ * lib/Makefile.am: Update for lib/jit_rewind.c.
+
+ * lib/jit_disasm.c: Update for a small rework on jit_node_t,
+ so that --enable-devel-disassembler does not need a change
+ in the layout of jit_node_t.
+
+ * lib/jit_names.c: Update for the new codes.
+
+ * lib/jit_print.c: Update to print more readable output, and
+ flag synthesized IR code sequences.
+
+ * lib/jit_aarch64-sz.c, lib/jit_aarch64.c,
+ lib/jit_arm-sz.c, lib/jit_arm.c, lib/jit_x86-sz.c,
+ lib/jit_x86.c: Update for new synthesized IR code sequences.
+
+ * lib/jit_ppc-cpu.c, lib/jit_ppc-fpu., lib/jit_ppc-sz.c,
+ lib/jit_ppc.c, lib/jit_mips-cpu.c, lib/jit_mips-fpu.c,
+ lib/jit_mips-sz.c, lib/jit_mips.c, lib/jit_s390-fpu.c,
+ lib/jit_s390-sz.c, lib/jit_s390.c: Update for new synthesized
+ IR code sequences and correct bugs in the initial varargs
+ implementation support.
+
+ * lib/jit_alpha-sz.c, lib/jit_alpha.c, lib/jit_hppa-sz.c,
+ lib/jit_hppa.c, lib/jit_ia64-sz.c, lib/jit_ia64.c,
+ lib/jit_sparc-sz.c, lib/jit_sparc.c: Add generic, untested
+ support for the new synthesized IR code sequences. Known
+ most likely broken right now, and should be corrected once
+ access to these hosts is available.
+
+ * lib/lightning.c: Update for new IR codes, and add support
+ for not yet existing instructions that change third argument.
+
+ * size.c: Change to use different tables for LE and BE PowerPC.
+ Correct a wrong endif for x32.
+
+2015-05-25 Paulo Andrade
+
+ * check/cva_list.c: New file implementing a test to ensure
+ the value returned by jit_va_start is a valid C va_list.
+
+ * check/va_list.ok: New simple helper file, as now the
+ va_list.tst test is enabled.
+
+ * check/va_list.tst: Rewritten for an extensive variadic
+ jit functions test.
+
+ * check/Makefile.am: Update for the new tests.
+
+ * lib/jit_arm-cpu.c, lib/jit_arm-swf.c, lib/jit_arm-vfp.c,
+ lib/jit_arm.c: Correct broken software float in a previous
+ commit. Note that the hard float abi implementation is known
+ broken at this time, for special cases involving variadic
+ functions, and should be corrected next.
+
+ lib/jit_x86-cpu.c, lib/jit_x86-sz.c, lib/jit_x86.c: Correct
+ the jit_va_list_t semantics to match C va_list.
+
+2015-05-24 Paulo Andrade
+
+ * lib/Makefile.am: Bump library major. This is a preparation
+ for a rework that was due for quite some time, but that is
+ now required to properly implement variadic jit functions.
+ The rework is mainly required to know at prolog parsing, if
+ a function is variadic or not. This will benefit a few
+ backends, and is mandatory for the hard float arm abi.
+ The rework was already planned for quite some time, to
+ be able to use a variable stack framesize, and for leaf
+ functions optimization where applicable.
+ The change will be source compatible, but will change
+ some internals, and jit_code_t values, as some new will
+ be added.
+ The only behavior change is that, jit_arg_register_p may
+ change return value on hard float arm abi, if called before
+ or after jit_ellipsis. Common sense anyway, would say to
+ make that call after jit_ellipsis, but documentation
+ should be updated for it.
+
+2015-05-24 Paulo Andrade
+
+ * lib/jit_aarch64-fpu.c, lib/jit_aarch64.c: Correct base
+ aarch64 varargs code.
+
+2015-05-24 Paulo Andrade
+
+ * check/lightning.c: Clearly run check if clang is the system
+ compiler.
+
+2015-05-20 Paulo Andrade
+
+ * lib/jit_sparc-cpu.c, lib/jit_sparc-fpu.c, lib/jit_sparc.c:
+ Add base support to jit vararg functions to the sparc backend.
+
+2015-05-20 Paulo Andrade
+
+ * lib/jit_alpha-cpu.c, lib/jit_alpha-fpu.c, lib/jit_alpha.c:
+ Add base support to jit vararg functions to the alpha backend.
+
+2015-05-19 Paulo Andrade
+
+ * lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c, lib/jit_hppa.c:
+ Add base support to jit vararg functions to the hppa backend.
+
+2015-05-10 Paulo Andrade
+
+ * lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c, lib/jit_ia64.c:
+ Add base support to jit vararg functions to the ia64 backend.
+
+2015-05-10 Paulo Andrade
+
+ * lib/jit_ia64-fpu.c, lib/jit_ia64.c: Correct movi_d_w
+ and movi_f_w implementation to work when not using a
+ data buffer. This causes the check varargs.tst to
+ work when passing "-d" to the lightning test tool.
+
+2015-05-10 Paulo Andrade
+
+ * lib/jit_ia64.c: Implement inline assembly cache flush,
+ required on multiprocessor systems.
+
+2015-05-06 Paulo Andrade
+
+ * lib/jit_mips-cpu.c, lib/jit_mips-fpu.c, lib/jit_mips.c:
+ Add base support to jit vararg functions to the mips backend.
+ Currently only supported on the o32 abi, until access to a
+ n32 system is arranged.
+
+2015-05-05 Paulo Andrade
+
+ * lib/jit_ppc-cpu.c, lib/jit_ppc-fpu.c, lib/jit_ppc.c:
+ Add base support to jit vararg functions to the PowerPC backend.
+
+2015-05-02 Paulo Andrade
+
+ * lib/jit_s390-cpu.c, lib/jit_s390-fpu.c, lib/jit_s390.c:
+ Add base support to jit vararg functions to the s390 backend.
+
+2015-05-01 Paulo Andrade
+
+ * lib/jit_arm-cpu.c, lib/jit_arm-swf.c, lib/jit_arm-vfp.c,
+ lib/jit_arm.c: Add base support to jit vararg
+ functions to the arm backend.
+
+2015-04-30 Paulo Andrade
+
+ * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c,
+ lib/jit_aarch64.c: Add base support to jit vararg
+ functions to the aarch64 backend.
+
+2015-04-27 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ lib/jit_names.c, lib/lightning.c: Add initial support
+ for the new jit_va_start, jit_va_arg, jit_va_arg_d, and
+ jit_va_end interfaces. The jit_va_start call is supposed
+ to return a va_list compatible pointer, but not yet
+ decided if it will be "declared" stdarg compatible,
+ as for now only x86 support has been added (and should
+ be compatible), but issues may arise on other backends.
+
+ * check/lightning.c: Add wrappers to call the new jit_va_*
+ interfaces.
+
+ * lib/jit_x86-cpu.c, lib/jit_x86.c: Implement the new
+ jit_va_* for x86.
+
+ * lib/jit_x86-sz.c: Add fields, but not yet fully updated,
+ as this is an intermediate commit.
+
+ * lib/jit_aarch64-sz.c, lib/jit_aarch64.c,
+ lib/jit_alpha-sz.c, lib/jit_alpha.c,
+ lib/jit_arm-sz.c, lib/jit_arm.c,
+ lib/jit_hppa-sz.c, lib/jit_hppa.c,
+ lib/jit_ia64-sz.c, lib/jit_ia64.c,
+ lib/jit_mips-sz.c, lib/jit_mips.c,
+ lib/jit_ppc-sz.c, lib/jit_ppc.c,
+ lib/jit_s390-sz.c, lib/jit_s390.c,
+ lib/jit_sparc-sz.c, lib/jit_sparc.c: Prepare for the
+ new jit_va_* interfaces. Not yet implemented, and will
+ cause an assertion if used.
+
+ * check/va_list.tst: Simple early test case, that works
+ on x86_64, x32, ix86, cygwin, and cygwin64.
+
+2015-02-17 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ lib/jit_aarch64-cpu.c, lib/jit_aarch64.c,
+ lib/jit_alpha-cpu.c, lib/jit_alpha.c,
+ lib/jit_arm-cpu.c, lib/jit_arm.c,
+ lib/jit_hppa-cpu.c, lib/jit_hppa.c,
+ lib/jit_ia64-cpu.c, lib/jit_ia64.c,
+ lib/jit_mips-cpu.c, lib/jit_mips.c,
+ lib/jit_ppc-cpu.c, lib/jit_ppc.c,
+ lib/jit_s390-cpu.c, lib/jit_s390.c,
+ lib/jit_sparc-cpu.c, lib/jit_sparc.c,
+ lib/jit_x86-cpu.c, lib/jit_x86.c: Implement the new
+ jit_allocar(offs, size) interface, that receives
+ two integer registers arguments, allocates space
+ dynamically in the stack, returns the offset in
+ the first argument, and uses the second argument
+ for the size in bytes of the memory to be allocated.
+
+ * check/allocar.ok, check/allocar.tst: New files
+ implementing test cases for the new jit_allocar
+ interface.
+
+ * check/Makefile.am, check/lightning.c: Update for
+ the new test case and interface.
+
+ * doc/body.texi: Add documentation of the new
+ interface.
+
+2015-02-17 Paulo Andrade
+
+ * include/lightning/jit_x86.h, lib/jit_x86-cpu.c,
+ lib/jit_x86-x87.c: No longer make st(7) available.
+ Need to keep one x87 slots empty to avoid exceptions.
+ This has the side effect of no longer needing the
+ hackish emms instruction before a function call.
+
+2015-02-16 Paulo Andrade
+
+ * lib/lightning.c: Remove the jit_regno_patch bitfield
+ register fields before actual emit, as it is only really
+ used before emit, otherwise, on special conditions it
+ may consider live registers as dead during code emit.
+
+2015-02-15 Paulo Andrade
+
+ * lib/jit_x86-cpu.c, lib/jit_x86-sse.c, lib/jit_x86-x87.c:
+ Correct encoding of ldxr* stxr* in the x32 abi. If the
+ displacement register is negative, it would generate
+ a 64 bit instruction with a 32 bit unsigned displacement.
+
+ * check/ranger.tst, check/ranger.ok: New files, implementing
+ a test case for negative loads and stores. This is range.tst
+ converted to use registers instead of immediate offsets.
+
+ check/Makefile.am: Update for the new test case.
+
+2015-02-07 Paulo Andrade
+
+ * lib/jit_size.c: Preventively use at least 144 bytes
+ if JIT_INSTR_MAX is less than it. The logic is not
+ guaranteed to be 100% precise, it is mostly heuristics
+ to allocate a buffer with as close as possible size,
+ but a wrong value may cause code generation to write
+ past the end of the buffer.
+
+2015-02-03 Paulo Andrade
+
+ * lib/lightning.c: Correct the reason the bug in
+ simplify_stxi was not triggered before, it was due to
+ incorrectly resetting the value->code field, what was
+ causing it to never properly optimize:
+ stxi Im0 Rb0 Rt0
+ ldxi Rt1 Rb1 Im1
+ when Rb0 == Rb1, Rt0 == Rt1 and Im0 == Im1
+ There was another possible issue, that has been also
+ addressed in this commit, that would be the case of
+ Rbn == Rtn, where no redundancy removal is possible.
+
+2015-02-03 Paulo Andrade
+
+ * lib/lightning.c: Correct wrong check in simplify_stxi.
+ The test was incorrectly comparing the target register
+ and the displacement offset. This was a time bomb bug,
+ that would trigger in code like:
+ stxi Im0 Rb0 Rt0
+ stxi Im1 Rb1 Rt1
+ if Rb0 == Rb1 && Rt0 == Rt1 && Im0 == Rt1, that is,
+ the wrong check was Im0 == Rt1, instead of the supposed
+ Im0 == Imm1 (that was what the code mean't to do). It
+ was removing the second stxi assuming it was redundantly
+ generated; as that is not uncommon pattern on
+ translators generating jit.
+
+2015-02-02 Paulo Andrade
+
+ * configure.ac, include/lightning/jit_private.h,
+ lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+ lib/jit_disasm.c, lib/jit_hppa.c, lib/jit_ia64.c,
+ lib/jit_mips.c, lib/jit_ppc.c, lib/jit_print.c,
+ lib/jit_s390.c, lib/jit_sparc.c, lib/jit_x86.c: Add a new
+ --enable-devel-disassembler option, that should be used
+ during development, or lightning debug. This option
+ intermixes previous jit_print and jit_disassemble
+ output, making it easier to visualize what lightning
+ call was used, and what code was generated.
+
+2015-01-31 Paulo Andrade
+
+ * lib/jit_arm-cpu.c, lib/jit_arm.c: Only limit to 24 bit
+ displacement non conditional jump in the same jit_state_t.
+
+2015-01-19 Paulo Andrade
+
+ * doc/body.texi: Reorder documentation, making jit_frame
+ and jit_tramp the lightning response to the need of
+ trampolines, continuations and tail call optimizations.
+ A pseudo code example of a factorial function was added.
+ Also added a section for description of the available
+ predicates.
+
+ * doc/fact.c: New file, implementing a simple example of
+ a translation of a trivial, recursive, tail call optimization
+ into lightning calls. This is the conversion to functional C
+ code of the example in doc/body.texi.
+
+ * doc/Makefile.am: Update for the next test case.
+
+2015-01-17 Paulo Andrade
+
+ * include/lightning.h, lib/jit_aarch64.c,
+ lib/jit_alpha.c, lib/jit_arm-vfp.c, lib/jit_arm.c,
+ lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_mips.c,
+ lib/jit_ppc.c, lib/jit_s390.c, lib/jit_sparc.c,
+ lib/jit_x86.c: Add the new jit_arg_register_p predicate.
+ The predicate is expected to be used to know if an
+ argument is in a register, what would need special
+ handling if code that can overwrite non callee save
+ registers is executed.
+
+ * check/carg.c: New test case to check consistency and
+ expected usage of jit_arg_register_p.
+
+ * check/Makefile.am: Update for new test case.
+
+2015-01-17 Paulo Andrade
+
+ * include/lightning/jit_aarch64.h,
+ include/lightning/jit_alpha.h,
+ include/lightning/jit_arm.h,
+ include/lightning/jit_hppa.h,
+ include/lightning/jit_mips.h,
+ include/lightning/jit_ppc.h,
+ include/lightning/jit_s390.h,
+ include/lightning/jit_sparc.h,
+ include/lightning/jit_x86.h,
+ lib/jit_aarch64.c, lib/jit_alpha.c,
+ lib/jit_arm.c, lib/jit_hppa.c,
+ lib/jit_ia64.c, lib/jit_mips.c,
+ lib/jit_ppc.c, lib/jit_s390.c,
+ lib/jit_sparc.c, lib/jit_x86.c: Remove jit_arg_reg_p and
+ jit_arg_f_reg_p from a public header, and define it only
+ on port specific files where an integer offset is used
+ to qualify an argument identifier. Exported code expects
+ an opaque pointer (but of jit_node_t* type) to "qualify"
+ an argument identifier.
+ This patch, and the code review/simplification done during
+ it also corrected some bugs:
+ o Inconsistent jit_arg_d value of double argument after 3
+ integer arguments in arm for jit_functions; tested, C
+ functions were being properly called.
+ o Inconsistent use of getarg_{f,d} and putarg*_{f,d} on
+ s390 (32-bit) that happened to not have a proper test
+ case, as it would only happen for jit functions, and
+ tested, called C functions had proper arguments.
+ o Corrected a "last minute" correction that did not go
+ to the committed version, and would not compile on hppa,
+ due to bad _jit_putargi_d prototype definition.
+
+2015-01-17 Paulo Andrade
+
+ * doc/body.texi: Correct wrong/outdated information for
+ hton*, pusharg* and ret*, and add missing documentation
+ for rsb*, qmul*, qdvi* and putarg*.
+
+2015-01-15 Paulo Andrade
+
+ * configure.ac, lib/jit_disasm.c: Rewrite workaround
+ to apparent problem to initialize powerpc disassembler.
+
+2015-01-15 Paulo Andrade
+
+ * include/lightning.h, lib/jit_aarch64.c,
+ lib/jit_alpha.c, lib/jit_arm.c, lib/jit_hppa.c,
+ lib/jit_ia64.c, lib/jit_mips.c, lib/jit_ppc.c,
+ lib/jit_s390.c, lib/jit_sparc.c, lib/jit_x86.c:
+ Implement jit_putarg*. It works as a mix of jit_getarg*
+ and jit_pusharg*, in the way that the first argument is
+ a register or immediate, and the second is a pointer
+ returned by jit_arg*. The use of the interface is to change
+ values of arguments to the current jit function.
+
+ * check/put.ok, check/put.tst: New test cases exercising
+ the new jit_putarg* interface.
+
+ * check/Makefile.am, check/lightning.c: Update for the
+ new test case and interface.
+
+2015-01-08 Paulo Andrade
+
+ * include/lightning/jit_s390.h, lib/jit_s390-cpu.c,
+ lib/jit_s390-fpu.c, lib/jit_s390-sz.c, lib/jit_s390.c:
+ Renamed s390x* files to s390*.
+
+ * check/float.tst, check/lightning.c, configure.ac,
+ include/lightning.h, include/lightning/Makefile.am,
+ lib/Makefile.am, lib/jit_s390.c, lib/jit_size.c,
+ lib/lightning.c: Update for renamed files.
+
+2015-01-08 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ include/lightning/jit_s390x.h, lib/jit_disasm.c,
+ lib/jit_s390x-cpu.c, lib/jit_s390x-fpu.c, lib/jit_s390x-sz.c,
+ lib/jit_s390x.c, lib/jit_size.c, lib/lightning.c:
+ Add support for generating jit for s390 32 bit. This change
+ also removed %f15 from the list of temporaries fpr registers;
+ it was not being used, but if were, it would corrupt the
+ stack frame because the spill address would overwrite grp
+ offsets.
+
+2014-12-26 Paulo Andrade
+
+ * lib/jit_ppc-cpu.c, lib/jit_ppc.c: Correct some endianess issues
+ on the powerpc le backend.
+
+2014-12-26 Paulo Andrade
+
+ * lib/jit_ppc-cpu.c: Add mcrxr instruction emulation,
+ as this instruction has been phased out, and should be
+ implemented as a kernel trap.
+
+2014-12-26 Paulo Andrade
+
+ * lib/jit_arm.c: Better check for need to flush constants
+ before the pool being no longer reachable.
+
+2014-12-25 Paulo Andrade
+
+ * include/lightning.h: Split jit_htonr in the new 3 interfaces
+ jit_htonr_us, jit_htonr_ui and jit_htonr_ul, the later only
+ available on 64 bit. The plain/untyped jit_htonr macro call
+ maps to the wordsize one.
+ * lib/jit_aarch64-cpu.c, lib/jit_aarch64-sz.c, lib/jit_aarch64.c,
+ lib/jit_alpha-cpu.c, lib/jit_alpha-sz.c, lib/jit_alpha.c,
+ lib/jit_arm-cpu.c, lib/jit_arm-sz.c, lib/jit_arm.c,
+ lib/jit_hppa-cpu.c, lib/jit_hppa-sz.c, lib/jit_hppa.c,
+ lib/jit_ia64-cpu.c, lib/jit_ia64-sz.c, lib/jit_ia64.c,
+ lib/jit_mips-cpu.c, lib/jit_mips-sz.c, lib/jit_mips.c,
+ lib/jit_ppc-cpu.c, lib/jit_ppc-sz.c, lib/jit_ppc.c,
+ lib/jit_s390x-cpu.c, lib/jit_s390x-sz.c, lib/jit_s390x.c,
+ lib/jit_sparc-cpu.c, lib/jit_sparc-sz.c, lib/jit_sparc.c,
+ lib/jit_x86-cpu.c, lib/jit_x86-sz.c, lib/jit_x86.c:
+ Update backends for the new jit_htonr*.
+ * check/lightning.c, lib/jit_names.c, lib/lightning.c:
+ Update for the new jit_htonr* interfaces.
+ * check/Makefile.am: Update for new test cases.
+ * check/hton.ok, check/hton.tst: New test cases.
+
+2014-12-24 Paulo Andrade
+
+ * include/lightning/jit_private.h, include/lightning/jit_x86.h,
+ lib/jit_disasm.c, lib/jit_x86-cpu.c, lib/jit_x86-sse.c,
+ lib/jit_x86-sz.c, lib/jit_x86-x87.c, lib/jit_x86.c,
+ size.c: Implement support for the x32 abi. Built and
+ tested on Gentoo default/linux/amd64/13.0/x32 profile.
+
+2014-12-24 Paulo Andrade
+
+ * lib/jit_names.c: Add missing rsbi_f and rsbi_d strings.
+
+2014-12-21 Paulo Andrade
+
+ * lib/jit_arm.c: Call __clear_cache for every page.
+ This should only be required for older boards or
+ toolchain setup, but has been reported to be required
+ for lightning at some point.
+
+2014-12-21 Paulo Andrade
+
+ * lib/jit_arm.c: Correct check to guard overflow of index
+ of constants from program counter.
+
+2014-11-24 Paulo Andrade
+
+ * lib/lightning.c: Remove an optimization to calee save
+ registers that may incorrectly remove a jit_movr under
+ special conditions.
+
+2014-11-20 Paulo Andrade
+
+ * include/lightning/jit_ppc.h, lib/jit_ppc-cpu.c,
+ lib/jit_ppc.c: Add initial powerpc le support.
+
+2014-11-20 Paulo Andrade
+
+ * lib/jit_disasm.c: Change thumb or arm disassemble based on
+ jit code before disassembly.
+
+ * lib/jit_arm-cpu.c: Correct reversed arguments to LDRD and
+ STRD instructions, and correct checking for support of those.
+
+ * lib/jit_arm-swf.c: Correct wrong use of LDRD and STRD and
+ only use those if the register is even.
+
+ * check/check.arm.swf.sh, check/check.arm4.swf.sh: New files
+ to test LDRD and STRD, as well as the alternate code path
+ when those are not available, in the .arm4. test case.
+
+ * check/Makefile.am: Update for the new test cases.
+
+2014-11-08 Paulo Andrade
+
+ * include/lightning/jit_private.h, lib/jit_aarch64.c,
+ lib/jit_alpha.c, lib/jit_arm.c, lib/jit_hppa.c,
+ lib/jit_ia64.c, lib/jit_mips.c, lib/jit_ppc.c,
+ lib/jit_s390x.c, lib/jit_sparc.c, lib/jit_x86.c:
+ Implement a private jit_flush call, that flushes
+ the cache, if applicable, aligning down to the
+ previous and up to the next page boundary.
+
+2014-11-08 Paulo Andrade
+
+ * check/ctramp.c: New file. It just repeats the test
+ of tramp.tst, but using two jit_state_t, what should
+ test possible issues with two contexts, and also validate
+ jit_tramp works on backends with function descriptions.
+
+ * check/Makefile.am: Update for new test case.
+
+2014-11-03 Paulo Andrade
+
+ * include/lightning/jit_mips.h: Do not make the t9 register
+ JIT_R11 (or JIT_R7 for n32 or n64 abi) available. Previously
+ it cause problems if one expects it to not be changed in a
+ function call. For example, calling a jit function, where it
+ really does not need to be changed.
+
+2014-10-26 Paulo Andrade
+
+ * lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+ lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_mips.c, lib/jit_ppc.c,
+ lib/jit_s390x.c, lib/jit_sparc.c, lib/jit_x86.c: Add an
+ assertion to all code generation "drivers" to ensure
+ _jitc->regarg is empty or in an expected state, after
+ translation of a lightning instruction to native code.
+ This change was a brute force test to find out other cases
+ of a temporary not being release (like was happening with
+ _bmsi and _bmci on x86), but no other case was found,
+ after running make check, with assertions enabled, on all
+ backends.
+
+2014-10-26 Paulo Andrade
+
+ * lib/jit_x86-cpu.c: Correct a register allocation leak in
+ _bmsi and _bmci.
+
+2014-10-25 Paulo Andrade
+
+ * lib/jit_disasm.c: Do not cause an fatal error if init_jit
+ fails in the jit_init_debug call.
+
+2014-10-24 Paulo Andrade
+
+ * lib/jit_ia64.c, lib/jit_ppc.c: Correct handling of function
+ descriptor when first prolog is a jit_tramp prolog. The
+ test case was using the same jit_context_t, so was not
+ triggering this condition.
+
+ * lib/jit_ppc-cpu.c: Properly handle jump displacements that
+ do not fit on 24 powerpc. This required changing from previous
+ "mtlr reg, blr" to "mtctr reg, bctr" to properly handle
+ the logic to "hide" function descriptors, but that would
+ also be required as the proper jit_jmpr when/if implementing
+ optimizations to leaf functions (was working with blr because
+ it is saved/reloaded in prolog/epilog).
+
+2014-10-21 Paulo Andrade
+
+ * include/lightning.h, lib/lightning.c: Add three predicates
+ to query information about labels. jit_forward_p(label)
+ will return non zero if the label is "forward", that is
+ need a call to jit_link(label), jit_indirect_p(label)
+ that returns non zero if the label was created with the
+ jit_indirect() call, and jit_target_p(label) that will
+ return non zero if there is at least one jump patched
+ to land at that label.
+
+2014-10-18 Paulo Andrade
+
+ * check/range.ok, check/range.tst: New test case designed
+ to catch incorrect code generation, usually due to incorrect
+ test of immediate size. The test checks a large amount of
+ encodings in "power of two" boundaries. This test exorcises
+ a significant amount of code paths that was previously not
+ tested.
+
+ * check/Makefile.am: Add range test to make check target.
+
+ * lib/jit_aarch64-cpu.c: Correct wrong address calculation
+ for stxi_c, stxi_s, stxi_i and stxi_l when the offset is
+ too large.
+
+ * lib/jit_mips-fpu.c: Correct wrong size test to check if
+ an immediate can be encoded in a float or double store.
+
+ * lib/jit_s390x-cpu.c: Correct inverted encoding to stxi_s
+ when the offset cannot be encoded, and fallbacks to an
+ alternate encoding in 2 instructions.
+
+2014-10-17 Paulo Andrade
+
+ * check/alu_rsb.ok, check/alu_rsb.tst: New files implementing
+ tests for jit_rsb*.
+
+ * check/Makefile.am, check/lightning.c, include/lightning.h,
+ lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c, lib/jit_aarch64-sz.c,
+ lib/jit_aarch64.c, lib/jit_alpha-cpu.c, lib/jit_alpha-fpu.c,
+ lib/jit_alpha-sz.c, lib/jit_alpha.c, lib/jit_arm-cpu.c,
+ lib/jit_arm-swf.c, lib/jit_arm-sz.c, lib/jit_arm-vfp.c,
+ lib/jit_arm.c, lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c,
+ lib/jit_hppa-sz.c, lib/jit_hppa.c, lib/jit_ia64-cpu.c,
+ lib/jit_ia64-fpu.c, lib/jit_ia64-sz.c, lib/jit_ia64.c,
+ lib/jit_mips-cpu.c, lib/jit_mips-fpu.c, lib/jit_mips-sz.c,
+ lib/jit_mips.c, lib/jit_names.c, lib/jit_ppc-cpu.c,
+ lib/jit_ppc-fpu.c, lib/jit_ppc-sz.c, lib/jit_ppc.c,
+ lib/jit_s390x-cpu.c, lib/jit_s390x-fpu.c, lib/jit_s390x-sz.c,
+ lib/jit_s390x.c, lib/jit_sparc-cpu.c, lib/jit_sparc-fpu.c,
+ lib/jit_sparc-sz.c, lib/jit_sparc.c, lib/jit_x86-cpu.c,
+ lib/jit_x86-sse.c, lib/jit_x86-sz.c, lib/jit_x86-x87.c,
+ lib/jit_x86.c, lib/lightning.c: Implement jit_rsb*. This
+ was a missing lightning 1.x interface, that on most
+ backends is synthesized, but on a few backends (hppa and ia64),
+ it can generate better code as on those there is, or the
+ only instruction with an immediate is in "rsb" format
+ (left operand).
+
+2014-10-17 Paulo Andrade
+
+ * lib/jit_names.c: New file with single definition of string
+ representation of lightning IR codes.
+
+ * size.c: Modified to append the code name in a C comment
+ after the maximum instruction size.
+
+ * lib/jit_print.c: Minor change to not duplicate jit_names.c
+ contents.
+
+ * lib/jit_aarch64-sz.c, lib/jit_alpha-sz.c, lib/jit_arm-sz.c,
+ lib/jit_hppa-sz.c, lib/jit_ia64-sz.c, lib/jit_mips-sz.c,
+ lib/jit_ppc-sz.c, lib/jit_s390x-sz.c, lib/jit_sparc-sz.c,
+ lib/jit_x86-sz.c: Rewritten to add string representation of
+ IR codes in a C comment.
+
+2014-10-14 Paulo Andrade
+
+ * lib/jit_aarch64-cpu.c, lib/jit_alpha-cpu.c, lib/jit_arm-cpu.c,
+ lib/jit_hppa-cpu.c, lib/jit_mips-cpu.c, lib/jit_ppc-cpu.c,
+ lib/jit_sparc-cpu.c: Implement or correct the internal
+ nop(count) call that receives an argument that tells the
+ modulo bytes to align the code for the next instruction.
+
+ * include/lightning.h, lib/lightning.c, lib/jit_aarch64.c,
+ lib/jit_alpha.c, lib/jit_arm.c, lib/jit_hppa.c, lib/jit_ia64.c,
+ lib/jit_mips.c, lib/jit_ppc.c, lib/jit_s390x.c, lib/jit_sparc.c,
+ lib/jit_x86.c: Implement the new jit_align() call that receive
+ an argument, that tells the modulo, in bytes, to align the
+ next instruction. In most backends the only value that makes
+ a difference is a value that matches sizeof(void*), as all
+ other values usually are already automatically aligned in
+ labels, but not guaranteed to be aligned at word size bytes.
+
+ * check/align.ok, check/align.tst: New files, implementing
+ a simple test for the new jit_align() interface.
+
+ * check/Makefile.am, check/lightning.c, lib/jit_aarch64-sz.c,
+ lib/jit_alpha-sz.c, lib/jit_arm-sz.c, lib/jit_hppa-sz.c,
+ lib/jit_ia64-sz.c, lib/jit_mips-sz.c, lib/jit_ppc-sz.c,
+ lib/jit_print.c, lib/jit_s390x-sz.c, lib/jit_sparc-sz.c,
+ lib/jit_x86-sz.c: Update for the new jit_code_align code and
+ the jit_align() interface.
+
+2014-10-13 Paulo Andrade
+
+ * include/lightning.h, lib/jit_size.c, size.c: Use a
+ symbolic value for the last IR code.
+
+2014-10-12 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ lib/jit_aarch64-cpu.c, lib/jit_alpha-cpu.c, lib/jit_arm-cpu.c,
+ lib/jit_hppa-cpu.c, lib/jit_ia64-cpu.c, lib/jit_mips-cpu.c,
+ lib/jit_ppc-cpu.c, lib/jit_s390x-cpu.c, lib/jit_sparc-cpu.c,
+ lib/jit_x86-cpu.c, lib/lightning.c: Implement the new
+ jit_frame and jit_tramp interfaces, that allow writing
+ trampoline like calls, where a single dispatcher jit buffer
+ is written, and later other jit buffers are created, with
+ the same stack frame layout as the dispatcher. This is the
+ logic that GNU Smalltalk used in lightning 1.x, and is required
+ to make a sane port for lighting 2.x.
+
+ * jit_ia64-cpu.c: Implement support for jit_frame and jit_tramp,
+ and also correct wrong encoding for B4 instructions, that
+ implement jmpr, as well as correct reverse logic in _jmpr,
+ that was moving the branch register to the jump register,
+ and not vice-versa.
+ Also, if a stack frame is to be assumed, always assume it may
+ call a function with up to 8 arguments, regardless of the
+ hint frame argument.
+
+ * lib/jit_arm.c: Add a new must_align_p() interface to ensure
+ function prologs are always aligned. This condition was
+ previously always true, somewhat by accident, but with
+ jit_tramp it is not guaranteed.
+
+ * jit_ia64-cpu.c: lib/jit_ppc.c: Add minor special handling
+ required to implement jit_tramp, where a function descriptor
+ should not be added before a prolog, as jit_tramp means omit
+ prolog.
+
+ * check/lightning.c: Update test driver for the new interfaces.
+
+ * check/Makefile.am, check/tramp.tst, check/tramp.ok: Add
+ a simple test and example of the jit_frame and jit_tramp
+ usage implementing a simple Fibonacci function using a
+ simulation of an interpreter stack and how it would handle
+ state in language specific variables.
+
+ * doc/body.texi: Add documentation for jit_frame and
+ jit_tramp.
+
+2014-09-29 Paulo Andrade
+
+ * lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+ lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_mips.c,
+ lib/jit_ppc.c, lib/jit_s390x.c, lib/jit_sparc.c,
+ lib/jit_x86.c, lib/lightning.c: Allow jit_jmpi on a
+ target that is not a node. This may lead to hard to
+ debug code generation, but is a required feature for
+ certain generators, like the ones that used lightning
+ 1.2x. Note that previously, but not really well
+ documented, it was instructed to use:
+ jit_movi(rn, addr); jit_jmpr(rn);
+ but now, plain:
+ jit_patch_abs(jit_jmpi(), addr);
+ should also work.
+
+2014-09-24 Paulo Andrade
+
+ * lib/jit_x86-sz.c: Generate information about instruction
+ lengths for more precise calculation of buffer size on
+ Windows x64. This change is specially important because
+ the maximum instruction length is larger than other
+ systems, what could cause an out of bounds write on
+ special conditions without this update.
+
+2014-09-24 Paulo Andrade
+
+ * check/lightning.c: Add workaround to conflicting global
+ optind variable in cygwin binutils that have an internal
+ getopt* implementation.
+
+ * lib/jit_x86-cpu.c: Add a simple define ffsl ffs if building
+ for 32 bit and there is no ffsl function.
+
+2014-09-24 Paulo Andrade
+
+ * check/lightning.c: Add a hopefully temporary kludge to not use
+ sprintf and sscanf returned by dlsym. This is required to pass
+ the varargs test.
+
+ * include/lightning/jit_private.h: Use symbolic name for first
+ integer register argument, as this is different in sysv and
+ win64 abi.
+
+ * include/lightning/jit_x86.h: Add conditionals and definitions
+ for Windows x64 (under __CYGWIN__ preprocessor conditional).
+
+ * lib/jit_x86-cpu.c: Correct one instruction encoding bug, that
+ was working by accident. Only use rax to rdx for some byte
+ operations to work on compatibility mode (that is, to generate
+ the proper encoding, instead of actually generating encoding
+ for high byte registers, e.g. %bh).
+ Add proper prolog and epilog for windows x64.
+
+ * lib/jit_x86-sse.c: Correct a swapped rex prefix for float
+ operations.
+
+ * lib/jit_x86.c: Adjust to support Windows x64 abi.
+
+ * check/check.x87.nodata.sh: New file, previously used but that
+ was missing git.
+
+2014-09-07 Paulo Andrade
+
+ * lib/lightning.c: Mark all registers advertised as live, as
+ per jit_callee_save_p as live whenever reaching a jump that
+ cannot be tracked. This is a rethink of the previous commit,
+ and is a better approach, otherwise there would not be much
+ sense on relying on jit_callee_save_p if it could not be
+ trusted.
+
+ * check/jmpr.tst, check/jmpr.ok: New files implementing a very
+ simple test case, that would actually cause an assertion on
+ code before the change to only mark as live when reaching a
+ jump that could not tracked, the actually advertised as callee
+ save registers.
+
+ check/Makefile.am: Update for new jmpr test case.
+
+2014-09-01 Paulo Andrade
+
+ * lib/lightning.c: Do not mark all registers in unknown state
+ as live on jit_jmpr, or jit_jmpi to an absolute address. Instead,
+ treat it as a function call, and only consider JIT_Vn registers
+ as possibly live.
+
+2014-08-29 Paulo Andrade
+
+ * doc/body.texi: Add a proper info menu entry for
+ GNU lightning.
+
+ * doc/version.texi: Regenerate.
+
+2014-08-16 Paulo Andrade
+
+ * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c,
+ lib/jit_arm-cpu.c, lib/jit_arm-vfp.c,
+ lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c,
+ lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c,
+ lib/jit_mips-cpu.c, lib/jit_mips-fpu.c,
+ lib/jit_ppc-cpu.c, lib/jit_ppc-fpu.c,
+ lib/jit_s390x-cpu.c, lib/jit_s390x-fpu.c,
+ lib/jit_s390x.c, lib/jit_sparc-cpu.c,
+ lib/jit_x86-cpu.c, lib/jit_x86-sse.c,
+ lib/jit_x86-x87.c: Review generation of all branch
+ instructions and always adds the jit_class_nospill
+ bitfield for temporary registers that cannot be spilled
+ because the reload would be after a conditional jump; the
+ patch only adds an extra assertion. These conditions do
+ not happen on documented lightning usage, but can happen
+ if one uses the not exported jit_get_reg and jit_unget_reg
+ calls and cause enough register starvation.
+
+2014-08-16 Paulo Andrade
+
+ * lib/jit_alpha.c: Correct wrong bitmask of most argument
+ float register arguments, that were being set as callee
+ save instead of argument registers class.
+
+2014-08-16 Paulo Andrade
+
+ * lib/jit_arm-sz.c: Regenerate table of known maximum
+ instruction sizes for the software float fallback,
+ that implements "virtual" float registers in the stack
+ and operations as calls to libgcc.
+
+ * size.c: Correct typo in the generated jit_arm-sz.c file.
+
+2014-08-10 Paulo Andrade
+
+ * include/lightning/jit_alpha.h, lib/jit_alpha-cpu.c,
+ lib/jit_alpha-fpu.c, lib/jit_alpha-sz.c, lib/jit_alpha.c:
+ New files implementing a lightning Alpha port. Thanks
+ to Trent Nelson and snakebit.net staff for providing access
+ to an Alpha system.
+
+ * check/float.tst, check/lightning.c, configure.ac,
+ include/lightning.h, include/lightning/Makefile.am,
+ include/lightning/jit_private.h, lib/Makefile.am,
+ lib/jit_disasm.c, lib/jit_size.c, lib/lightning.c:
+ Minor changes to adapt for the new Alpha port.
+
+2014-08-10 Paulo Andrade
+
+ * lib/lightning.c: Always mark JIT_RET and JIT_FRET as
+ live in a function epilog. This is required because
+ on some ports a complex sequence, allocating one or more
+ registers, may be required to jump from a ret* to the
+ epilog, and the lightning api does not have annotations
+ to know if a function returns a value, or the type of
+ the return value.
+
+2014-08-10 Paulo Andrade
+
+ * lib/lightning.c: Change the correct live bitmask of
+ return registers after a function call in jit_update.
+
+2014-08-10 Paulo Andrade
+
+ * lib/lightning.c: Change assertions to have an int
+ result and correct a bad bit mask assertion.
+
+2014-08-10 Paulo Andrade
+
+ * lib/jit_aarch64.c: Correct bad setup for assertion
+ of consistency before a patch.
+
+2014-08-10 Paulo Andrade
+
+ * lib/jit_mips-cpu.c: Correct typo in the jit_bmsr
+ implementation that was using the wrong test result
+ register.
+
+2014-07-28 Paulo Andrade
+
+ * lib/jit_memory.c: Do not call free on NULL pointers.
+
+ * include/lightning/jit_private.h, lib/jit_note.c,
+ lib/lightning.c: Add a wrapper to memcpy and memmove
+ to not actually call those functions with a zero size
+ argument, and likely also a null src or dst.
+
+2014-07-27 Paulo Andrade
+
+ * include/lightning/jit_private.h, lib/jit_disasm.c,
+ lib/lightning.c: Remove the global jit_progname variable.
+ It was being only used in jit_init_debug, that is called
+ from init_jit, so, just pass an argument.
+
+2014-07-27 Paulo Andrade
+
+ * doc/body.texi: Add note that jit_set_memory_functions
+ should be called before init_jit, because init_jit
+ itself may call the memory wrappers.
+
+2014-04-22 Paulo Andrade
+
+ * lib/jit_arm.c: Do not get confused with default settings
+ if /proc is not mounted on Linux specific code path.
+
+2014-04-09 Paulo Andrade
+
+ * include/lightning/jit_aarch64.h, include/lightning/jit_arm.h,
+ include/lightning/jit_hppa.h, include/lightning/jit_ia64.h,
+ include/lightning/jit_mips.h, include/lightning/jit_ppc.h,
+ include/lightning/jit_private.h, include/lightning/jit_s390x.h,
+ include/lightning/jit_sparc.h, include/lightning/jit_x86.h:
+ Do not add jit_regset_t, JIT_RA0, and JIT_FA0 to the installed
+ header file. These types and definitions are supposed to be
+ only used internally.
+
+2014-04-05 Paulo Andrade
+
+ * lib/jit_arm-cpu.c: Only adjust stack pointer in prolog if
+ need stack space, that is, do not emit a nop instruction
+ subtracting zero from the stack pointer.
+
+2014-04-04 Paulo Andrade
+
+ * lib/jit_disasm.c: Correct a crash in the doc/printf example
+ on arm due to releasing the data_info information in
+ jit_clear_state. This is a special case for arm only, and
+ actually, only armv5 or older uses the data_info buffer,
+ or when forcing arm instruction set mode besides thumb
+ available.
+
+2014-12-03 Paulo Andrade
+
+ * doc/body.texi: Write detailed description and examples for
+ jit_get_memory_functions, jit_set_memory_functions,
+ jit_get_code, jit_set_code, jit_get_data and jit_set_data.
+
+2014-12-03 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ lib/lightning.c: Implement the new jit_set_data() interface,
+ and the new jit_get_data() helper. Like jit_set_code(),
+ jit_realize() should be called before jit_set_data().
+ The most common usage should be jit_set_data(JIT_DISABLE_DATA
+ | JIT_DISABLE_NOTE), to force synthesize any float/double
+ constant in the stack and not generate any debug information.
+
+ * lib/jit_note.c: Minor change to debug note generation as
+ now it uses an alternate temporary data buffer during constants
+ and debug generation to accommodate the possibility of the user
+ setting an alternate data buffer.
+
+ * lib/jit_hppa-fpu.c, lib/jit_s390x.c, lib/jit_s390x-cpu.c,
+ lib/jit_s390x-fpu.c, lib/jit_sparc.c, lib/jit_sparc-fpu.c,
+ lib/jit_x86-sse.c, lib/jit_x86-x87.c: Implement jit_set_data.
+
+ * lib/jit_hppa-sz.c, lib/jit_sparc-sz.c, lib/jit_x86-sz.c,
+ lib/jit_s390x-sz.c: Update for several instructions that now
+ have a different maximum length due to jit_set_data.
+
+ * lib/jit_mips-fpu.c: Implement jit_set_data, but missing
+ validation on n32 and n64 abis (and/or big endian).
+
+ * lib/jit_mips-sz.c: Update for changes in o32.
+
+ * lib/jit_ppc-fpu.c: Implement jit_set_data, but missing
+ validation on Darwin PPC.
+
+ * lib/jit_ppc-sz.c: Update for changes in powerpc 32 and
+ 64 bit.
+
+ * lib/jit_ia64-fpu.c: Implement untested jit_set_data.
+
+ * TODO: Add note to list ports that were not tested for the
+ new jit_set_data() feature, due to no longer having access
+ to them.
+
+ * check/nodata.c: New file implementing a simple test exercising
+ several different conditions created by jit_set_data().
+
+ * check/check.nodata.sh: New file implementing a wrapper
+ over the existing *.tst files, that runs all tests without
+ using a data buffer for constants; only meaningful (and
+ enabled) on architectures that used to store float/double
+ constants on a read only data buffer.
+
+ * configure.ac, check/Makefile.am: Update for the new test
+ cases.
+
+ * check/lightning.c: Implement the new "-d" option that
+ sets an internal flag to call jit_set_data() disable
+ constants and debug, that is, using only a pure code
+ buffer.
+
+2014-11-03 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ lib/lightning.c: Implement the new jit_set_code() interface,
+ that allows instructing lightning to use an alternate code
+ buffer. The new jit_realize() function should be called
+ before jit_set_code(), and usually call jit_get_code()
+ to query the amount of bytes expected to be required for
+ the code.
+
+ * lib/jit_size.c: Minor update to have less chances of
+ miscalculating the code buffer by starting the counter
+ with the size of the longest instruction instead of zero,
+ as code emit fails if at any moment less than the longest
+ instruction bytes are available.
+
+ * check/setcode.c: New file implementing some basic tests
+ of the new jit_set_code() interface.
+
+ * check/Makefile.am: Update for newer test case.
+
+2014-06-03 Paulo Andrade
+
+ * include/lightning.h, lib/lightning.c: Add the new
+ jit_indirect() call, that returns a special label node,
+ and tells lightning that the label may be the target of
+ an indirect jump.
+
+ * doc/body.texi: Document the new jit_indirect() call, and
+ add examples of different ways to create labels and branches.
+
+2014-23-02 Paulo Andrade
+
+ * lib/jit_x86.c: Rewrite previous patch to inline save/restore
+ because clobbering %ebx in x86 is treated as an error
+ (jit_x86.c:239:5: error: PIC register clobbered by 'ebx' in 'asm').
+
+2014-19-02 Paulo Andrade
+
+ * lib/jit_x86.c: Rewrite incorrect inline assembly that could
+ truncate a variable in a callee save register. Now it simply
+ tells gcc that the register is clobbered, instead of using a
+ *32 bit* swap with a temporary variable. The problem only
+ happens when compiling with optimization.
+
+2014-19-02 Paulo Andrade
+
+ * include/lightning/jit_aarch64.h, include/lightning/jit_arm.h,
+ include/lightning/jit_hppa.h, include/lightning/jit_ia64.h,
+ include/lightning/jit_mips.h, include/lightning/jit_ppc.h,
+ include/lightning/jit_s390x.h, include/lightning/jit_sparc.h,
+ include/lightning/jit_x86.h: Change jit_regset_t to an
+ unsigned type, to allow safe right shift.
+
+ * lib/lightning.c: Rewrite jit_regset_scan1 to allow easier
+ compiler optimization.
+
+2013-12-03 Paulo Andrade
+
+ * lib/jit_x86-x87.c: Correct wrong optimization when
+ loading the log(2) constant.
+
+2013-12-03 Paulo Andrade
+
+ * lib/jit_x86-cpu.c: Use the emms instruction before
+ calling any function. This is particularly important
+ when using c99 complex functions as it can easily
+ overflow the x87 stack due to the way lightning uses
+ the x87 stack as a flat register file.
+
+2013-12-02 Paulo Andrade
+
+ * lib/jit_x86-x87.c: Correct wrong code generation due
+ to comparing the base and not the value register with
+ %st(0) in stxi_f.
+
+2013-12-02 Paulo Andrade
+
+ * lib/jit_x86-x87.c, lib/jit_x86.c: Use 8 bytes aligned
+ stack offset for float/double x87 to/from sse move.
+
+2013-11-27 Paulo Andrade
+
+ * configure.ac, lib/jit_arm-swf.c, lib/jit_arm.c: Add
+ changes that should at least allow building lightning
+ on Apple iOS7.
+
+2013-10-08 Paulo Andrade
+
+ * lib/jit_ppc-cpu.c: Correct wrong shortcut for ldxi_l with
+ a zero offset, that was calling ldr_i instead of ldr_l.
+
+2013-10-08 Paulo Andrade
+
+ * include/lightning/jit_arm.h, lib/jit_arm-cpu.c: Do not use
+ by default load/store instructions that map to ldrt/strt.
+ There is already the long displacement version for positive
+ offsets, and when using a (shorter) negative offset it does
+ not map to ldrt/strt. At least on qemu strt may cause
+ reproducible, but unexpected SIGILL.
+
+2013-10-08 Paulo Andrade
+
+ * lib/jit_arm-vfp.c: Correct wrong load/store offset
+ calculation when the displacement is constant but too
+ large to use an instruction with an immediate offset.
+
+2013-10-07 Paulo Andrade
+
+ * check/self.c: Extend tests to validate jit_callee_save_p
+ does not cause an assertion on valid arguments, and test
+ extra registers defined on some backends.
+
+ * configure.ac: Do not ignore environment CFLAGS when
+ checking if need to test runtime configurable options,
+ like use x87 when sse2 is available, arm instruction set
+ instead of thumb, etc.
+
+ * include/lightning/jit_arm.h: Correct wrong jit_f macro
+ definition.
+
+ * include/lightning/jit_ia64.h, include/lightning/jit_ppc.h:
+ Correct wrong jit_r macro definition.
+
+ * lib/jit_x86-x87.c, lib/jit_x86.c: Actually use the
+ reserved stack space for integer to/from float conversion.
+ The stack space was also changed to ensure it is 8 bytes
+ aligned. Also, for Solaris x86 in 32 bit mode, an alternate
+ truncr_d was implemented because for some reason it is
+ failing with SIGILL if using the "fisttpl" instructions,
+ that must be available on p6 or newer, but for the sake of
+ making all tests pass, implement a 486 or newer sequence
+ if "sun" is defined.
+
+2013-10-03 Paulo Andrade
+
+ * include/lightning/jit_mips.h, lib/jit_mips-cpu.c,
+ lib/jit_mips-sz.c, lib/jit_mips.c, size: Build and
+ pass all test cases on Irix big endian mips using
+ the 64 bit abi.
+
+2013-10-02 Paulo Andrade
+
+ * include/lightning/jit_mips.h: Add proper mips abi detection.
+
+2013-09-30 Paulo Andrade
+
+ * lib/jit_print.c: Do not crash if calling jit_print from
+ gdb before actually emitting code.
+
+ * lib/lightning.c: Correct misplaced check for already
+ visited blocks on conditional branches, what was preventing
+ proper merge live bit masks of forward blocks.
+
+2013-09-30 Paulo Andrade
+
+ * lib/jit_x86-cpu.c: Correct not properly tested case of using
+ %r12 as index register, what was causing an invalid assertion.
+ %r12 is mapped to the "extra" JIT_R3 register, and test cases
+ only test "standard" lightning registers.
+
+2013-09-28 Paulo Andrade
+
+ * lib/jit_ia64.c: Minor change to force collecting the maximum
+ instruction length in the --enable-devel-get-jit-size build
+ mode. The actual generated file did not change because the
+ sampling was large enough that it had already collected proper
+ information in the previously slightly buggy code (not forcing
+ a sync of the instructions that could be combined).
+
+2013-09-27 Paulo Andrade
+
+ * lib/jit_arm.c: Correct build when disassembler is
+ disabled.
+
+2013-09-25 Paulo Andrade
+
+ * lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c: Correct some
+ off by one range checks (that were only accepting values
+ one less than the maximum allowed) and an invalid test
+ condition check that was forcing it to always use
+ indirect jumps even when reachable with an immediate
+ displacement.
+
+2013-09-24 Paulo Andrade
+
+ * lib/jit_aarch64-sz.c, lib/jit_arm-sz.c, lib/jit_hppa-sz.c,
+ lib/jit_ia64-sz.c, lib/jit_mips-sz.c, lib/jit_ppc-sz.c,
+ lib/jit_s390x-sz.c, lib/jit_size.c, lib/jit_sparc-sz.c,
+ lib/jit_x86-sz.c: New files implementing static tables
+ with longest known instructions length generated to match
+ a lightning instruction. These tables should make it easier
+ to make it very unlikely to ever miscalculate, or by too
+ much, the size of a code buffer.
+
+ * lib/jit_size.c: New file that aids to either collect
+ jit code size information, or use the information depending
+ on build options.
+
+ * size.c: New helper file that parses input for, and create
+ an initial jit_$arch-sz.c file, that needs some minor edit
+ for arches with multiple configurations.
+
+ * configure.ac, Makefile.am: Add the new, devel mode only
+ --enable-devel-get-jit-size configure option, that sets
+ compile time flags to collect jit code size information,
+ that will be used as input for the "noinst size program".
+
+ * lib/jit_aarch64.c, lib/jit_arm.c, lib/jit_disasm.c,
+ lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_memory.c,
+ lib/jit_mips.c, lib/jit_ppc.c, lib/jit_s390x.c,
+ lib/jit_sparc.c, lib/jit_x86.c, lib/lightning.c: Minor
+ changes for the --enable-devel-get-jit-size build mode,
+ as well as the "production build mode" with jit code
+ size information.
+
+2013-09-14 Paulo Andrade
+
+ * include/lightning.h, lib/lightning.c: Add the new
+ jit_pointer_p interface, that returns a boolean value
+ telling if the pointer argument is inside the jit
+ code buffer. This is useful to avoid the need to add
+ extra labels and calls to jit_address to figure bounds
+ of code buffer, and still keep internal data private.
+
+2013-09-13 Paulo Andrade
+
+ * include/lightning.h, include/lightning/jit_private.h,
+ lib/jit_note.c: Change the code argument of jit_get_note
+ to a jit_pointer_t and make jit_get_note a public interface.
+ It was intended so since start, as a way to map an offset
+ in the code to a function name, file name and line number
+ mapping.
+
+2013-09-11 Paulo Andrade
+
+ * doc/body.texi: Correct reversed arguments in example of
+ usage in a (possibly) multi threaded, multiple jit_state_t
+ environments.
+
+ * include/lightning/jit_arm.h, include/lightning/jit_private.h,
+ lib/jit_arm-cpu.c, lib/jit_arm.c: Make a previously, non
+ documented, global state private to the related jit_state_t
+ generating code.
+
+2013-09-10 Paulo Andrade
+
+ * check/self.c, check/self.ok: New files implementing simple
+ consistency check assertions. At first validating some macros
+ that use values from different sources agree.
+
+ * check/Makefile.am: Update for the new test case.
+
+ * include/lightning.h, lib/lightning.c: Add the new
+ jit_callee_save_p() call, that is intended to be used when
+ writing complex code using lightning, so that one does not
+ need to verify what backend is being used, or have access to
+ private data, to query if a register is callee save or not;
+ on several backends the scratch registers are actually callee
+ save.
+
+ * include/lightning/jit_aarch64.h, include/lightning/jit_arm.h,
+ include/lightning/jit_hppa.h, include/lightning/jit_mips.h,
+ include/lightning/jit_ppc.h, include/lightning/jit_sparc.h,
+ include/lightning/jit_x86.h: Add an explicit definition for
+ JIT_R3-JIT_Rn, JIT_V3-JIT_Vn and JIT_F6-JIT_Fn when applicable.
+ This allows one to write code based on "#if defined(JIT_XN)"
+ and therefore, not need to check what is the current backend
+ or have access to private data structures. This is particularly
+ useful when writing virtual machines with several specialized,
+ global registers.
+
+ * lib/jit_ia64.c: Properly flag the callee save general
+ purpose registers as such, so that jit_callee_save_p() works
+ as intended.
+
+2013-09-10 Paulo Andrade
+
+ * check/lightning.c, configure.ac: Conditionally use the
+ code written to workaround a bug in the Hercules emulator,
+ as isnan and isinf are not available at least on HP-UX ia64.
+
+2013-09-10 Paulo Andrade
+
+ * lib/jit_s390x-cpu.c: Spill/reload correct callee save
+ float registers.
+
+2013-09-10 Paulo Andrade
+
+ * lib/jit_hppa-cpu.c: Correct code to call a function stored
+ in a register or a patched function address.
+
+2013-09-10 Paulo Andrade
+
+ * lib/jit_ia64-cpu.c: Correct incorrect logic when restoring
+ the value of the "r2" callee save register.
+
+2013-08-29 Paulo Andrade
+
+ * lib/jit_arm-cpu.c, lib/jit_arm.c: Correct wrong test and update
+ of the thumb offset information, when checking if needing to
+ patch a jump from arm to thumb mode. The problem would happen when
+ remapping the code buffer, and the new address being lower than
+ the previous one.
+
+2013-08-26 Paulo Andrade
+
+ * configure.ac: Extend FreeBSD test to also handle NetBSD.
+
+ * lib/jit_x86-cpu.c: Correct wrongly defined offset type of
+ ldxi_ui. Problem detected when building on NetBSD.
+
+ * lib/lightning.c: Adjust code to handle NetBSD mremap,
+ where arguments do not match Linux mremap.
+
+2013-08-26 Paulo Andrade
+
+ * lib/jit_ppc.c: Correct C sequence point problem miscalculating
+ the actual function address in a function descriptor. Problem
+ happens with gcc 4.8.1 at least.
+
+2013-08-11 Paulo Andrade
+
+ * lib/jit_s390x-cpu.c: Correct code checking if immediate
+ fits instruction, but using the negated value.
+
+2013-07-28 Paulo Andrade
+
+ * include/lightning/jit_s390x.h, lib/jit_s390x-cpu.c,
+ lib/jit_s390x-fpu.c, lib/jit_s390x.c: New files
+ implementing the new s390x port.
+
+ * configure.ac, include/lightning.h,
+ include/lightning/Makefile.am,
+ include/lightning/jit_private.h,
+ lib/Makefile.am, lib/jit_disasm.c, lib/lightning.c:
+ Minor adaptation for the new s390x backend.
+
+ * check/float.tst: Update for the s390x result of
+ truncating +Inf to integer.
+
+ * check/qalu_mul.tst: Add extra test cases to better test
+ high word of signed multiplication as the result is
+ adjust from unsigned multiplication on s390x.
+
+2013-07-28 Paulo Andrade
+
+ * check/lightning.c: Do not assume casting a double NaN or
+ Inf to float will produce the expected float NaN or Inf.
+ This is not true at least under s390x.
+
+2013-07-28 Paulo Andrade
+
+ * check/check.arm.sh, check/check.sh, check/check.swf.sh,
+ check/check.x87.sh: Properly check test programs output,
+ not just rely on the test program self testing the results
+ and not crashing.
+
+2013-07-28 Paulo Andrade
+
+ * lib/jit_aarch64.c: Remove unused macros left from cut&paste
+ of jit_arm.c.
+
+2013-07-16 Paulo Andrade
+
+ * include/lightning/jit_aarch64.h, lib/jit_aarch64-cpu.c,
+ lib/jit_aarch64-fpu.c, lib/jit_aarch64.c: New files
+ implementing the new aarch64 port, as a new architecture,
+ not as an expansion of the existing armv[4-7] port.
+
+ * check/lightning.c: Add aarch64 support and a small
+ change to recognize character constants as immediate
+ values.
+
+ * check/float.tst: Add aarch64 preprocessor conditionals
+ to select proper expected value when converting [+-]Inf
+ and NaN to integer.
+
+ * include/lightning/jit_arm.h, lib/jit_arm.c: Minor changes
+ to better match the new aarch64 files.
+
+ * configure.ac, include/lightning.h,
+ include/lightning/Makefile.am, include/lightning/jit_private.h,
+ lib/Makefile.am, lib/lightning.c: Minor adjustments
+ for the aarch64 port.
+
+2013-07-08 Paulo Andrade
+
+ * NEWS, THANKS, configure.ac, doc/version.texi: Update for
+ the 1.99a second alpha release.
+
+2013-06-25 Paulo Andrade
+
+ * lib/jit_mips.c: Correct cut&paste error that caused wrong
+ stack offset calculation for double arguments in stack in
+ the o32 abi.
+ Correct typo in the __LITTLE_ENDIAN macro name, that came
+ from cut&paste error in the original typo in lib/jit_ppc.c.
+
+ * lib/jit_ia64.c, lib/jit_ppc.c: Correct typo in the
+ __LITTLE_ENDIAN macro name.
+
+2013-06-22 Paulo Andrade
+
+ * check/lightning.c, configure.ac, include/lightning.h,
+ lib/lightning.c: Add tests and quirks to build/detect
+ and/or work on Irix.
+
+ * include/lightning/jit_mips.h, lib/jit_mips-cpu.c,
+ lib/jit_mips-fpu.c, lib/jit_mips.c: Adapt code to run
+ in big endian mips, using the n32 abi.
+
+2013-06-18 Paulo Andrade
+
+ * include/lightning.h: Minor extra preprocessor testing
+ to "detect" byte order on x86 solaris, that now builds
+ and pass all test cases.
+
+2013-06-18 Paulo Andrade
+
+ * lib/jit_sparc-cpu.c: Correct compiler warning of value
+ used before assignment. The usage is bogus as the api
+ requires always patching jumps, but the random value used
+ could cause an assertion due to invalid displacement.
+
+ * lib/jit_sparc.c: Always load and store double arguments
+ in stack as 2 float loads or stores, for safety, as unaligned
+ access is not allowed in Sparc Solaris.
+
+2013-06-14 Paulo Andrade
+
+ * configure.ac: Force -mlp64 to CFLAGS on HP-UX ia64 port.
+ It is the only supported mode, and expects gcc as C compiler.
+
+ * include/lightning.h, lib/jit_ia64-cpu.c, lib/jit_ia64.c:
+ Correct ia64 port to work on HP-UX that runs it in big endian
+ mode.
+
+2013-06-10 Paulo Andrade
+
+ * lib/jit_hppa.c: Sanitize the cache synchronization inline
+ assembly code that was doing twice the work and redundantly
+ flushing the end address every loop iteration.
+
+2013-06-09 Paulo Andrade
+
+ * configure.ac, check/Makefile.am, doc/Makefile.am: Do not
+ explicitly link to -ldl, but instead autodetect the library
+ with dlopen, dlsym, etc.
+
+ * check/lightning.c: Add workaround to apparently buggy
+ getopt in HP-UX that sets optind to the wrong index, and
+ use RTLD_NEXT on HP-UX instead of RTLD_DEFAULT to dlsym
+ global symbols.
+
+ * include/lightning.h: Rework definitions of wordsize and
+ byte order to detect proper values on HP-UX.
+
+ * lib/lightning.c: Minor correction to use MAP_ANONYMOUS
+ instead of MAP_ANON on HP-UX.
+
+ * lib/jit_hppa.c: Float arguments must be passed on integer
+ registers on HP-UX, not only for varargs functions.
+ Add code to properly clear instruction cache. This was
+ not required on Debian hppa port, but may have been working
+ by accident.
+
+ * lib/jit_hppa-cpu.c: Follow pattern of HP-UX binaries and
+ use bve,n instead of bv,n to return from functions.
+
+ * lib/jit_hppa-fpu.c: For some reason "fst? frX,rX,(rY)" did
+ not work on the tested computer (HP-UX B.11.23 U 9000/785 HP-UX)
+ so the code was changed, at first for __hpux only to add the
+ base and offset register and use the instruction with an
+ immediate (zero) offset.
+
+2013-06-07 Paulo Andrade