diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 11a6098ed7..1c14850a07 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -251,6 +251,7 @@ set(STANDARD_PACKAGES KSPACE LATBOLTZ LATTE + LEPTON MACHDYN MANIFOLD MANYBODY @@ -513,7 +514,7 @@ else() endif() foreach(PKG_WITH_INCL KSPACE PYTHON ML-IAP VORONOI COLVARS ML-HDNNP MDI MOLFILE NETCDF - PLUMED QMMM ML-QUIP SCAFACOS MACHDYN VTK KIM LATTE MSCG COMPRESS ML-PACE) + PLUMED QMMM ML-QUIP SCAFACOS MACHDYN VTK KIM LATTE MSCG COMPRESS ML-PACE LEPTON) if(PKG_${PKG_WITH_INCL}) include(Packages/${PKG_WITH_INCL}) endif() diff --git a/cmake/Modules/Packages/COLVARS.cmake b/cmake/Modules/Packages/COLVARS.cmake index da5b685536..3ca48b81fc 100644 --- a/cmake/Modules/Packages/COLVARS.cmake +++ b/cmake/Modules/Packages/COLVARS.cmake @@ -2,19 +2,14 @@ set(COLVARS_SOURCE_DIR ${LAMMPS_LIB_SOURCE_DIR}/colvars) file(GLOB COLVARS_SOURCES ${COLVARS_SOURCE_DIR}/[^.]*.cpp) -option(COLVARS_DEBUG "Debugging messages for Colvars (quite verbose)" OFF) +option(COLVARS_DEBUG "Enable debugging messages for Colvars (quite verbose)" OFF) -# Build Lepton by default -option(COLVARS_LEPTON "Build and link the Lepton library" ON) +option(COLVARS_LEPTON "Use the Lepton library for custom expressions" ON) if(COLVARS_LEPTON) - set(LEPTON_DIR ${LAMMPS_LIB_SOURCE_DIR}/colvars/lepton) - file(GLOB LEPTON_SOURCES ${LEPTON_DIR}/src/[^.]*.cpp) - add_library(lepton STATIC ${LEPTON_SOURCES}) - # Change the define below to LEPTON_BUILDING_SHARED_LIBRARY when linking Lepton as a DLL with MSVC - target_compile_definitions(lepton PRIVATE -DLEPTON_BUILDING_STATIC_LIBRARY) - set_target_properties(lepton PROPERTIES OUTPUT_NAME lammps_lepton${LAMMPS_MACHINE}) - target_include_directories(lepton PRIVATE ${LEPTON_DIR}/include) + if(NOT LEPTON_SOURCE_DIR) + include(Packages/LEPTON) + endif() endif() add_library(colvars STATIC ${COLVARS_SOURCES}) @@ -30,14 +25,11 @@ target_include_directories(colvars PRIVATE ${LAMMPS_SOURCE_DIR}) target_link_libraries(lammps PRIVATE colvars) if(COLVARS_DEBUG) - # Need to export the macro publicly to also affect the proxy + # Need to export the macro publicly to be valid in interface code target_compile_definitions(colvars PUBLIC -DCOLVARS_DEBUG) endif() if(COLVARS_LEPTON) - target_link_libraries(lammps PRIVATE lepton) target_compile_definitions(colvars PRIVATE -DLEPTON) - # Disable the line below when linking Lepton as a DLL with MSVC - target_compile_definitions(colvars PRIVATE -DLEPTON_USE_STATIC_LIBRARIES) - target_include_directories(colvars PUBLIC ${LEPTON_DIR}/include) + target_link_libraries(colvars PRIVATE lepton) endif() diff --git a/cmake/Modules/Packages/LEPTON.cmake b/cmake/Modules/Packages/LEPTON.cmake new file mode 100644 index 0000000000..df8a201c6b --- /dev/null +++ b/cmake/Modules/Packages/LEPTON.cmake @@ -0,0 +1,35 @@ +# avoid including this file twice +if(LEPTON_SOURCE_DIR) + return() +endif() +set(LEPTON_SOURCE_DIR ${LAMMPS_LIB_SOURCE_DIR}/lepton) + +file(GLOB LEPTON_SOURCES ${LEPTON_SOURCE_DIR}/src/[^.]*.cpp) + +if((CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "amd64") OR + (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") OR + (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")) + option(LEPTON_ENABLE_JIT "Enable Just-In-Time compiler for Lepton" ON) +else() + option(LEPTON_ENABLE_JIT "Enable Just-In-Time compiler for Lepton" OFF) +endif() + +if(LEPTON_ENABLE_JIT) + file(GLOB ASMJIT_SOURCES ${LEPTON_SOURCE_DIR}/asmjit/*/[^.]*.cpp) +endif() + +add_library(lepton STATIC ${LEPTON_SOURCES} ${ASMJIT_SOURCES}) +set_target_properties(lepton PROPERTIES OUTPUT_NAME lammps_lepton${LAMMPS_MACHINE}) +target_compile_definitions(lepton PUBLIC LEPTON_BUILDING_STATIC_LIBRARY=1) +target_include_directories(lepton PUBLIC ${LEPTON_SOURCE_DIR}/include) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_library(LIB_RT rt QUIET) + target_link_libraries(lepton PUBLIC ${LIB_RT}) +endif() + +if(LEPTON_ENABLE_JIT) + target_compile_definitions(lepton PUBLIC "LEPTON_USE_JIT=1;ASMJIT_BUILD_X86=1;ASMJIT_STATIC=1;ASMJIT_BUILD_RELEASE=1") + target_include_directories(lepton PUBLIC ${LEPTON_SOURCE_DIR}) +endif() + +target_link_libraries(lammps PRIVATE lepton) diff --git a/cmake/presets/all_off.cmake b/cmake/presets/all_off.cmake index 9127305528..3d5ee95b3d 100644 --- a/cmake/presets/all_off.cmake +++ b/cmake/presets/all_off.cmake @@ -44,6 +44,7 @@ set(ALL_PACKAGES KSPACE LATBOLTZ LATTE + LEPTON MACHDYN MANIFOLD MANYBODY diff --git a/cmake/presets/all_on.cmake b/cmake/presets/all_on.cmake index 0a001bdc56..474051f6ec 100644 --- a/cmake/presets/all_on.cmake +++ b/cmake/presets/all_on.cmake @@ -46,6 +46,7 @@ set(ALL_PACKAGES KSPACE LATBOLTZ LATTE + LEPTON MACHDYN MANIFOLD MANYBODY diff --git a/cmake/presets/mingw-cross.cmake b/cmake/presets/mingw-cross.cmake index 2d74657394..6c6170acd3 100644 --- a/cmake/presets/mingw-cross.cmake +++ b/cmake/presets/mingw-cross.cmake @@ -36,6 +36,7 @@ set(WIN_PACKAGES INTERLAYER KSPACE LATTE + LEPTON MACHDYN MANIFOLD MANYBODY diff --git a/cmake/presets/most.cmake b/cmake/presets/most.cmake index 5dd9a2b78b..0d63140506 100644 --- a/cmake/presets/most.cmake +++ b/cmake/presets/most.cmake @@ -35,6 +35,7 @@ set(ALL_PACKAGES GRANULAR INTERLAYER KSPACE + LEPTON MACHDYN MANYBODY MC diff --git a/cmake/presets/nolib.cmake b/cmake/presets/nolib.cmake index b6567ad617..b022d4bb55 100644 --- a/cmake/presets/nolib.cmake +++ b/cmake/presets/nolib.cmake @@ -13,6 +13,7 @@ set(PACKAGES_WITH_LIB KOKKOS LATBOLTZ LATTE + LEPTON MACHDYN MDI MESONT diff --git a/cmake/presets/windows.cmake b/cmake/presets/windows.cmake index e93cd35daa..7075659964 100644 --- a/cmake/presets/windows.cmake +++ b/cmake/presets/windows.cmake @@ -31,6 +31,7 @@ set(WIN_PACKAGES GRANULAR INTERLAYER KSPACE + LEPTON MANIFOLD MANYBODY MC diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index d1161164e9..eab9355a83 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -35,7 +35,7 @@ This is the list of packages that may require additional steps. * :ref:`ADIOS ` * :ref:`ATC ` * :ref:`AWPMD ` - * :ref:`COLVARS ` + * :ref:`COLVARS ` * :ref:`COMPRESS ` * :ref:`ELECTRODE ` * :ref:`GPU ` @@ -44,6 +44,7 @@ This is the list of packages that may require additional steps. * :ref:`KIM ` * :ref:`KOKKOS ` * :ref:`LATTE ` + * :ref:`LEPTON ` * :ref:`MACHDYN ` * :ref:`MDI ` * :ref:`MESONT ` @@ -876,6 +877,55 @@ library. ---------- +.. _lepton: + +LEPTON package +-------------- + +To build with this package, you must build the Lepton library which is +included in the LAMMPS source distribution in the ``lib/lepton`` folder. + +.. tabs:: + + .. tab:: CMake build + + This is the recommended build procedure for using Lepton in + LAMMPS. No additional settings are normally needed besides + ``-D PKG_LEPTON=yes``. + + On x86 hardware the Lepton library will also include a just-in-time + compiler for faster execution. This is auto detected but can + be explicitly disabled by setting ``-D LEPTON_ENABLE_JIT=no`` + (or enabled by setting it to yes). + + .. tab:: Traditional make + + Before building LAMMPS, one must build the Lepton library in lib/lepton. + + This can be done manually in the same folder by using or adapting + one of the provided Makefiles: for example, ``Makefile.serial`` for + the GNU C++ compiler, or ``Makefile.mpi`` for the MPI compiler wrapper. + The Lepton library is written in C++-11 and thus the C++ compiler + may need to be instructed to enable support for that. + + In general, it is safer to use build setting consistent with the + rest of LAMMPS. This is best carried out from the LAMMPS src + directory using a command like these, which simply invokes the + ``lib/lepton/Install.py`` script with the specified args: + + .. code-block:: bash + + $ make lib-lepton # print help message + $ make lib-lepton args="-m serial" # build with GNU g++ compiler (settings as with "make serial") + $ make lib-lepton args="-m mpi" # build with default MPI compiler (settings as with "make mpi") + + The "machine" argument of the "-m" flag is used to find a + Makefile.machine to use as build recipe. + + The build should produce a ``build`` folder and the library ``lib/lepton/liblmplepton.a`` + +---------- + .. _mliap: ML-IAP package @@ -1221,7 +1271,7 @@ The ATC package requires the MANYBODY package also be installed. .. _awpmd: AWPMD package ------------------- +------------- .. tabs:: @@ -1269,14 +1319,13 @@ AWPMD package ---------- -.. _colvars: +.. _colvar: COLVARS package ---------------------------------------- +--------------- -This package includes the `Colvars library -`_ into the LAMMPS distribution, which can -be built for the most part with all major versions of the C++ language. +This package enables the use of the `Colvars `_ +module included in the LAMMPS source distribution. .. tabs:: @@ -1289,17 +1338,13 @@ be built for the most part with all major versions of the C++ language. .. tab:: Traditional make - Before building LAMMPS, one must build the Colvars library in lib/colvars. + As with other libraries distributed with LAMMPS, the Colvars library + needs to be built before building the LAMMPS program with the COLVARS + package enabled. - This can be done manually in the same folder by using or adapting - one of the provided Makefiles: for example, ``Makefile.g++`` for - the GNU C++ compiler. C++11 compatibility may need to be enabled - for some older compilers (as is done in the example makefile). - - In general, it is safer to use build setting consistent with the - rest of LAMMPS. This is best carried out from the LAMMPS src - directory using a command like these, which simply invokes the - ``lib/colvars/Install.py`` script with the specified args: + From the LAMMPS ``src`` directory, this is most easily and safely done + via one of the following commands, which implicitly rely on the + ``lib/colvars/Install.py`` script with optional arguments: .. code-block:: bash @@ -1309,10 +1354,17 @@ be built for the most part with all major versions of the C++ language. make lib-colvars args="-m g++-debug" # build with GNU g++ compiler and colvars debugging enabled The "machine" argument of the "-m" flag is used to find a - Makefile.machine to use as build recipe. If it does not already - exist in ``lib/colvars``, it will be auto-generated by using - compiler flags consistent with those parsed from the core LAMMPS - makefiles. + ``Makefile.machine`` file to use as build recipe. If such recipe does + not already exist in ``lib/colvars``, suitable settings will be + auto-generated consistent with those used in the core LAMMPS makefiles. + + + .. versionchanged:: TBD + + Please note that Colvars uses the Lepton library, which is now + included with the LEPTON package; if you use anything other than + the ``make lib-colvars`` command, please make sure to :ref:`build + Lepton beforehand `. Optional flags may be specified as environment variables: @@ -1321,10 +1373,10 @@ be built for the most part with all major versions of the C++ language. COLVARS_DEBUG=yes make lib-colvars args="-m machine" # Build with debug code (much slower) COLVARS_LEPTON=no make lib-colvars args="-m machine" # Build without Lepton (included otherwise) - The build should produce two files: the library ``lib/colvars/libcolvars.a`` - (which also includes Lepton objects if enabled) and the specification file - ``lib/colvars/Makefile.lammps``. The latter is auto-generated, and normally does - not need to be edited. + The build should produce two files: the library + ``lib/colvars/libcolvars.a`` and the specification file + ``lib/colvars/Makefile.lammps``. The latter is auto-generated, + and normally does not need to be edited. ---------- diff --git a/doc/src/Build_package.rst b/doc/src/Build_package.rst index 4ee779742e..938ffec306 100644 --- a/doc/src/Build_package.rst +++ b/doc/src/Build_package.rst @@ -37,7 +37,7 @@ packages: * :ref:`ADIOS ` * :ref:`ATC ` * :ref:`AWPMD ` - * :ref:`COLVARS ` + * :ref:`COLVARS ` * :ref:`COMPRESS ` * :ref:`ELECTRODE ` * :ref:`GPU ` @@ -46,6 +46,7 @@ packages: * :ref:`KIM ` * :ref:`KOKKOS ` * :ref:`LATTE ` + * :ref:`LEPTON ` * :ref:`MACHDYN ` * :ref:`MDI ` * :ref:`MESONT ` diff --git a/doc/src/Commands_bond.rst b/doc/src/Commands_bond.rst index ac2d5882fb..cfc896aa0e 100644 --- a/doc/src/Commands_bond.rst +++ b/doc/src/Commands_bond.rst @@ -44,6 +44,7 @@ OPT. * :doc:`harmonic (iko) ` * :doc:`harmonic/shift (o) ` * :doc:`harmonic/shift/cut (o) ` + * :doc:`lepton (o) ` * :doc:`mesocnt ` * :doc:`mm3 ` * :doc:`morse (o) ` @@ -93,6 +94,7 @@ OPT. * :doc:`fourier/simple (o) ` * :doc:`gaussian ` * :doc:`harmonic (iko) ` + * :doc:`lepton (o) ` * :doc:`mesocnt ` * :doc:`mm3 ` * :doc:`quartic (o) ` @@ -127,6 +129,7 @@ OPT. * :doc:`fourier (io) ` * :doc:`harmonic (iko) ` * :doc:`helix (o) ` + * :doc:`lepton (o) ` * :doc:`multi/harmonic (o) ` * :doc:`nharmonic (o) ` * :doc:`opls (iko) ` diff --git a/doc/src/Commands_pair.rst b/doc/src/Commands_pair.rst index 2fc90652c5..59501b4a56 100644 --- a/doc/src/Commands_pair.rst +++ b/doc/src/Commands_pair.rst @@ -134,6 +134,8 @@ OPT. * :doc:`lcbop ` * :doc:`lebedeva/z ` * :doc:`lennard/mdf ` + * :doc:`lepton (o) ` + * :doc:`lepton/coul (o) ` * :doc:`line/lj ` * :doc:`lj/charmm/coul/charmm (giko) ` * :doc:`lj/charmm/coul/charmm/implicit (ko) ` diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index 969765e3be..79d5d872aa 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -68,6 +68,7 @@ page gives those details. * :ref:`KSPACE ` * :ref:`LATBOLTZ ` * :ref:`LATTE ` + * :ref:`LEPTON ` * :ref:`MACHDYN ` * :ref:`MANIFOLD ` * :ref:`MANYBODY ` @@ -492,22 +493,21 @@ COLVARS package **Contents:** -COLVARS stands for collective variables, which can be used to -implement various enhanced sampling methods, including Adaptive -Biasing Force, Metadynamics, Steered MD, Umbrella Sampling and -Restraints. A :doc:`fix colvars ` command is implemented -which wraps a COLVARS library, which implements these methods. -simulations. +Colvars stands for collective variables, which can be used to implement +various enhanced sampling methods, including Adaptive Biasing Force, +Metadynamics, Steered MD, Umbrella Sampling and Restraints. A :doc:`fix +colvars ` command is implemented which wraps a COLVARS +library, which implements these methods. simulations. -**Authors:** The COLVARS library is written and maintained by -Giacomo Fiorin (ICMS, Temple University, Philadelphia, PA, USA) -and Jerome Henin (LISM, CNRS, Marseille, France), originally for -the NAMD MD code, but with portability in mind. Axel Kohlmeyer -(Temple U) provided the interface to LAMMPS. +**Authors:** The COLVARS library is written and maintained by Giacomo +Fiorin (NIH, Bethesda, MD, USA) and Jerome Henin (CNRS, Paris, France), +originally for the NAMD MD code, but with portability in mind. Axel +Kohlmeyer (Temple U) provided the interface to LAMMPS. **Install:** -This package has :ref:`specific installation instructions ` on the :doc:`Build extras ` page. +This package has :ref:`specific installation instructions ` on +the :doc:`Build extras ` page. **Supporting info:** @@ -516,6 +516,8 @@ This package has :ref:`specific installation instructions ` on the :doc * src/COLVARS/README * lib/colvars/README * :doc:`fix colvars ` +* :doc:`group2ndx ` +* :doc:`ndx2group ` * examples/PACKAGES/colvars ---------- @@ -1388,6 +1390,46 @@ the :doc:`Build extras ` page. ---------- +.. _PKG-LEPTON: + +LEPTON package +-------------- + +**Contents:** + +Styles for pair, bond, and angle forces that evaluate the potential +function from a string using the `Lepton mathematical expression parser +`_. Lepton is a C++ library that is +bundled with `OpenMM `_ and can be used for +parsing, evaluating, differentiating, and analyzing mathematical +expressions. This is a more lightweight and efficient alternative for +evaluating custom potential function to an embedded Python interpreter +as used in the :ref:`PYTHON package `. On the other hand, +since the potentials are evaluated form analytical expressions, they are +more precise than what can be done with :ref:`tabulated potentials +`. + +**Authors:** Axel Kohlmeyer (Temple U). Lepton itself is developed +by Peter Eastman at Stanford University. + +.. versionadded:: TBD + +**Install:** + +This package has :ref:`specific installation instructions ` on +the :doc:`Build extras ` page. + +**Supporting info:** + +* src/LEPTON: filenames -> commands +* lib/lepton/README.md +* :doc:`pair_style lepton ` +* :doc:`bond_style lepton ` +* :doc:`angle_style lepton ` +* :doc:`dihedral_style lepton ` + +---------- + .. _PKG-MACHDYN: MACHDYN package diff --git a/doc/src/Packages_list.rst b/doc/src/Packages_list.rst index fa887e7977..9e5727bb0e 100644 --- a/doc/src/Packages_list.rst +++ b/doc/src/Packages_list.rst @@ -238,6 +238,11 @@ whether an extra library is needed to build and use the package: - :doc:`fix latte ` - latte - ext + * - :ref:`LEPTON ` + - evaluate strings as potential function + - :doc:`pair_style lepton ` + - PACKAGES/lepton + - int * - :ref:`MACHDYN ` - smoothed Mach dynamics - `SMD User Guide `_ diff --git a/doc/src/angle_lepton.rst b/doc/src/angle_lepton.rst new file mode 100644 index 0000000000..ea948c6a5f --- /dev/null +++ b/doc/src/angle_lepton.rst @@ -0,0 +1,94 @@ +.. index:: angle_style lepton +.. index:: angle_style lepton/omp + +angle_style lepton command +========================== + +Accelerator Variants: *lepton/omp* + +Syntax +"""""" + +.. code-block:: LAMMPS + + angle_style lepton + +Examples +"""""""" + +.. code-block:: LAMMPS + + angle_style lepton + + angle_coeff 1 120.0 "k*theta^2; k=250.0" + angle_coeff 2 90.0 "k2*theta^2 + k3*theta^3 + k4*theta^4; k2=300.0; k3=-100.0; k4=50.0" + angle_coeff 3 109.47 "k*theta^2; k=350.0" + +Description +""""""""""" + +.. versionadded:: TBD + +Angle style *lepton* computes angular interactions between three atoms +with a custom potential function. The potential function must be +provided as an expression string using "theta" as the angle variable +relative to the reference angle :math:`\theta_0` which is provided as an +angle coefficient. For example `"200.0*theta^2"` represents a +:doc:`harmonic angle ` potential with a force constant +*K* of 200.0 energy units: + +.. math:: + + U_{angle,i} = K (\theta_i - \theta_0)^2 = K \theta^2 \qquad \theta = \theta_i - \theta_0 + +The `Lepton library `_, that the +*lepton* angle style interfaces with, evaluates this expression string +at run time to compute the pairwise energy. It also creates an +analytical representation of the first derivative of this expression +with respect to "theta" and then uses that to compute the force between +the angle atoms as defined by the topology data. + +The following coefficients must be defined for each angle type via the +:doc:`angle_coeff ` command as in the example above, or in +the data file or restart files read by the :doc:`read_data ` +or :doc:`read_restart ` commands: + +* Lepton expression (energy units) +* :math:`\theta_0` (degrees) + +The Lepton expression must be either enclosed in quotes or must not +contain any whitespace so that LAMMPS recognizes it as a single keyword. +More on valid Lepton expressions below. The :math:`\theta_0` +coefficient is the "equilibrium angle". It is entered in degrees, but +internally converted to radians. Thus the expression must assume +"theta" is in radians. The potential energy function in the Lepton +expression is shifted in such a way, that the potential energy is 0 for +a angle :math:`\theta_i == \theta_0`. + +---------- + +.. include:: lepton_expression.rst + +---------- + +.. include:: accel_styles.rst + +---------- + +Restrictions +"""""""""""" + +This angle style is part of the LEPTON package and only enabled if LAMMPS +was built with this package. See the :doc:`Build package +` page for more info. + +Related commands +"""""""""""""""" + +:doc:`angle_coeff `, :doc:`angle_style table `, +:doc:`bond_style lepton `,:doc:`dihedral_style lepton ` + +Default +""""""" + +none diff --git a/doc/src/angle_style.rst b/doc/src/angle_style.rst index 024481ce68..1f1ae72647 100644 --- a/doc/src/angle_style.rst +++ b/doc/src/angle_style.rst @@ -10,7 +10,7 @@ Syntax angle_style style -* style = *none* or *zero* or *hybrid* or *amoeba* or *charmm* or *class2* or *class2/p6* or *cosine* or *cosine/buck6d* or *cosine/delta* or *cosine/periodic* or *cosine/shift* or *cosine/shift/exp* or *cosine/squared* or *cross* or *dipole* or *fourier* or *fourier/simple* or *gaussian* or *harmonic* or *mm3* or *quartic* or *spica* or *table* +* style = *none* or *zero* or *hybrid* or *amoeba* or *charmm* or *class2* or *class2/p6* or *cosine* or *cosine/buck6d* or *cosine/delta* or *cosine/periodic* or *cosine/shift* or *cosine/shift/exp* or *cosine/squared* or *cross* or *dipole* or *fourier* or *fourier/simple* or *gaussian* or *harmonic* or *lepton* or *mm3* or *quartic* or *spica* or *table* Examples """""""" @@ -90,6 +90,7 @@ of (g,i,k,o,t) to indicate which accelerated styles exist. * :doc:`fourier/simple ` - angle with a single cosine term * :doc:`gaussian ` - multi-centered Gaussian-based angle potential * :doc:`harmonic ` - harmonic angle +* :doc:`lepton ` - angle potential from evaluating a string * :doc:`mesocnt ` - piecewise harmonic and linear angle for bending-buckling of nanotubes * :doc:`mm3 ` - anharmonic angle * :doc:`quartic ` - angle with cubic and quartic terms diff --git a/doc/src/bond_lepton.rst b/doc/src/bond_lepton.rst new file mode 100644 index 0000000000..91f040e183 --- /dev/null +++ b/doc/src/bond_lepton.rst @@ -0,0 +1,92 @@ +.. index:: bond_style lepton +.. index:: bond_style lepton/omp + +bond_style lepton command +========================= + +Accelerator Variants: *lepton/omp* + +Syntax +"""""" + +.. code-block:: LAMMPS + + bond_style lepton + +Examples +"""""""" + +.. code-block:: LAMMPS + + bond_style lepton + + bond_coeff 1 1.5 "k*r^2; k=250.0" + bond_coeff 2 1.1 "k2*r^2 + k3*r^3 + k4*r^4; k2=300.0; k3=-100.0; k4=50.0" + bond_coeff 3 1.3 "k*r^2; k=350.0" + +Description +""""""""""" + +.. versionadded:: TBD + +Bond style *lepton* computes bonded interactions between two atoms with +a custom function. The potential function must be provided as an +expression string using "r" as the distance variable relative to the +reference distance :math:`r_0` which is provided as a bond coefficient. +For example `"200.0*r^2"` represents a harmonic potential with a force +constant *K* of 200.0 energy units: + +.. math:: + + U_{bond,i} = K (r_i - r_0)^2 = K r^2 \qquad r = r_i - r_0 + +The `Lepton library `_, that the +*lepton* bond style interfaces with, evaluates this expression string at +run time to compute the pairwise energy. It also creates an analytical +representation of the first derivative of this expression with respect to +"r" and then uses that to compute the force between the atom pairs forming +bonds as defined by the topology data. + +The following coefficients must be defined for each bond type via the +:doc:`bond_coeff ` command as in the examples above, or in +the data file or restart files read by the :doc:`read_data ` +or :doc:`read_restart ` commands: + +* Lepton expression (energy units) +* :math:`r_0` (distance) + +The Lepton expression must be either enclosed in quotes or must not +contain any whitespace so that LAMMPS recognizes it as a single keyword. +More on valid Lepton expressions below. The :math:`r_0` is the +"equilibrium distance". The potential energy function in the Lepton +expression is shifted in such a way, that the potential energy is 0 for +a bond length :math:`r_i == r_0`. + +---------- + +.. include:: lepton_expression.rst + +---------- + +.. include:: accel_styles.rst + +---------- + +Restrictions +"""""""""""" + +This bond style is part of the LEPTON package and only enabled if LAMMPS +was built with this package. See the :doc:`Build package +` page for more info. + +Related commands +"""""""""""""""" + +:doc:`bond_coeff `, :doc:`bond_style table `, +:doc:`bond_write `, :doc:`angle_style lepton `, +:doc:`dihedral_style lepton ` + +Default +""""""" + +none diff --git a/doc/src/bond_style.rst b/doc/src/bond_style.rst index 9197e6c4eb..23b89d00a2 100644 --- a/doc/src/bond_style.rst +++ b/doc/src/bond_style.rst @@ -10,7 +10,7 @@ Syntax bond_style style args -* style = *none* or *zero* or *hybrid* or *bpm/rotational* or *bpm/spring* or *class2* or *fene* or *fene/expand* or *fene/nm* or *gaussian* or *gromos* or *harmonic* or *harmonic/shift* or *harmonic/shift/cut* or *morse* or *nonlinear* or *oxdna/fene* or *oxdena2/fene* or *oxrna2/fene* or *quartic* or *special* or *table* +* style = *none* or *zero* or *hybrid* or *bpm/rotational* or *bpm/spring* or *class2* or *fene* or *fene/expand* or *fene/nm* or *gaussian* or *gromos* or *harmonic* or *harmonic/shift* or *harmonic/shift/cut* or *lepton* or *morse* or *nonlinear* or *oxdna/fene* or *oxdena2/fene* or *oxrna2/fene* or *quartic* or *special* or *table* * args = none for any style except *hybrid* @@ -95,6 +95,7 @@ accelerated styles exist. * :doc:`harmonic ` - harmonic bond * :doc:`harmonic/shift ` - shifted harmonic bond * :doc:`harmonic/shift/cut ` - shifted harmonic bond with a cutoff +* :doc:`lepton ` - bond potential from evaluating a string * :doc:`mesocnt ` - Harmonic bond wrapper with parameterization presets for nanotubes * :doc:`mm3 ` - MM3 anharmonic bond * :doc:`morse ` - Morse bond diff --git a/doc/src/dihedral_lepton.rst b/doc/src/dihedral_lepton.rst new file mode 100644 index 0000000000..e030c3b7c4 --- /dev/null +++ b/doc/src/dihedral_lepton.rst @@ -0,0 +1,89 @@ +.. index:: dihedral_style lepton +.. index:: dihedral_style lepton/omp + +dihedral_style lepton command +============================= + +Accelerator Variants: *lepton/omp* + +Syntax +"""""" + +.. code-block:: LAMMPS + + dihedral_style lepton + +Examples +"""""""" + +.. code-block:: LAMMPS + + dihedral_style lepton + + dihedral_coeff 1 "k*(1 + d*cos(n*phi)); k=75.0; d=1; n=2" + dihedral_coeff 2 "45*(1-cos(4*phi))" + dihedral_coeff 2 "k2*cos(phi) + k3*cos(phi)^2; k2=100.0" + dihedral_coeff 3 "k*(phi-phi0)^2; k=85.0; phi0=120.0" + +Description +""""""""""" + +.. versionadded:: TBD + +Dihedral style *lepton* computes dihedral interactions between four +atoms forming a dihedral angle with a custom potential function. The +potential function must be provided as an expression string using "phi" +as the dihedral angle variable. For example `"200.0*(phi-120.0)^2"` +represents a :doc:`quadratic dihedral ` potential +around a 120 degree dihedral angle with a force constant *K* of 200.0 +energy units: + +.. math:: + + U_{dihedral,i} = K (\phi_i - \phi_0)^2 + +The `Lepton library `_, that the +*lepton* dihedral style interfaces with, evaluates this expression +string at run time to compute the pairwise energy. It also creates an +analytical representation of the first derivative of this expression +with respect to "phi" and then uses that to compute the force between +the dihedral atoms as defined by the topology data. + +The potential function expression for each dihedral type is provided via the +:doc:`dihedral_coeff ` command as in the example above, or in +the data file or restart files read by the :doc:`read_data ` +or :doc:`read_restart ` commands. The expression is in energy units. + +The Lepton expression must be either enclosed in quotes or must not +contain any whitespace so that LAMMPS recognizes it as a single keyword. +More on valid Lepton expressions below. Dihedral angles are internally +computed in radians and thus the expression must assume "phi" is in +radians. + +---------- + +.. include:: lepton_expression.rst + +---------- + +.. include:: accel_styles.rst + +---------- + +Restrictions +"""""""""""" + +This dihedral style is part of the LEPTON package and only enabled if LAMMPS +was built with this package. See the :doc:`Build package +` page for more info. + +Related commands +"""""""""""""""" + +:doc:`dihedral_coeff `, :doc:`dihedral_style table `, +:doc:`bond_style lepton `, :doc:`angle_style lepton ` + +Default +""""""" + +none diff --git a/doc/src/dihedral_style.rst b/doc/src/dihedral_style.rst index 4e56d1f787..45dd66e750 100644 --- a/doc/src/dihedral_style.rst +++ b/doc/src/dihedral_style.rst @@ -10,7 +10,7 @@ Syntax dihedral_style style -* style = *none* or *zero* or *hybrid* or *charmm* or *charmmfsw* or *class2* or *osine/shift/exp* or *fourier* or *harmonic* or *helix* or *multi/harmonic* or *nharmonic* or *opls* or *spherical* or *table* or *table/cut* +* style = *none* or *zero* or *hybrid* or *charmm* or *charmmfsw* or *class2* or *cosine/shift/exp* or *fourier* or *harmonic* or *helix* or *lepton* or *multi/harmonic* or *nharmonic* or *opls* or *spherical* or *table* or *table/cut* Examples """""""" @@ -108,6 +108,7 @@ exist. * :doc:`fourier ` - dihedral with multiple cosine terms * :doc:`harmonic ` - harmonic dihedral * :doc:`helix ` - helix dihedral +* :doc:`lepton ` - dihedral potential from evaluating a string * :doc:`multi/harmonic ` - dihedral with 5 harmonic terms * :doc:`nharmonic ` - same as multi-harmonic with N terms * :doc:`opls ` - OPLS dihedral diff --git a/doc/src/fix_colvars.rst b/doc/src/fix_colvars.rst index ec7b33ce51..77a90cc54f 100644 --- a/doc/src/fix_colvars.rst +++ b/doc/src/fix_colvars.rst @@ -37,57 +37,64 @@ Description This fix interfaces LAMMPS to the collective variables (Colvars) library, which allows to calculate potentials of mean force (PMFs) for -any set of colvars, using different sampling methods: currently -implemented are the Adaptive Biasing Force (ABF) method, metadynamics, -Steered Molecular Dynamics (SMD) and Umbrella Sampling (US) via a -flexible harmonic restraint bias. +any set of colvars, using sampling methods, including but not limited to +Adaptive Biasing Force (ABF), metadynamics (MtD), Steered Molecular +Dynamics (SMD) and Umbrella Sampling (US) via a flexible harmonic +restraint bias. -This documentation describes only the fix colvars command itself and -LAMMPS specific parts of the code. The full documentation of the -colvars library is available as `this supplementary PDF document `_ +This documentation describes only the ``fix colvars`` command itself in +a LAMMPS script. The Colvars library is documented via the included +`PDF manual `_ or at the webpage +`https://colvars.github.io/colvars-refman-lammps/colvars-refman-lammps.html +`_. -The Colvars library is developed at `https://github.com/colvars/colvars `_ -A detailed discussion of its implementation is in :ref:`(Fiorin) `. +The Colvars library is developed at `https://github.com/Colvars/colvars +`_ A detailed discussion of its +implementation is in :ref:`(Fiorin) `; additional references are +printed at runtime based on specific features being used. There are some example scripts for using this package with LAMMPS in the -examples/PACKAGES/colvars directory. +``examples/PACKAGES/colvars`` directory. ---------- -The only mandatory argument to the fix is the filename to the colvars -input file that contains the input that is independent from the MD -program in which the colvars library has been integrated. +The only required argument to ``fix colvars`` is the filename to the +Colvars configuration file that contains the definition of the variables +and any biasing methods applied to them. from the MD program in which +the colvars library has been integrated. -The *group-ID* entry is ignored. The collective variable module will -always apply to the entire system and there can only be one instance -of the colvars fix at a time. The colvars fix will only communicate -the minimum information necessary and the colvars library supports -multiple, completely independent collective variables, so there is -no restriction to functionality by limiting the number of colvars fixes. +The *group-ID* entry is ignored. ``fix colvars`` will always apply to +the entire system, but specific atoms will be selected based on +selection keywords in the Colvars configuration file or files. There is +no need to define multiple ``fix colvars`` instances and it is not +allowed. -The *input* keyword allows to specify a state file that would contain -the restart information required in order to continue a calculation from -a prerecorded state. Fix colvars records it state in :doc:`binary restart ` -files, so when using the :doc:`read_restart ` command, -this is usually not needed. +The *output* keyword allows to specify the prefix of output files +generated by Colvars, for example ``output.colvars.traj`` or +``output.pmf``. -The *output* keyword allows to specify the output prefix. All output -files generated will use this prefix followed by the ".colvars." and -a word like "state" or "traj". +The *input* keyword allows to specify an optional state file that +contains the restart information needed to continue a previous +simulation state. Note, however, that ``fix colvars`` records its state +in :doc:`binary restart ` files, so when using the +:doc:`read_restart ` command, this is usually not needed. The *seed* keyword contains the seed for the random number generator -that will be used in the colvars module. +used by Colvars. The *unwrap* keyword controls whether wrapped or unwrapped coordinates -are passed to the colvars library for calculation of the collective +are passed to the Colvars library for calculation of the collective variables and the resulting forces. The default is *yes*, i.e. to use -the image flags to reconstruct the absolute atom positions. -Setting this to *no* will use the current local coordinates that are -wrapped back into the simulation cell at each re-neighboring instead. +the image flags to reconstruct the absolute atom positions. Setting +this to *no* will use the current local coordinates that are wrapped +back into the simulation cell at each re-neighboring instead. For +information about when and how this affects results, please see +`https://colvars.github.io/colvars-refman-lammps/colvars-refman-lammps.html#sec:colvar_atom_groups_wrapping +`_. The *tstat* keyword can be either NULL or the label of a thermostatting -fix that thermostats all atoms in the fix colvars group. This will be -used to provide the colvars module with the current thermostat target +fix that thermostats all atoms in the fix colvars group. This will be +used to let Colvars know what is the current thermostat target temperature. Restart, fix_modify, output, run start/stop, minimize info @@ -95,41 +102,42 @@ Restart, fix_modify, output, run start/stop, minimize info This fix writes the current status of the colvars module into :doc:`binary restart files `. This is in addition to the text -mode status file that is written by the colvars module itself and the -kind of information in both files is identical. +mode ``.colvars.state`` written by Colvars itself and the information in +both files is identical. -The :doc:`fix_modify ` *energy* option is supported by -this fix to add the energy change from the biasing force added by -Colvars to the global potential energy of the system as part of -:doc:`thermodynamic output `. The default setting for -this fix is :doc:`fix_modify energy no `. +The :doc:`fix_modify ` *energy* option is supported by this +fix to add the energy change from the biasing force added by Colvars to +the global potential energy of the system as part of :doc:`thermodynamic +output `. The default setting for this fix is +:doc:`fix_modify energy no `. -The *fix_modify configfile * option allows to add settings -from an additional config file to the colvars module. This option can -only be used, after the system has been initialized with a :doc:`run ` -command. +The *fix_modify configfile * option loads Colvars +configuration from an additional file. This option can only be used, +after the system has been initialized with a :doc:`run ` command. The *fix_modify config * option allows to add settings -from inline strings. Those have to fit on a single line when enclosed -in a pair of double quotes ("), or can span multiple lines when bracketed -by a pair of triple double quotes (""", like python embedded documentation). +from inline strings. Those have to fit on a single line when enclosed in +a pair of double quotes ("), or can span multiple lines when bracketed +by a pair of triple double quotes (""", like Python embedded +documentation). This fix computes a global scalar which can be accessed by various -:doc:`output commands `. The scalar is the Colvars -energy mentioned above. The scalar value calculated by this fix is +:doc:`output commands `. The scalar is the Colvars energy +mentioned above. The scalar value calculated by this fix is "extensive". Restrictions """""""""""" -This fix is part of the COLVARS package. It is only enabled if -LAMMPS was built with that package. See the :doc:`Build package -` page for more info. +``fix colvars`` is provided by the COLVARS package and is only available +if LAMMPS was built with that package. Some of the features also +require code available from the LEPTON package. See the :doc:`Build +package ` page for more info. -There can only be one colvars fix active at a time. Since the interface -communicates only the minimum amount of information and colvars module -itself can handle an arbitrary number of collective variables, this is -not a limitation of functionality. +There can only be one Colvars instance defined at a time. Since the +interface communicates only the minimum amount of information and the +Colvars module itself can handle an arbitrary number of collective +variables, this is not a limitation of functionality. Related commands """""""""""""""" diff --git a/doc/src/lepton_expression.rst b/doc/src/lepton_expression.rst new file mode 100644 index 0000000000..9ecebc921e --- /dev/null +++ b/doc/src/lepton_expression.rst @@ -0,0 +1,122 @@ + +Lepton expression syntax and features +""""""""""""""""""""""""""""""""""""" + +Lepton supports the following operators in expressions: + +.. table_from_list:: + :columns: 14 + + * \+ + * Add + * + * \- + * Subtract + * + * \* + * Multiply + * + * \/ + * Divide + * + * \^ + * Power + +The following mathematical functions are available: + +.. table_from_list:: + :columns: 4 + + * sqrt(x) + * Square root + * exp(x) + * Exponential + * log(x) + * Natural logarithm + * sin(x) + * Sine (angle in radians) + * cos(x) + * Cosine (angle in radians) + * sec(x) + * Secant (angle in radians) + * csc(x) + * Cosecant (angle in radians) + * tan(x) + * Tangent (angle in radians) + * cot(x) + * Cotangent (angle in radians) + * asin(x) + * Inverse sine (in radians) + * acos(x) + * Inverse cosine (in radians) + * atan(x) + * Inverse tangent (in radians) + * sinh(x) + * Hyperbolic sine + * cosh(x) + * Hyperbolic cosine + * tanh(x) + * Hyperbolic tangent + * erf(x) + * Error function + * erfc(x) + * Complementary Error function + * abs(x) + * Absolute value + * min(x,y) + * Minimum of two values + * max(x,y) + * Maximum of two values + * delta(x) + * delta(x) is 1 for `x = 0`, otherwise 0 + * step(x) + * step(x) is 0 for `x < 0`, otherwise 1 + +Numbers may be given in either decimal or exponential form. All of the +following are valid numbers: `5`, `-3.1`, `1e6`, and `3.12e-2`. + +As an extension to the standard Lepton syntax, it is also possible to +use LAMMPS :doc:`variables ` in the format "v_name". Before +evaluating the expression, "v_name" will be replaced with the value of +the variable "name". This is compatible with all kinds of scalar +variables, but not with vectors, arrays, local, or per-atom +variables. If necessary, a custom scalar variable needs to be defined +that can access the desired (single) item from a non-scalar variable. +As an example, the following lines will instruct LAMMPS to ramp +the force constant for a harmonic bond from 100.0 to 200.0 during the +next run: + +.. code-block:: LAMMPS + + variable fconst equal ramp(100.0, 200) + bond_style lepton + bond_coeff 1 1.5 "v_fconst * (r^2)" + +An expression may be followed by definitions for intermediate values that appear in the +expression. A semicolon ";" is used as a delimiter between value definitions. For example, +the expression: + +.. code-block:: C + + a^2+a*b+b^2; a=a1+a2; b=b1+b2 + +is exactly equivalent to + +.. code-block:: C + + (a1+a2)^2+(a1+a2)*(b1+b2)+(b1+b2)^2 + +The definition of an intermediate value may itself involve other +intermediate values. Whitespace and quotation characters ('\'' and '"') +are ignored. All uses of a value must appear *before* that value's +definition. For efficiency reasons, the expression string is parsed, +optimized, and then stored in an internal, pre-parsed representation for +evaluation. + +Evaluating a Lepton expression is typically between 2.5 and 5 times +slower than the corresponding compiled and optimized C++ code. If +additional speed or GPU acceleration (via GPU or KOKKOS) is required, +the interaction can be represented as a table. Suitable table files +can be created either internally using the :doc:`pair_write ` +or :doc:`bond_write ` command or through the Python scripts +in the :ref:`tools/tabulate ` folder. diff --git a/doc/src/pair_lepton.rst b/doc/src/pair_lepton.rst new file mode 100644 index 0000000000..303bc13bb9 --- /dev/null +++ b/doc/src/pair_lepton.rst @@ -0,0 +1,159 @@ +.. index:: pair_style lepton +.. index:: pair_style lepton/omp +.. index:: pair_style lepton/coul +.. index:: pair_style lepton/coul/omp + +pair_style lepton command +========================= + +Accelerator Variants: *lepton/omp*, *lepton/coul/comp* + +Syntax +"""""" + +.. code-block:: LAMMPS + + pair_style style args + +* style = *lepton* or *lepton/coul* +* args = list of arguments for a particular style + +.. parsed-literal:: + + *lepton* args = cutoff + cutoff = global cutoff for the interactions (distance units) + *lepton/coul* args = cutoff keyword + cutoff = global cutoff for the interactions (distance units) + zero or more keywords may be appended + keyword = *ewald* or *pppm* or *msm* or *dispersion* or *tip4p* + +Examples +"""""""" + +.. code-block:: LAMMPS + + pair_style lepton 2.5 + + pair_coeff * * "k*((r-r0)^2*step(r0-r)); k=200; r0=1.5" 2.0 + pair_coeff 1 2 "4.0*eps*((sig/r)^12 - (sig/r)^6);eps=1.0;sig=1.0" 1.12246204830937 + pair_coeff 2 2 "eps*(2.0*(sig/r)^9 - 3.0*(sig/r)^6);eps=1.0;sig=1.0" + + pair_style lepton/coul 2.5 + pair_coeff 1 1 "qi*qj/r" 4.0 + pair_coeff 1 2 "lj+coul; lj=4.0*eps*((sig/r)^12 - (sig/r)^6); eps=1.0; sig=1.0; coul=qi*qj/r" + + pair_style lepton/coul 2.5 pppm + kspace_style pppm 1.0e-4 + pair_coeff 1 1 "qi*qj/r*erfc(alpha*r); alpha=1.067" + +Description +""""""""""" + +.. versionadded:: TBD + +Pair styles *lepton* and *lepton/coul* compute pairwise interactions +between particles which depend solely on the distance and have a cutoff. +The potential function must be provided as an expression string using +"r" as the distance variable. With pair style *lepton/coul* one may +additionally reference the charges of the two atoms of the pair with +"qi" and "qj", respectively. Note that further constants in the +expression can be defined in the same string as additional expressions +separated by semi-colons as shown in the examples above. + +The expression `"200.0*(r-1.5)^2"` represents a harmonic potential +around the pairwise distance :math:`r_0` of 1.5 distance units and a +force constant *K* of 200.0 energy units: + +.. math:: + + U_{ij} = K (r-r_0)^2 + +The expression `"qi*qj/r"` represents a regular Coulombic potential with cutoff: + +.. math:: + + U_{ij} = \frac{C q_i q_j}{\epsilon r} \qquad r < r_c + +The `Lepton library `_, that the +*lepton* pair style interfaces with, evaluates this expression string at +run time to compute the pairwise energy. It also creates an analytical +representation of the first derivative of this expression with respect +to "r" and then uses that to compute the force between the pairs of +particles within the given cutoff. + +The following coefficients must be defined for each pair of atoms types +via the :doc:`pair_coeff ` command as in the examples above, +or in the data file or restart files read by the :doc:`read_data +` or :doc:`read_restart ` commands: + +* Lepton expression (energy units) +* cutoff (distance units) + +The Lepton expression must be either enclosed in quotes or must not +contain any whitespace so that LAMMPS recognizes it as a single keyword. +More on valid Lepton expressions below. The last coefficient is +optional; it allows to set the cutoff for a pair of atom types to a +different value than the global cutoff. + +For pair style *lepton* only the "lj" value of the :doc:`special_bonds ` +settings apply in case the interacting pair is also connected with a bond. +The potential energy will *only* be added to the "evdwl" property. + +For pair style *lepton/coul* only the "coul" value of the :doc:`special_bonds ` +settings apply in case the interacting pair is also connected with a bond. +The potential energy will *only* be added to the "ecoul" property. + +---------- + +.. include:: lepton_expression.rst + +---------- + +.. include:: accel_styles.rst + +---------- + +Mixing, shift, table, tail correction, restart, rRESPA info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Pair styles *lepton* and *lepton/coul* do not support mixing. Thus, +expressions for *all* I,J pairs must be specified explicitly. + +Only pair style *lepton* supports the :doc:`pair_modify shift ` +option for shifting the energy of the pair interaction so that it is +0 at the cutoff, pair style *lepton/coul* does *not*. + +The :doc:`pair_modify table ` options are not relevant for +the these pair styles. + +These pair styles do not support the :doc:`pair_modify tail +` option for adding long-range tail corrections to energy +and pressure. + +These pair styles write its information to :doc:`binary restart files +`, so pair_style and pair_coeff commands do not need to be +specified in an input script that reads a restart file. + +These pair styles can only be used via the *pair* keyword of the +:doc:`run_style respa ` command. They do not support the +*inner*, *middle*, *outer* keywords. + +---------- + +Restrictions +"""""""""""" + +These pair styles are part of the LEPTON package and only enabled if +LAMMPS was built with this package. See the :doc:`Build package +` page for more info. + +Related commands +"""""""""""""""" + +:doc:`pair_coeff `, :doc:`pair_style python `, +:doc:`pair_style table `, :doc:`pair_write ` + +Default +""""""" + +none diff --git a/doc/src/pair_style.rst b/doc/src/pair_style.rst index 48daf34f17..3f91bfc0b4 100644 --- a/doc/src/pair_style.rst +++ b/doc/src/pair_style.rst @@ -212,6 +212,8 @@ accelerated styles exist. * :doc:`lcbop ` - long-range bond-order potential (LCBOP) * :doc:`lebedeva/z ` - Lebedeva interlayer potential for graphene with normals along z-axis * :doc:`lennard/mdf ` - LJ potential in A/B form with a taper function +* :doc:`lepton ` - pair potential from evaluating a string +* :doc:`lepton/coul ` - pair potential from evaluating a string with support for charges * :doc:`line/lj ` - LJ potential between line segments * :doc:`list ` - potential between pairs of atoms explicitly listed in an input file * :doc:`lj/charmm/coul/charmm ` - CHARMM potential with cutoff Coulomb diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index c1eb202525..1724cb4982 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -554,6 +554,7 @@ corotate corotation corotational correlator +Cosecant cosineshifted cossq costheta @@ -586,6 +587,7 @@ Crozier Cryst Crystallogr Csanyi +csc csg csh cshrc @@ -2236,7 +2238,7 @@ msm msmflag msse msst -Mtchell +MtD Mth mtk Mtotal @@ -3277,6 +3279,7 @@ Simul simulations Sinkovits Sinnott +sinh sinusoid sinusoidally SiO diff --git a/lib/README b/lib/README index ab71e6763c..255077bb1b 100644 --- a/lib/README +++ b/lib/README @@ -33,6 +33,8 @@ kim hooks to the KIM library, used by KIM package from Ryan Elliott and Ellad Tadmor (U Minn) kokkos Kokkos package for GPU and many-core acceleration from Kokkos development team (Sandia) +lepton Lepton library for fast evaluation of mathematical + expressions from a string. Imported from OpenMM. linalg set of BLAS and LAPACK routines needed by ATC package from Axel Kohlmeyer (Temple U) mdi hooks to the MDI library, used by MDI package diff --git a/lib/colvars/Makefile.common b/lib/colvars/Makefile.common index 31a93652ae..356a7f4a91 100644 --- a/lib/colvars/Makefile.common +++ b/lib/colvars/Makefile.common @@ -61,29 +61,25 @@ COLVARS_SRCS = \ colvarvalue.cpp \ colvar_neuralnetworkcompute.cpp -LEPTON_SRCS = \ - lepton/src/CompiledExpression.cpp \ - lepton/src/CompiledVectorExpression.cpp \ - lepton/src/ExpressionProgram.cpp \ - lepton/src/ExpressionTreeNode.cpp \ - lepton/src/Operation.cpp \ - lepton/src/ParsedExpression.cpp \ - lepton/src/Parser.cpp - # Allow to selectively turn off Lepton ifeq ($(COLVARS_LEPTON),no) -LEPTON_INCFLAGS = -COLVARS_OBJS = $(COLVARS_SRCS:.cpp=.o) + +LEPTON_INCFLAGS = + else -LEPTON_INCFLAGS = -Ilepton/include -DLEPTON -COLVARS_OBJS = $(COLVARS_SRCS:.cpp=.o) $(LEPTON_SRCS:.cpp=.o) + +LEPTON_DIR = ../lepton +include $(LEPTON_DIR)/Settings.mk +LEPTON_INCFLAGS = $(LEPTON_INC) $(LEPTON_DEF) + endif +COLVARS_OBJS = $(COLVARS_SRCS:.cpp=.o) %.o: %.cpp $(CXX) $(CXXFLAGS) $(COLVARS_INCFLAGS) $(LEPTON_INCFLAGS) -c -o $@ $< -$(COLVARS_LIB): Makefile.deps $(COLVARS_OBJS) +$(COLVARS_LIB): Makefile.deps $(COLVARS_OBJS) $(AR) $(ARFLAGS) $(COLVARS_LIB) $(COLVARS_OBJS) @@ -97,12 +93,3 @@ Makefile.deps: $(COLVARS_SRCS) include Makefile.deps -Makefile.lepton.deps: $(LEPTON_SRCS) - @echo > $@ - @for src in $^ ; do \ - obj=`basename $$src .cpp`.o ; \ - $(CXX) $(CXXFLAGS) -MM $(LEPTON_INCFLAGS) \ - -MT '$$(COLVARS_OBJ_DIR)'$$obj $$src >> $@ ; \ - done - -include Makefile.lepton.deps diff --git a/lib/colvars/Makefile.deps b/lib/colvars/Makefile.deps index d26df41995..6619653af0 100644 --- a/lib/colvars/Makefile.deps +++ b/lib/colvars/Makefile.deps @@ -5,327 +5,367 @@ $(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h \ colvaratoms.h colvardeps.h $(COLVARS_OBJ_DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h \ colvars_version.h colvar.h colvarvalue.h colvartypes.h colvarparse.h \ - colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarbias_abf.h colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ - colvarbias.h colvargrid.h colvar_UIestimator.h + colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarbias_abf.h colvarproxy.h \ + colvarproxy_tcl.h colvarproxy_volmaps.h colvarbias.h colvargrid.h \ + colvar_UIestimator.h $(COLVARS_OBJ_DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h \ colvars_version.h colvarbias.h colvar.h colvarvalue.h colvartypes.h \ - colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarbias_alb.h + colvarparse.h colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarbias_alb.h $(COLVARS_OBJ_DIR)colvarbias.o: colvarbias.cpp colvarmodule.h \ colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvarbias.h colvar.h \ - colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvargrid.h + colvarparse.h colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvargrid.h $(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \ colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \ colvarvalue.h colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h \ - colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarbias_histogram.h colvarbias.h colvargrid.h + colvarparse.h colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarbias_histogram.h colvarbias.h \ + colvargrid.h $(COLVARS_OBJ_DIR)colvarbias_histogram_reweight_amd.o: \ colvarbias_histogram_reweight_amd.cpp \ colvarbias_histogram_reweight_amd.h colvarbias_histogram.h colvarbias.h \ colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ - colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvargrid.h colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h + colvarparse.h colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvargrid.h colvarproxy.h \ + colvarproxy_tcl.h colvarproxy_volmaps.h $(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvarmodule.h \ colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvarparse.h \ - colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarbias_meta.h colvarbias.h colvargrid.h + colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarbias_meta.h colvarbias.h \ + colvargrid.h $(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \ colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \ colvarvalue.h colvarproxy_tcl.h colvarproxy_volmaps.h \ colvarbias_restraint.h colvarbias.h colvar.h colvarparse.h \ - colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h + colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h $(COLVARS_OBJ_DIR)colvarcomp_alchlambda.o: colvarcomp_alchlambda.cpp \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_angles.o: colvarcomp_angles.cpp \ colvarmodule.h colvars_version.h colvar.h colvarvalue.h colvartypes.h \ - colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + colvarparse.h colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_apath.o: colvarcomp_apath.cpp colvarmodule.h \ colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \ - colvarparams.h colvar.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + colvarparams.h colvar.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp \ colvarmodule.h colvars_version.h colvarparse.h colvarvalue.h \ colvartypes.h colvarparams.h colvaratoms.h colvarproxy.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h colvar.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvar_arithmeticpath.h \ + colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h \ colvars_version.h colvarvalue.h colvartypes.h colvar.h colvarparse.h \ - colvarparams.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + colvarparams.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_distances.o: colvarcomp_distances.cpp \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_gpath.o: colvarcomp_gpath.cpp colvarmodule.h \ colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \ - colvarparams.h colvar.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + colvarparams.h colvar.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_neuralnetwork.o: \ colvarcomp_neuralnetwork.cpp colvarmodule.h colvars_version.h \ colvarvalue.h colvartypes.h colvarparse.h colvarparams.h colvar.h \ - colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h \ + colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h \ colvar_neuralnetworkcompute.h $(COLVARS_OBJ_DIR)colvarcomp_combination.o: colvarcomp_combination.cpp \ colvarcomp.h colvarmodule.h colvars_version.h colvar.h colvarvalue.h \ colvartypes.h colvarparse.h colvarparams.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvaratoms.h colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ - colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvaratoms.h colvarproxy.h \ + colvarproxy_tcl.h colvarproxy_volmaps.h colvar_arithmeticpath.h \ + colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvarcomp_volmaps.o: colvarcomp_volmaps.cpp \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h $(COLVARS_OBJ_DIR)colvar.o: colvar.cpp colvarmodule.h colvars_version.h \ colvarvalue.h colvartypes.h colvarparse.h colvarparams.h colvar.h \ - colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h \ - colvarscript.h colvarbias.h colvarscript_commands.h \ - colvarscript_commands_colvar.h colvarscript_commands_bias.h + colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h colvarscript.h \ + colvarbias.h colvarscript_commands.h colvarscript_commands_colvar.h \ + colvarscript_commands_bias.h $(COLVARS_OBJ_DIR)colvardeps.o: colvardeps.cpp colvarmodule.h \ colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h colvarparse.h \ colvarparams.h $(COLVARS_OBJ_DIR)colvargrid.o: colvargrid.cpp colvarmodule.h \ colvars_version.h colvarvalue.h colvartypes.h colvarparse.h \ - colvarparams.h colvar.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ - colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h \ - colvargrid.h + colvarparams.h colvar.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarcomp.h colvaratoms.h \ + colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ + colvar_arithmeticpath.h colvar_geometricpath.h colvargrid.h $(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \ colvars_version.h colvarparse.h colvarvalue.h colvartypes.h \ colvarparams.h colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \ - colvar.h colvardeps.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarbias.h colvarbias_abf.h colvargrid.h colvar_UIestimator.h \ - colvarbias_alb.h colvarbias_histogram.h \ - colvarbias_histogram_reweight_amd.h colvarbias_meta.h \ - colvarbias_restraint.h colvarscript.h colvarscript_commands.h \ - colvarscript_commands_colvar.h colvarscript_commands_bias.h \ - colvaratoms.h colvarcomp.h colvar_arithmeticpath.h \ - colvar_geometricpath.h colvarmodule_refs.h + colvar.h colvardeps.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarbias.h colvarbias_abf.h \ + colvargrid.h colvar_UIestimator.h colvarbias_alb.h \ + colvarbias_histogram.h colvarbias_histogram_reweight_amd.h \ + colvarbias_meta.h colvarbias_restraint.h colvarscript.h \ + colvarscript_commands.h colvarscript_commands_colvar.h \ + colvarscript_commands_bias.h colvaratoms.h colvarcomp.h \ + colvar_arithmeticpath.h colvar_geometricpath.h colvarmodule_refs.h $(COLVARS_OBJ_DIR)colvarparams.o: colvarparams.cpp colvarmodule.h \ colvars_version.h colvarvalue.h colvartypes.h colvarparams.h $(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \ @@ -335,17 +375,19 @@ $(COLVARS_OBJ_DIR)colvarproxy.o: colvarproxy.cpp colvarmodule.h \ colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvarscript.h colvarbias.h \ colvar.h colvarparse.h colvarparams.h colvardeps.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarscript_commands.h colvarscript_commands_colvar.h \ - colvarscript_commands_bias.h colvaratoms.h colvarmodule_utils.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarscript_commands.h \ + colvarscript_commands_colvar.h colvarscript_commands_bias.h \ + colvaratoms.h colvarmodule_utils.h $(COLVARS_OBJ_DIR)colvarproxy_replicas.o: colvarproxy_replicas.cpp \ colvarmodule.h colvars_version.h colvarproxy.h colvartypes.h \ colvarvalue.h colvarproxy_tcl.h colvarproxy_volmaps.h @@ -360,64 +402,68 @@ $(COLVARS_OBJ_DIR)colvarscript.o: colvarscript.cpp colvarproxy.h \ colvarmodule.h colvars_version.h colvartypes.h colvarvalue.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h colvarparse.h \ colvarparams.h colvarscript.h colvarbias.h colvar.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarscript_commands.h colvarscript_commands_colvar.h \ - colvarscript_commands_bias.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarscript_commands.h \ + colvarscript_commands_colvar.h colvarscript_commands_bias.h $(COLVARS_OBJ_DIR)colvarscript_commands.o: colvarscript_commands.cpp \ colvarproxy.h colvarmodule.h colvars_version.h colvartypes.h \ colvarvalue.h colvarproxy_tcl.h colvarproxy_volmaps.h colvardeps.h \ colvarparse.h colvarparams.h colvarscript.h colvarbias.h colvar.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarscript_commands.h colvarscript_commands_colvar.h \ - colvarscript_commands_bias.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarscript_commands.h \ + colvarscript_commands_colvar.h colvarscript_commands_bias.h $(COLVARS_OBJ_DIR)colvarscript_commands_bias.o: \ colvarscript_commands_bias.cpp colvarproxy.h colvarmodule.h \ colvars_version.h colvartypes.h colvarvalue.h colvarproxy_tcl.h \ colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h \ - colvarscript.h colvarbias.h colvar.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarscript_commands.h colvarscript_commands_colvar.h \ - colvarscript_commands_bias.h + colvarscript.h colvarbias.h colvar.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarscript_commands.h \ + colvarscript_commands_colvar.h colvarscript_commands_bias.h $(COLVARS_OBJ_DIR)colvarscript_commands_colvar.o: \ colvarscript_commands_colvar.cpp colvarproxy.h colvarmodule.h \ colvars_version.h colvartypes.h colvarvalue.h colvarproxy_tcl.h \ colvarproxy_volmaps.h colvardeps.h colvarparse.h colvarparams.h \ - colvarscript.h colvarbias.h colvar.h lepton/include/Lepton.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarscript_commands.h colvarscript_commands_colvar.h \ - colvarscript_commands_bias.h + colvarscript.h colvarbias.h colvar.h ../lepton/include/Lepton.h \ + ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarscript_commands.h \ + colvarscript_commands_colvar.h colvarscript_commands_bias.h $(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \ colvars_version.h colvartypes.h colvarparse.h colvarvalue.h \ colvarparams.h ../../src/math_eigen_impl.h @@ -425,14 +471,15 @@ $(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \ colvars_version.h colvarvalue.h colvartypes.h $(COLVARS_OBJ_DIR)colvar_neuralnetworkcompute.o: \ colvar_neuralnetworkcompute.cpp colvar_neuralnetworkcompute.h \ - lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ - colvarparse.h colvarmodule.h colvars_version.h colvarvalue.h \ - colvartypes.h colvarparams.h + ../lepton/include/Lepton.h ../lepton/include/lepton/CompiledExpression.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/windowsIncludes.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/ExpressionProgram.h \ + ../lepton/include/lepton/ExpressionTreeNode.h \ + ../lepton/include/lepton/Operation.h \ + ../lepton/include/lepton/CustomFunction.h \ + ../lepton/include/lepton/Exception.h \ + ../lepton/include/lepton/ParsedExpression.h \ + ../lepton/include/lepton/Parser.h colvarparse.h colvarmodule.h \ + colvars_version.h colvarvalue.h colvartypes.h colvarparams.h diff --git a/lib/colvars/Makefile.lepton.deps b/lib/colvars/Makefile.lepton.deps deleted file mode 100644 index 4546339de6..0000000000 --- a/lib/colvars/Makefile.lepton.deps +++ /dev/null @@ -1,50 +0,0 @@ - -$(COLVARS_OBJ_DIR)CompiledExpression.o: lepton/src/CompiledExpression.cpp \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h -$(COLVARS_OBJ_DIR)CompiledVectorExpression.o: \ - lepton/src/CompiledVectorExpression.cpp \ - lepton/include/lepton/CompiledVectorExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h -$(COLVARS_OBJ_DIR)ExpressionProgram.o: lepton/src/ExpressionProgram.cpp \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h -$(COLVARS_OBJ_DIR)ExpressionTreeNode.o: lepton/src/ExpressionTreeNode.cpp \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/Exception.h lepton/include/lepton/Operation.h \ - lepton/include/lepton/CustomFunction.h lepton/include/lepton/Exception.h -$(COLVARS_OBJ_DIR)Operation.o: lepton/src/Operation.cpp \ - lepton/include/lepton/Operation.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h lepton/include/lepton/Exception.h \ - lepton/include/lepton/ExpressionTreeNode.h lepton/src/MSVC_erfc.h -$(COLVARS_OBJ_DIR)ParsedExpression.o: lepton/src/ParsedExpression.cpp \ - lepton/include/lepton/ParsedExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CompiledExpression.h \ - lepton/include/lepton/CompiledVectorExpression.h \ - lepton/include/lepton/ExpressionProgram.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h -$(COLVARS_OBJ_DIR)Parser.o: lepton/src/Parser.cpp \ - lepton/include/lepton/Parser.h lepton/include/lepton/windowsIncludes.h \ - lepton/include/lepton/CustomFunction.h lepton/include/lepton/Exception.h \ - lepton/include/lepton/ExpressionTreeNode.h \ - lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \ - lepton/include/lepton/Exception.h \ - lepton/include/lepton/ParsedExpression.h \ - lepton/include/lepton/ExpressionTreeNode.h diff --git a/lib/colvars/README b/lib/colvars/README index eeba557ce3..cd1e08b6de 100644 --- a/lib/colvars/README +++ b/lib/colvars/README @@ -35,39 +35,32 @@ The reference article is: The Colvars library can be built for the most part with all major versions of the C++ language. -A few of the most recent features require C++11 support. In particular, the -library is optionally built together with the -"Lepton"_https://simtk.org/projects/lepton library, a copy of which is also -included in the LAMMPS distribution. Lepton implements the -"customFunction"_http://colvars.github.io/colvars-refman-lammps/colvars-refman-lammps.html#colvar|customFunction -feature, and requires C++11 support. - -See "here"_https://colvars.github.io/README-c++11.html for a detailed list of -C++11-only features. - +A few of the most recent features require C++11 support, which is also required +by LAMMPS, so no additional notes are needed. ## How to build (CMake) This is the recommended build recipe: no additional settings are normally needed besides "-D PKG_COLVARS=yes". -Building and linking of Lepton (or other C++11-only features) is enabled -automatically when compilation is carried out with C++11 support, and disabled -otherwise. Optionally, Lepton build may be manually controlled with the flag -"-D COLVARS_LEPTON=yes|no". - +Linking to the Lepton library, which is also used by the LEPTON LAMMPS package, +is enabled automatically. Optionally, support for Lepton within Colvars may +be manually controlled with theCMake setting "-D COLVARS_LEPTON=yes|no". ## How to build (traditional make) -Before building LAMMPS, one must build the Colvars library in lib/colvars. +Before building LAMMPS, one must build the Colvars library in lib/colvars +and the Lepton library in lib/lepton. For building Lepton please see the +README.md file in the lib/lepton folder. -This can be done manually in the same folder by using or adapting one of the -provided Makefiles: for example, Makefile.g++ for the GNU compiler. +Building the Colvars library can be done manually in the respective +folders by using or adapting one of the provided Makefiles: for example, +Makefile.g++ for the GNU compiler. In general, it is safer to use build setting consistent with the rest of LAMMPS. This is best carried out from the LAMMPS src directory using a -command like these, which simply invoke the lib/colvars/Install.py script with -the specified args: +command like these, which simply invoke the lib/colvars/Install.py script +with the specified args: make lib-colvars # print help message make lib-colvars args="-m serial" # build with GNU g++ compiler (settings as with "make serial") diff --git a/lib/lepton/Common.mk b/lib/lepton/Common.mk new file mode 100644 index 0000000000..3eead392a4 --- /dev/null +++ b/lib/lepton/Common.mk @@ -0,0 +1,123 @@ +# -*- makefile -*- +# common settings for Lepton library makefiles + +SRC= \ + src/CompiledExpression.cpp \ + src/CompiledVectorExpression.cpp \ + src/ExpressionProgram.cpp \ + src/ExpressionTreeNode.cpp \ + src/Operation.cpp \ + src/ParsedExpression.cpp \ + src/Parser.cpp +OBJ=$(SRC:src/%.cpp=build/lepton.%.o) + +JITARM= \ + asmjit/arm/a64assembler.cpp \ + asmjit/arm/a64builder.cpp \ + asmjit/arm/a64compiler.cpp \ + asmjit/arm/a64emithelper.cpp \ + asmjit/arm/a64formatter.cpp \ + asmjit/arm/a64func.cpp \ + asmjit/arm/a64instapi.cpp \ + asmjit/arm/a64instdb.cpp \ + asmjit/arm/a64operand.cpp \ + asmjit/arm/a64rapass.cpp \ + asmjit/arm/armformatter.cpp +JITX86 = \ + asmjit/x86/x86assembler.cpp \ + asmjit/x86/x86builder.cpp \ + asmjit/x86/x86compiler.cpp \ + asmjit/x86/x86emithelper.cpp \ + asmjit/x86/x86formatter.cpp \ + asmjit/x86/x86func.cpp \ + asmjit/x86/x86instapi.cpp \ + asmjit/x86/x86instdb.cpp \ + asmjit/x86/x86operand.cpp \ + asmjit/x86/x86rapass.cpp +JITCORE= \ + asmjit/core/archtraits.cpp \ + asmjit/core/assembler.cpp \ + asmjit/core/builder.cpp \ + asmjit/core/codeholder.cpp \ + asmjit/core/codewriter.cpp \ + asmjit/core/compiler.cpp \ + asmjit/core/constpool.cpp \ + asmjit/core/cpuinfo.cpp \ + asmjit/core/emithelper.cpp \ + asmjit/core/emitter.cpp \ + asmjit/core/emitterutils.cpp \ + asmjit/core/environment.cpp \ + asmjit/core/errorhandler.cpp \ + asmjit/core/formatter.cpp \ + asmjit/core/funcargscontext.cpp \ + asmjit/core/func.cpp \ + asmjit/core/globals.cpp \ + asmjit/core/inst.cpp \ + asmjit/core/jitallocator.cpp \ + asmjit/core/jitruntime.cpp \ + asmjit/core/logger.cpp \ + asmjit/core/operand.cpp \ + asmjit/core/osutils.cpp \ + asmjit/core/ralocal.cpp \ + asmjit/core/rapass.cpp \ + asmjit/core/rastack.cpp \ + asmjit/core/string.cpp \ + asmjit/core/support.cpp \ + asmjit/core/target.cpp \ + asmjit/core/type.cpp \ + asmjit/core/virtmem.cpp \ + asmjit/core/zone.cpp \ + asmjit/core/zonehash.cpp \ + asmjit/core/zonelist.cpp \ + asmjit/core/zonestack.cpp \ + asmjit/core/zonetree.cpp \ + asmjit/core/zonevector.cpp + +JITOBJ=$(JITX86:asmjit/x86/%.cpp=build/x86.%.o) \ + $(JITARM:asmjit/arm/%.cpp=build/arm.%.o) \ + $(JIXCORE:asmjit/core/%.cpp=build/core.%.o) + +LEPTON_DIR=. + +include $(LEPTON_DIR)/Settings.mk + +EXTRAMAKE=Makefile.lammps.empty +LIB=liblepton.a + +ifeq ($(ENABLE_JIT),1) +OBJ += $(JITOBJ) +endif + +INC += $(LEPTON_INC) +CXXFLAGS += $(LEPTON_DEF) + +all: $(LIB) Makefile.lammps + +build: + mkdir -p build + +build/lepton.%.o: src/%.cpp build + $(CXX) $(INC) $(CXXFLAGS) -c $< -o $@ + +build/arm.%.o: asmjit/arm/%.cpp build + $(CXX) $(INC) $(CXXFLAGS) -c $< -o $@ + +build/x86.%.o: asmjit/x86/%.cpp build + $(CXX) $(INC) $(CXXFLAGS) -c $< -o $@ + +build/core.%.o: asmjit/core/%.cpp build + $(CXX) $(INC) $(CXXFLAGS) -c $< -o $@ + +Makefile.lammps: + cp $(EXTRAMAKE) $@ + sed -i -e 's,^.*lepton_SYSINC *=.*$$,lepton_SYSINC = $(DEF),' $@ + +.PHONY: all lib clean + +$(LIB) : $(OBJ) + $(AR) $(ARFLAGS) $@ $^ + +clean: + rm -f build/*.o $(LIB) *~ Makefile.lammps + + diff --git a/lib/lepton/Install.py b/lib/lepton/Install.py new file mode 100755 index 0000000000..34e01ad339 --- /dev/null +++ b/lib/lepton/Install.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +""" +Install.py tool to build the Lepton library +""" + +from __future__ import print_function +import sys, os, subprocess +from argparse import ArgumentParser + +sys.path.append('..') +from install_helpers import get_cpus, fullpath + +parser = ArgumentParser(prog='Install.py', + description="LAMMPS Lepton library build wrapper script") + +HELP = """ +Syntax from src dir: make lib-lepton args="-m machine" +Syntax from lib dir: python Install.py -m machine + +specify -m + +Examples: + +make lib-lepton args="-m serial" # build Lepton lib with same settings as in the serial Makefile in src +python Install.py -m mpi # build Lepton lib with same settings as in the mpi Makefile in src +""" + +# parse and process arguments + +parser.add_argument("-m", "--machine", + help="suffix of a /Makefile.* file used for compiling this library") + +args = parser.parse_args() + +# print help message and exit, if neither build nor path options are given +if not args.machine: + parser.print_help() + sys.exit(HELP) + +machine = args.machine + +# set lib from working dir + +cwd = fullpath('.') +lib = os.path.basename(cwd) + +if not os.path.exists("Makefile.%s" % machine): + sys.exit("lib/%s/Makefile.%s does not exist" % (lib, machine)) + +# make the library with parallel make +n_cpus = get_cpus() + +print("Building lib%s.a ..." % lib) +cmd = "make -f Makefile.%s clean; make -f Makefile.%s -j%d" % (machine, machine, n_cpus) +try: + txt = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) + print(txt.decode('UTF-8')) +except subprocess.CalledProcessError as e: + print("Make failed with:\n %s" % e.output.decode('UTF-8')) + sys.exit(1) + +if os.path.exists("lib%s.a" % lib): + print("Build was successful") +else: + sys.exit("Build of lib/%s/lib%s.a was NOT successful" % (lib, lib)) + +if not os.path.exists("Makefile.lammps"): + print("WARNING: lib/%s/Makefile.lammps was NOT created" % lib) diff --git a/lib/lepton/LICENSE b/lib/lepton/LICENSE new file mode 100644 index 0000000000..6359209705 --- /dev/null +++ b/lib/lepton/LICENSE @@ -0,0 +1,20 @@ +Portions copyright (c) 2009-2019 Stanford University and the Authors. +Authors: Peter Eastman and OpenMM contributors + +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, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/lepton/Makefile.lammps.empty b/lib/lepton/Makefile.lammps.empty new file mode 100644 index 0000000000..57d5846c1b --- /dev/null +++ b/lib/lepton/Makefile.lammps.empty @@ -0,0 +1,5 @@ +# Settings that the LAMMPS build will import when this package library is used + +lepton_SYSINC = +lepton_SYSLIB = +lepton_SYSPATH = diff --git a/lib/lepton/Makefile.mpi b/lib/lepton/Makefile.mpi new file mode 100644 index 0000000000..ee5d9aafae --- /dev/null +++ b/lib/lepton/Makefile.mpi @@ -0,0 +1,8 @@ +# -*- makefile -*- + +CC=mpicxx +CXXFLAGS=-D_DEFAULT_SOURCE -O2 -Wall -fPIC -std=c++11 +AR=ar +ARFLAGS=rc + +include Common.mk diff --git a/lib/lepton/Makefile.serial b/lib/lepton/Makefile.serial new file mode 100644 index 0000000000..bebe2ce873 --- /dev/null +++ b/lib/lepton/Makefile.serial @@ -0,0 +1,8 @@ +# -*- makefile -*- + +CC=g++ +CXXFLAGS=-D_DEFAULT_SOURCE -O3 -DNDEBUG -Wall -fPIC -std=c++11 -ffast-math -msse4.2 +AR=ar +ARFLAGS=rc + +include Common.mk diff --git a/lib/lepton/README.md b/lib/lepton/README.md new file mode 100644 index 0000000000..d83fe7ffc1 --- /dev/null +++ b/lib/lepton/README.md @@ -0,0 +1,28 @@ +This directory contains the lepton library from the OpenMM software +which allows to efficiently evaluate mathematical expressions from +strings. This library is used with the LEPTON package that support +force styles within LAMMPS that make use of this library. + +You can type "make lib-lepton" from the src directory to see help on how +to build this library via make commands, or you can do the same thing +by typing "python Install.py" from within this directory, or you can +do it manually by following the instructions below. + +--------------------- + +Lepton (short for “lightweight expression parser”) is a C++ library for +parsing, evaluating, differentiating, and analyzing mathematical +expressions. It takes expressions in the form of text strings, then +converts them to an internal representation suitable for evaluation or +analysis. Here are some of its major features: + +- Support for a large number of standard mathematical functions and operations. +- Support for user defined custom functions. +- A variety of optimizations for automatically simplifying expressions. +- Computing analytic derivatives. +- Representing parsed expressions in two different forms (tree or program) suitable for + further analysis or processing. +- Support for just-in-time compilation via asmjit library on x86 (autodetected) + This should make evaluation about 2 times faster + +Lepton was originally created for use in the [OpenMM project](https://openmm.org) diff --git a/lib/lepton/Settings.mk b/lib/lepton/Settings.mk new file mode 100644 index 0000000000..d7fd0ac22e --- /dev/null +++ b/lib/lepton/Settings.mk @@ -0,0 +1,17 @@ +# makefile variables and settings related to configuring JIT with Lepton. + +ENABLE_JIT=0 +ifeq ($(shell uname -m),x86_64) +ENABLE_JIT=1 +endif +ifeq ($(shell uname -m),amd64) +ENABLE_JIT=1 +endif + +LEPTON_INC = -I$(LEPTON_DIR)/include +LEPTON_DEF = -DLEPTON_BUILDING_STATIC_LIBRARY=1 + +ifeq ($(ENABLE_JIT),1) +LEPTON_INC += -I$(LEPTON_DIR) +LEPTON_DEF += -DLEPTON_USE_JIT=1 -DASMJIT_BUILD_X86=1 -DASMJIT_STATIC=1 -DASMJIT_BUILD_RELEASE=1 +endif diff --git a/lib/lepton/asmjit/LICENSE.md b/lib/lepton/asmjit/LICENSE.md new file mode 100644 index 0000000000..020a569dbd --- /dev/null +++ b/lib/lepton/asmjit/LICENSE.md @@ -0,0 +1,17 @@ +Copyright (c) 2008-2020 The AsmJit Authors + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/lib/lepton/asmjit/a64.h b/lib/lepton/asmjit/a64.h new file mode 100644 index 0000000000..ea4d304f05 --- /dev/null +++ b/lib/lepton/asmjit/a64.h @@ -0,0 +1,62 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#ifndef ASMJIT_A64_H_INCLUDED +#define ASMJIT_A64_H_INCLUDED + +//! \addtogroup asmjit_a64 +//! +//! ### Emitters +//! +//! - \ref a64::Assembler - AArch64 assembler (must read, provides examples). +//! - \ref a64::Builder - AArch64 builder. +//! - \ref a64::Compiler - AArch64 compiler. +//! - \ref a64::Emitter - AArch64 emitter (abstract). +//! +//! ### Supported Instructions +//! +//! - Emitters: +//! - \ref a64::EmitterExplicitT - Provides all instructions that use explicit +//! operands, provides also utility functions. The member functions provided +//! are part of all ARM/AArch64 emitters. +//! +//! - Instruction representation: +//! - \ref a64::Inst::Id - instruction identifiers. +//! +//! ### Register Operands +//! +//! - \ref arm::Reg - Base class for any AArch32/AArch64 register. +//! - \ref arm::Gp - General purpose register: +//! - \ref arm::GpW - 32-bit register. +//! - \ref arm::GpX - 64-bit register. +//! - \ref arm::Vec - Vector (SIMD) register: +//! - \ref arm::VecB - 8-bit SIMD register (AArch64 only). +//! - \ref arm::VecH - 16-bit SIMD register (AArch64 only). +//! - \ref arm::VecS - 32-bit SIMD register. +//! - \ref arm::VecD - 64-bit SIMD register. +//! - \ref arm::VecV - 128-bit SIMD register. +//! +//! ### Memory Operands +//! +//! - \ref arm::Mem - AArch32/AArch64 memory operand that provides support for all ARM addressing features +//! including base, index, pre/post increment, and ARM-specific shift addressing and index extending. +//! +//! ### Other +//! +//! - \ref arm::Shift - Shift operation and value. +//! - \ref a64::Utils - Utilities that can help during code generation for AArch64. + +#include "./arm.h" +#include "./arm/a64assembler.h" +#include "./arm/a64builder.h" +#include "./arm/a64compiler.h" +#include "./arm/a64emitter.h" +#include "./arm/a64globals.h" +#include "./arm/a64instdb.h" +#include "./arm/a64operand.h" +#include "./arm/a64utils.h" + +#endif // ASMJIT_A64_H_INCLUDED + diff --git a/lib/lepton/asmjit/arm.h b/lib/lepton/asmjit/arm.h new file mode 100644 index 0000000000..57ffa815b8 --- /dev/null +++ b/lib/lepton/asmjit/arm.h @@ -0,0 +1,62 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#ifndef ASMJIT_ARM_H_INCLUDED +#define ASMJIT_ARM_H_INCLUDED + +//! \addtogroup asmjit_arm +//! +//! ### Namespaces +//! +//! - \ref arm - arm namespace provides common functionality for both AArch32 and AArch64 backends. +//! - \ref a64 - a64 namespace provides support for AArch64 architecture. In addition it includes +//! \ref arm namespace, so you can only use a single namespace when targeting AArch64 architecture. +//! +//! ### Emitters +//! +//! - AArch64 +//! - \ref a64::Assembler - AArch64 assembler (must read, provides examples). +//! - \ref a64::Builder - AArch64 builder. +//! - \ref a64::Compiler - AArch64 compiler. +//! - \ref a64::Emitter - AArch64 emitter (abstract). +//! +//! ### Supported Instructions +//! +//! - AArch64: +//! - Emitters: +//! - \ref a64::EmitterExplicitT - Provides all instructions that use explicit operands, provides also +//! utility functions. The member functions provided are part of all AArch64 emitters. +//! - Instruction representation: +//! - \ref a64::Inst::Id - instruction identifiers. +//! +//! ### Register Operands +//! +//! - \ref arm::Reg - Base class for any AArch32/AArch64 register. +//! - \ref arm::Gp - General purpose register: +//! - \ref arm::GpW - 32-bit register. +//! - \ref arm::GpX - 64-bit register. +//! - \ref arm::Vec - Vector (SIMD) register: +//! - \ref arm::VecB - 8-bit SIMD register (AArch64 only). +//! - \ref arm::VecH - 16-bit SIMD register (AArch64 only). +//! - \ref arm::VecS - 32-bit SIMD register. +//! - \ref arm::VecD - 64-bit SIMD register. +//! - \ref arm::VecV - 128-bit SIMD register. +//! +//! ### Memory Operands +//! +//! - \ref arm::Mem - AArch32/AArch64 memory operand that provides support for all ARM addressing features +//! including base, index, pre/post increment, and ARM-specific shift addressing and index extending. +//! +//! ### Other +//! +//! - \ref arm::Shift - Shift operation and value (both AArch32 and AArch64). +//! - \ref arm::DataType - Data type that is part of an instruction in AArch32 mode. +//! - \ref a64::Utils - Utilities that can help during code generation for AArch64. + +#include "./core.h" +#include "./arm/armglobals.h" +#include "./arm/armoperand.h" + +#endif // ASMJIT_ARM_H_INCLUDED diff --git a/lib/lepton/asmjit/arm/a64archtraits_p.h b/lib/lepton/asmjit/arm/a64archtraits_p.h new file mode 100644 index 0000000000..87559c71d5 --- /dev/null +++ b/lib/lepton/asmjit/arm/a64archtraits_p.h @@ -0,0 +1,81 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#ifndef ASMJIT_ARM_A64ARCHTRAITS_P_H_INCLUDED +#define ASMJIT_ARM_A64ARCHTRAITS_P_H_INCLUDED + +#include "../core/archtraits.h" +#include "../core/misc_p.h" +#include "../core/type.h" +#include "../arm/a64operand.h" + +ASMJIT_BEGIN_SUB_NAMESPACE(a64) + +//! \cond INTERNAL +//! \addtogroup asmjit_a64 +//! \{ + +static const constexpr ArchTraits a64ArchTraits = { + // SP/FP/LR/PC. + Gp::kIdSp, Gp::kIdFp, Gp::kIdLr, 0xFF, + + // Reserved. + { 0, 0, 0 }, + + // HW stack alignment (AArch64 requires stack aligned to 64 bytes). + 16, + + // Min/max stack offset - byte addressing is the worst, VecQ addressing the best. + 4095, 65520, + + // Instruction hints [Gp, Vec, ExtraVirt2, ExtraVirt3]. + {{ + InstHints::kPushPop, + InstHints::kPushPop, + InstHints::kNoHints, + InstHints::kNoHints + }}, + + // RegInfo. + #define V(index) OperandSignature{arm::RegTraits::kSignature} + {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }}, + #undef V + + // RegTypeToTypeId. + #define V(index) TypeId(arm::RegTraits::kTypeId) + {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }}, + #undef V + + // TypeIdToRegType. + #define V(index) (index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt8) ? RegType::kARM_GpW : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt8) ? RegType::kARM_GpW : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt16) ? RegType::kARM_GpW : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt16) ? RegType::kARM_GpW : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt32) ? RegType::kARM_GpW : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt32) ? RegType::kARM_GpW : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt64) ? RegType::kARM_GpX : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt64) ? RegType::kARM_GpX : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kIntPtr) ? RegType::kARM_GpX : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUIntPtr) ? RegType::kARM_GpX : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat32) ? RegType::kARM_VecS : \ + index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat64) ? RegType::kARM_VecD : RegType::kNone) + {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }}, + #undef V + + // Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities. + { + ArchTypeNameId::kByte, + ArchTypeNameId::kHWord, + ArchTypeNameId::kWord, + ArchTypeNameId::kXWord + } +}; + +//! \} +//! \endcond + +ASMJIT_END_SUB_NAMESPACE + +#endif // ASMJIT_ARM_A64ARCHTRAITS_P_H_INCLUDED diff --git a/lib/lepton/asmjit/arm/a64assembler.cpp b/lib/lepton/asmjit/arm/a64assembler.cpp new file mode 100644 index 0000000000..485f05f491 --- /dev/null +++ b/lib/lepton/asmjit/arm/a64assembler.cpp @@ -0,0 +1,5115 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#include "../core/api-build_p.h" +#if !defined(ASMJIT_NO_AARCH64) + +#include "../core/codewriter_p.h" +#include "../core/cpuinfo.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" +#include "../core/misc_p.h" +#include "../core/support.h" +#include "../arm/armformatter_p.h" +#include "../arm/a64assembler.h" +#include "../arm/a64emithelper_p.h" +#include "../arm/a64instdb_p.h" +#include "../arm/a64utils.h" + +ASMJIT_BEGIN_SUB_NAMESPACE(a64) + +// a64::Assembler - Cond +// ===================== + +static inline uint32_t condCodeToOpcodeCond(uint32_t cond) noexcept { + return (uint32_t(cond) - 2u) & 0xFu; +} + +// a64::Assembler - Bits +// ===================== + +template +static inline constexpr uint32_t B(const T& index) noexcept { return uint32_t(1u) << uint32_t(index); } + +static constexpr uint32_t kSP = Gp::kIdSp; +static constexpr uint32_t kZR = Gp::kIdZr; +static constexpr uint32_t kWX = InstDB::kWX; + +// a64::Assembler - ShiftOpToLdStOptMap +// ==================================== + +// Table that maps ShiftOp to OPT part in LD/ST (register) opcode. +#define VALUE(index) index == uint32_t(ShiftOp::kUXTW) ? 2u : \ + index == uint32_t(ShiftOp::kLSL) ? 3u : \ + index == uint32_t(ShiftOp::kSXTW) ? 6u : \ + index == uint32_t(ShiftOp::kSXTX) ? 7u : 0xFF +static const uint8_t armShiftOpToLdStOptMap[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) }; +#undef VALUE + +static inline constexpr uint32_t diff(RegType a, RegType b) noexcept { + return uint32_t(a) - uint32_t(b); +} + +// asmjit::a64::Assembler - SizeOp +// =============================== + +//! Struct that contains Size (2 bits), Q flag, and S (scalar) flag. These values +//! are used to encode Q, Size, and Scalar fields in an opcode. +struct SizeOp { + enum : uint8_t { + k128BitShift = 0, + kScalarShift = 1, + kSizeShift = 2, + + kQ = uint8_t(1u << k128BitShift), + kS = uint8_t(1u << kScalarShift), + + k00 = uint8_t(0 << kSizeShift), + k01 = uint8_t(1 << kSizeShift), + k10 = uint8_t(2 << kSizeShift), + k11 = uint8_t(3 << kSizeShift), + + k00Q = k00 | kQ, + k01Q = k01 | kQ, + k10Q = k10 | kQ, + k11Q = k11 | kQ, + + k00S = k00 | kS, + k01S = k01 | kS, + k10S = k10 | kS, + k11S = k11 | kS, + + kInvalid = 0xFFu, + + // Masks used by SizeOpMap. + kSzQ = (0x3u << kSizeShift) | kQ, + kSzS = (0x3u << kSizeShift) | kS, + kSzQS = (0x3u << kSizeShift) | kQ | kS + }; + + uint8_t value; + + inline bool isValid() const noexcept { return value != kInvalid; } + inline void makeInvalid() noexcept { value = kInvalid; } + + inline uint32_t q() const noexcept { return (value >> k128BitShift) & 0x1u; } + inline uint32_t qs() const noexcept { return ((value >> k128BitShift) | (value >> kScalarShift)) & 0x1u; } + inline uint32_t scalar() const noexcept { return (value >> kScalarShift) & 0x1u; } + inline uint32_t size() const noexcept { return (value >> kSizeShift) & 0x3u; } + + inline void decrementSize() noexcept { + ASMJIT_ASSERT(size() > 0); + value = uint8_t(value - (1u << kSizeShift)); + } +}; + +struct SizeOpTable { + enum TableId : uint8_t { + kTableBin = 0, + kTableAny, + kCount + }; + + // 40 elements for each combination. + SizeOp array[(uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB) + 1) * 8]; +}; + +#define VALUE_BIN(x) { \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k00 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k00Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00Q : SizeOp::kInvalid \ +} + +#define VALUE_ANY(x) { \ + x == (((uint32_t(RegType::kARM_VecB) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k00S : \ + x == (((uint32_t(RegType::kARM_VecH) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k01S : \ + x == (((uint32_t(RegType::kARM_VecS) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k10S : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k11S : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeH )) ? SizeOp::k01 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeH )) ? SizeOp::k01Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeS )) ? SizeOp::k10 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeS )) ? SizeOp::k10Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeD )) ? SizeOp::k11S : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeD )) ? SizeOp::k11Q : SizeOp::kInvalid \ +} + +static const SizeOpTable sizeOpTable[SizeOpTable::kCount] = { + {{ ASMJIT_LOOKUP_TABLE_40(VALUE_BIN, 0) }}, + {{ ASMJIT_LOOKUP_TABLE_40(VALUE_ANY, 0) }} +}; + +#undef VALUE_ANY +#undef VALUE_BIN + +struct SizeOpMap { + uint8_t tableId; + uint8_t sizeOpMask; + uint16_t acceptMask; +}; + +static const constexpr SizeOpMap sizeOpMap[InstDB::kVO_Count] = { + { // kVO_V_B: + SizeOpTable::kTableBin, SizeOp::kQ , uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q)) + }, + + { // kVO_V_BH: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k01) | B(SizeOp::k01Q)) + }, + + { // kVO_V_BH_4S: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k10Q)) + }, + + { // kVO_V_BHS: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k10) | B(SizeOp::k10Q)) + }, + + { // kVO_V_BHS_D2: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k10) | B(SizeOp::k10Q) | B(SizeOp::k11Q)) + }, + + { // kVO_V_HS: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k10) | B(SizeOp::k10Q)) + }, + + { // kVO_V_S: + SizeOpTable::kTableAny, SizeOp::kQ , uint16_t(B(SizeOp::k10) | B(SizeOp::k10Q)) + }, + + { // kVO_V_B8H4: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k01)) + }, + + { // kVO_V_B8H4S2: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k01) | B(SizeOp::k10)) + }, + + { // kVO_V_B8D1: + SizeOpTable::kTableAny, SizeOp::kSzQ , uint16_t(B(SizeOp::k00) | B(SizeOp::k11S)) + }, + + { // kVO_V_H4S2: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k01) | B(SizeOp::k10)) + }, + + { // kVO_V_B16: + SizeOpTable::kTableBin, SizeOp::kQ , uint16_t(B(SizeOp::k00Q)) + }, + + { // kVO_V_B16H8: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00Q) | B(SizeOp::k01Q)) + }, + + { // kVO_V_B16H8S4: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00Q) | B(SizeOp::k01Q) | B(SizeOp::k10Q)) + }, + + { // kVO_V_B16D2: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00Q) | B(SizeOp::k11Q)) + }, + + { // kVO_V_H8S4: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k01Q) | B(SizeOp::k10Q)) + }, + + { // kVO_V_S4: + SizeOpTable::kTableAny, 0 , uint16_t(B(SizeOp::k10Q)) + }, + + { // kVO_V_D2: + SizeOpTable::kTableAny, 0 , uint16_t(B(SizeOp::k11Q)) + }, + + { // kVO_SV_BHS: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k00S) | B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k01S) | B(SizeOp::k10) | B(SizeOp::k10Q) | B(SizeOp::k10S)) + }, + + { // kVO_SV_B8H4S2: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00S) | B(SizeOp::k01) | B(SizeOp::k01S) | B(SizeOp::k10) | B(SizeOp::k10S)) + }, + + { // kVO_SV_HS: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k01S) | B(SizeOp::k10) | B(SizeOp::k10Q) | B(SizeOp::k10S)) + }, + + { // kVO_V_Any: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k10) | B(SizeOp::k10Q) | B(SizeOp::k11S) | B(SizeOp::k11Q)) + }, + + { // kVO_SV_Any: + SizeOpTable::kTableAny, SizeOp::kSzQS, uint16_t(B(SizeOp::k00) | B(SizeOp::k00Q) | B(SizeOp::k00S) | + B(SizeOp::k01) | B(SizeOp::k01Q) | B(SizeOp::k01S) | + B(SizeOp::k10) | B(SizeOp::k10Q) | B(SizeOp::k10S) | + B(SizeOp::k11) | B(SizeOp::k11Q) | B(SizeOp::k11S)) + } +}; + +static const Operand_& significantSimdOp(const Operand_& o0, const Operand_& o1, uint32_t instFlags) noexcept { + return !(instFlags & InstDB::kInstFlagLong) ? o0 : o1; +} + +static inline SizeOp armElementTypeToSizeOp(uint32_t vecOpType, RegType regType, uint32_t elementType) noexcept { + // Instruction data or Assembler is wrong if this triggers an assertion failure. + ASMJIT_ASSERT(vecOpType < InstDB::kVO_Count); + // ElementType uses 3 bits in the operand signature, it should never overflow. + ASMJIT_ASSERT(elementType <= 0x7u); + + const SizeOpMap& map = sizeOpMap[vecOpType]; + const SizeOpTable& table = sizeOpTable[map.tableId]; + + size_t index = (Support::min(diff(regType, RegType::kARM_VecB), diff(RegType::kARM_VecV, RegType::kARM_VecB) + 1) << 3) | elementType; + SizeOp op = table.array[index]; + SizeOp modifiedOp { uint8_t(op.value & map.sizeOpMask) }; + + if (!Support::bitTest(map.acceptMask, op.value)) + modifiedOp.makeInvalid(); + + return modifiedOp; +} + +// a64::Assembler - Immediate Encoding Utilities (Integral) +// ======================================================== + +using Utils::LogicalImm; + +struct HalfWordImm { + uint32_t hw; + uint32_t inv; + uint32_t imm; +}; + +struct LMHImm { + uint32_t lm; + uint32_t h; + uint32_t maxRmId; +}; + +static inline uint32_t countZeroHalfWords64(uint64_t imm) noexcept { + return uint32_t((imm & 0x000000000000FFFFu) == 0) + + uint32_t((imm & 0x00000000FFFF0000u) == 0) + + uint32_t((imm & 0x0000FFFF00000000u) == 0) + + uint32_t((imm & 0xFFFF000000000000u) == 0) ; +} + +static uint32_t encodeMovSequence32(uint32_t out[2], uint32_t imm, uint32_t rd, uint32_t x) noexcept { + ASMJIT_ASSERT(rd <= 31); + + uint32_t kMovZ = 0b01010010100000000000000000000000 | (x << 31); + uint32_t kMovN = 0b00010010100000000000000000000000; + uint32_t kMovK = 0b01110010100000000000000000000000; + + if ((imm & 0xFFFF0000u) == 0x00000000u) { + out[0] = kMovZ | (0 << 21) | ((imm & 0xFFFFu) << 5) | rd; + return 1; + } + + if ((imm & 0xFFFF0000u) == 0xFFFF0000u) { + out[0] = kMovN | (0 << 21) | ((~imm & 0xFFFFu) << 5) | rd; + return 1; + } + + if ((imm & 0x0000FFFFu) == 0x00000000u) { + out[0] = kMovZ | (1 << 21) | ((imm >> 16) << 5) | rd; + return 1; + } + + if ((imm & 0x0000FFFFu) == 0x0000FFFFu) { + out[0] = kMovN | (1 << 21) | ((~imm >> 16) << 5) | rd; + return 1; + } + + out[0] = kMovZ | (0 << 21) | ((imm & 0xFFFFu) << 5) | rd; + out[1] = kMovK | (1 << 21) | ((imm >> 16) << 5) | rd; + return 2; +} + +static uint32_t encodeMovSequence64(uint32_t out[4], uint64_t imm, uint32_t rd, uint32_t x) noexcept { + ASMJIT_ASSERT(rd <= 31); + + uint32_t kMovZ = 0b11010010100000000000000000000000; + uint32_t kMovN = 0b10010010100000000000000000000000; + uint32_t kMovK = 0b11110010100000000000000000000000; + + if (imm <= 0xFFFFFFFFu) + return encodeMovSequence32(out, uint32_t(imm), rd, x); + + uint32_t zhw = countZeroHalfWords64( imm); + uint32_t ohw = countZeroHalfWords64(~imm); + + if (zhw >= ohw) { + uint32_t op = kMovZ; + uint32_t count = 0; + + for (uint32_t hwIndex = 0; hwIndex < 4; hwIndex++, imm >>= 16) { + uint32_t hwImm = uint32_t(imm & 0xFFFFu); + if (hwImm == 0) + continue; + + out[count++] = op | (hwIndex << 21) | (hwImm << 5) | rd; + op = kMovK; + } + + // This should not happen - zero should be handled by encodeMovSequence32(). + ASMJIT_ASSERT(count > 0); + + return count; + } + else { + uint32_t op = kMovN; + uint32_t count = 0; + uint32_t negMask = 0xFFFFu; + + for (uint32_t hwIndex = 0; hwIndex < 4; hwIndex++, imm >>= 16) { + uint32_t hwImm = uint32_t(imm & 0xFFFFu); + if (hwImm == 0xFFFFu) + continue; + + out[count++] = op | (hwIndex << 21) | ((hwImm ^ negMask) << 5) | rd; + op = kMovK; + negMask = 0; + } + + if (count == 0) { + out[count++] = kMovN | ((0xFFFF ^ negMask) << 5) | rd; + } + + return count; + } +} + +static inline bool encodeLMH(uint32_t sizeField, uint32_t elementIndex, LMHImm* out) noexcept { + if (sizeField != 1 && sizeField != 2) + return false; + + uint32_t hShift = 3u - sizeField; + uint32_t lmShift = sizeField - 1u; + uint32_t maxElementIndex = 15u >> sizeField; + + out->h = elementIndex >> hShift; + out->lm = (elementIndex << lmShift) & 0x3u; + out->maxRmId = (8u << sizeField) - 1; + + return elementIndex <= maxElementIndex; +} + +// [.......A|B.......|.......C|D.......|.......E|F.......|.......G|H.......] +static inline uint32_t encodeImm64ByteMaskToImm8(uint64_t imm) noexcept { + return uint32_t(((imm >> (7 - 0)) & 0b00000011) | // [.......G|H.......] + ((imm >> (23 - 2)) & 0b00001100) | // [.......E|F.......] + ((imm >> (39 - 4)) & 0b00110000) | // [.......C|D.......] + ((imm >> (55 - 6)) & 0b11000000)); // [.......A|B.......] +} + +// a64::Assembler - Opcode +// ======================= + +//! Helper class to store and manipulate ARM opcode. +struct Opcode { + uint32_t v; + + enum Bits : uint32_t { + kN = (1u << 22), + kQ = (1u << 30), + kX = (1u << 31) + }; + + // -------------------------------------------------------------------------- + // [Opcode Builder] + // -------------------------------------------------------------------------- + + inline uint32_t get() const noexcept { return v; } + inline void reset(uint32_t value) noexcept { v = value; } + + inline bool hasQ() const noexcept { return (v & kQ) != 0; } + inline bool hasX() const noexcept { return (v & kX) != 0; } + + template + inline Opcode& addImm(T value, uint32_t bitIndex) noexcept { return operator|=(uint32_t(value) << bitIndex); } + + template + inline Opcode& xorImm(T value, uint32_t bitIndex) noexcept { return operator^=(uint32_t(value) << bitIndex); } + + template + inline Opcode& addIf(T value, const Condition& condition) noexcept { return operator|=(condition ? uint32_t(value) : uint32_t(0)); } + + inline Opcode& addLogicalImm(const LogicalImm& logicalImm) noexcept { + addImm(logicalImm.n, 22); + addImm(logicalImm.r, 16); + addImm(logicalImm.s, 10); + return *this; + } + + inline Opcode& addReg(uint32_t id, uint32_t bitIndex) noexcept { return operator|=((id & 31u) << bitIndex); } + inline Opcode& addReg(const Operand_& op, uint32_t bitIndex) noexcept { return addReg(op.id(), bitIndex); } + + inline Opcode& operator=(uint32_t x) noexcept { v = x; return *this; } + inline Opcode& operator&=(uint32_t x) noexcept { v &= x; return *this; } + inline Opcode& operator|=(uint32_t x) noexcept { v |= x; return *this; } + inline Opcode& operator^=(uint32_t x) noexcept { v ^= x; return *this; } + + inline uint32_t operator&(uint32_t x) const noexcept { return v & x; } + inline uint32_t operator|(uint32_t x) const noexcept { return v | x; } + inline uint32_t operator^(uint32_t x) const noexcept { return v ^ x; } +}; + +// a64::Assembler - Signature Utilities +// ==================================== + +// TODO: [ARM] Deprecate matchSignature. +static inline bool matchSignature(const Operand_& o0, const Operand_& o1, uint32_t instFlags) noexcept { + if (!(instFlags & (InstDB::kInstFlagLong | InstDB::kInstFlagNarrow))) + return o0.signature() == o1.signature(); + + // TODO: [ARM] Something smart to validate this. + return true; +} + +static inline bool matchSignature(const Operand_& o0, const Operand_& o1, const Operand_& o2, uint32_t instFlags) noexcept { + return matchSignature(o0, o1, instFlags) && o1.signature() == o2.signature(); +} + +static inline bool matchSignature(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint32_t instFlags) noexcept { + return matchSignature(o0, o1, instFlags) && o1.signature() == o2.signature() && o2.signature() == o3.signature();; +} + +// Memory must be either: +// 1. Absolute address, which will be converted to relative. +// 2. Relative displacement (Label). +// 3. Base register + either offset or index. +static inline bool armCheckMemBaseIndexRel(const Mem& mem) noexcept { + // Allowed base types (Nothing, Label, and GpX). + constexpr uint32_t kBaseMask = B(0) | + B(RegType::kLabelTag) | + B(RegType::kARM_GpX); + + // Allowed index types (Nothing, GpW, and GpX). + constexpr uint32_t kIndexMask = B(0) | + B(RegType::kARM_GpW) | + B(RegType::kARM_GpX) ; + + RegType baseType = mem.baseType(); + RegType indexType = mem.indexType(); + + if (!Support::bitTest(kBaseMask, baseType)) + return false; + + if (baseType > RegType::kLabelTag) { + // Index allows either GpW or GpX. + if (!Support::bitTest(kIndexMask, indexType)) + return false; + + if (indexType == RegType::kNone) + return true; + else + return !mem.hasOffset(); + } + else { + // No index register allowed if this is a PC relative address (literal). + return indexType == RegType::kNone; + } +} + +struct EncodeFpOpcodeBits { + uint32_t sizeMask; + uint32_t mask[3]; +}; + +static inline bool pickFpOpcode(const Vec& reg, uint32_t sOp, uint32_t sHf, uint32_t vOp, uint32_t vHf, Opcode* opcode, uint32_t* szOut) noexcept { + static constexpr uint32_t kQBitIndex = 30; + + static const EncodeFpOpcodeBits szBits[InstDB::kHF_Count] = { + { B(2) | B(1) , { 0u , 0u, B(22) } }, + { B(2) | B(1) | B(0), { 0u , 0u, 0u } }, + { B(2) | B(1) | B(0), { B(23) | B(22) , 0u, B(22) } }, + { B(2) | B(1) | B(0), { B(22) | B(20) | B(19) , 0u, B(22) } }, + { B(2) | B(1) | B(0), { B(22) | B(21) | B(15) | B(14), 0u, B(22) } }, + { B(2) | B(1) | B(0), { B(23) , 0u, B(22) } } + }; + + if (!reg.hasElementType()) { + // Scalar operation [HSD]. + uint32_t sz = diff(reg.type(), RegType::kARM_VecH); + if (sz > 2u || !Support::bitTest(szBits[sHf].sizeMask, sz)) + return false; + + opcode->reset(szBits[sHf].mask[sz] ^ sOp); + *szOut = sz; + return sOp != 0; + } + else { + // Vector operation [HSD]. + uint32_t q = diff(reg.type(), RegType::kARM_VecD); + uint32_t sz = reg.elementType() - Vec::kElementTypeH; + + if (q > 1u || sz > 2u || !Support::bitTest(szBits[vHf].sizeMask, sz)) + return false; + + opcode->reset(szBits[vHf].mask[sz] ^ (vOp | (q << kQBitIndex))); + *szOut = sz; + return vOp != 0; + } +} + +static inline bool pickFpOpcode(const Vec& reg, uint32_t sOp, uint32_t sHf, uint32_t vOp, uint32_t vHf, Opcode* opcode) noexcept { + uint32_t sz; + return pickFpOpcode(reg, sOp, sHf, vOp, vHf, opcode, &sz); +} + +// a64::Assembler - Operand Checks +// =============================== + +// Checks whether all operands have the same signature. +static inline bool checkSignature(const Operand_& o0, const Operand_& o1) noexcept { + return o0.signature() == o1.signature(); +} + +static inline bool checkSignature(const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { + return o0.signature() == o1.signature() && + o1.signature() == o2.signature(); +} + +static inline bool checkSignature(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { + return o0.signature() == o1.signature() && + o1.signature() == o2.signature() && + o2.signature() == o3.signature(); +} + +// Checks whether the register is GP register of the allowed types. +// +// Allowed is a 2-bit mask, where the first bits allows GpW and the second bit +// allows GpX. These bits are usually stored within the instruction, but could +// be also hardcoded in the assembler for instructions where GP types are not +// selectable. +static inline bool checkGpType(const Operand_& op, uint32_t allowed) noexcept { + RegType type = op.as().type(); + return Support::bitTest(allowed << uint32_t(RegType::kARM_GpW), type); +} + +static inline bool checkGpType(const Operand_& op, uint32_t allowed, uint32_t* x) noexcept { + // NOTE: We set 'x' to one only when GpW is allowed, otherwise the X is part + // of the opcode and we cannot set it. This is why this works without requiring + // additional logic. + RegType type = op.as().type(); + *x = diff(type, RegType::kARM_GpW) & allowed; + return Support::bitTest(allowed << uint32_t(RegType::kARM_GpW), type); +} + +static inline bool checkGpType(const Operand_& o0, const Operand_& o1, uint32_t allowed, uint32_t* x) noexcept { + return checkGpType(o0, allowed, x) && checkSignature(o0, o1); +} + +static inline bool checkGpType(const Operand_& o0, const Operand_& o1, const Operand_& o2, uint32_t allowed, uint32_t* x) noexcept { + return checkGpType(o0, allowed, x) && checkSignature(o0, o1, o2); +} + +static inline bool checkGpId(const Operand_& op, uint32_t hiId = kZR) noexcept { + uint32_t id = op.as().id(); + return id < 31u || id == hiId; +} + +static inline bool checkGpId(const Operand_& o0, const Operand_& o1, uint32_t hiId = kZR) noexcept { + uint32_t id0 = o0.as().id(); + uint32_t id1 = o1.as().id(); + + return (id0 < 31u || id0 == hiId) && (id1 < 31u || id1 == hiId); +} + +static inline bool checkGpId(const Operand_& o0, const Operand_& o1, const Operand_& o2, uint32_t hiId = kZR) noexcept { + uint32_t id0 = o0.as().id(); + uint32_t id1 = o1.as().id(); + uint32_t id2 = o2.as().id(); + + return (id0 < 31u || id0 == hiId) && (id1 < 31u || id1 == hiId) && (id2 < 31u || id2 == hiId); +} + +static inline bool checkVecId(const Operand_& op) noexcept { + uint32_t id = op.as().id(); + return id <= 31u; +} + +static inline bool checkVecId(const Operand_& o0, const Operand_& o1) noexcept { + uint32_t id0 = o0.as().id(); + uint32_t id1 = o1.as().id(); + + return (id0 | id1) <= 31u; +} + +/* Unused at the moment. +static inline bool checkVecId(const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { + uint32_t id0 = o0.as().id(); + uint32_t id1 = o1.as().id(); + uint32_t id2 = o2.as().id(); + + return (id0 | id1 | id2) <= 31u; +} + +static inline bool checkVecId(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { + uint32_t id0 = o0.as().id(); + uint32_t id1 = o1.as().id(); + uint32_t id2 = o2.as().id(); + uint32_t id3 = o3.as().id(); + + return (id0 | id1 | id2 | id3) <= 31u; +} +*/ + +static inline bool checkMemBase(const Mem& mem) noexcept { + return mem.baseType() == RegType::kARM_GpX && mem.baseId() <= 31; +} + +static inline bool checkEven(const Operand_& o0, const Operand_& o1) noexcept { + return ((o0.id() | o1.id()) & 1) == 0; +} + +static inline bool checkConsecutive(const Operand_& o0, const Operand_& o1) noexcept { + return ((o0.id() + 1u) & 0x1Fu) == o1.id(); +} + +static inline bool checkConsecutive(const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { + return ((o0.id() + 1u) & 0x1Fu) == o1.id() && + ((o0.id() + 2u) & 0x1Fu) == o2.id(); +} + +static inline bool checkConsecutive(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { + return ((o0.id() + 1u) & 0x1Fu) == o1.id() && + ((o0.id() + 2u) & 0x1Fu) == o2.id() && + ((o0.id() + 3u) & 0x1Fu) == o3.id(); +} + +// a64::Assembler - CheckReg +// ========================= + +#define V(index) (index == uint32_t(RegType::kARM_GpW) ? Gp::kIdZr : \ + index == uint32_t(RegType::kARM_GpX) ? Gp::kIdZr : \ + index == uint32_t(RegType::kARM_VecB) ? 31u : \ + index == uint32_t(RegType::kARM_VecH) ? 31u : \ + index == uint32_t(RegType::kARM_VecS) ? 31u : \ + index == uint32_t(RegType::kARM_VecD) ? 31u : \ + index == uint32_t(RegType::kARM_VecV) ? 31u : 0) +static const Support::Array commonHiRegIdOfType = {{ + ASMJIT_LOOKUP_TABLE_32(V, 0) +}}; +#undef V + +static inline bool checkValidRegs(const Operand_& o0) noexcept { + return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])); +} + +static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1) noexcept { + return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])) & + ((o1.id() < 31) | (o1.id() == commonHiRegIdOfType[o1.as().type()])) ; +} + +static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { + return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])) & + ((o1.id() < 31) | (o1.id() == commonHiRegIdOfType[o1.as().type()])) & + ((o2.id() < 31) | (o2.id() == commonHiRegIdOfType[o2.as().type()])) ; +} + +static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { + return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])) & + ((o1.id() < 31) | (o1.id() == commonHiRegIdOfType[o1.as().type()])) & + ((o2.id() < 31) | (o2.id() == commonHiRegIdOfType[o2.as().type()])) & + ((o3.id() < 31) | (o3.id() == commonHiRegIdOfType[o3.as().type()])) ; +} + +// a64::Assembler - Construction & Destruction +// =========================================== + +Assembler::Assembler(CodeHolder* code) noexcept : BaseAssembler() { + _archMask = uint64_t(1) << uint32_t(Arch::kAArch64); + assignEmitterFuncs(this); + + if (code) + code->attach(this); +} + +Assembler::~Assembler() noexcept {} + +// a64::Assembler - Emit +// ===================== + +#define ENC_OPS1(OP0) \ + (uint32_t(OperandType::k##OP0)) + +#define ENC_OPS2(OP0, OP1) \ + (uint32_t(OperandType::k##OP0) + \ + (uint32_t(OperandType::k##OP1) << 3)) + +#define ENC_OPS3(OP0, OP1, OP2) \ + (uint32_t(OperandType::k##OP0) + \ + (uint32_t(OperandType::k##OP1) << 3) + \ + (uint32_t(OperandType::k##OP2) << 6)) + +#define ENC_OPS4(OP0, OP1, OP2, OP3) \ + (uint32_t(OperandType::k##OP0) + \ + (uint32_t(OperandType::k##OP1) << 3) + \ + (uint32_t(OperandType::k##OP2) << 6) + \ + (uint32_t(OperandType::k##OP3) << 9)) + +Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + // Logging/Validation/Error. + constexpr InstOptions kRequiresSpecialHandling = InstOptions::kReserved; + + Error err; + CodeWriter writer(this); + + // Combine all instruction options and also check whether the instruction + // is valid. All options that require special handling (including invalid + // instruction) are handled by the next branch. + InstOptions options = InstOptions(instId - 1 >= Inst::_kIdCount - 1) | InstOptions((size_t)(_bufferEnd - writer.cursor()) < 4) | instOptions() | forcedInstOptions(); + + CondCode instCC = BaseInst::extractARMCondCode(instId); + instId = instId & uint32_t(InstIdParts::kRealId); + + if (instId >= Inst::_kIdCount) + instId = 0; + + const InstDB::InstInfo* instInfo = &InstDB::_instInfoTable[instId]; + uint32_t encodingIndex = instInfo->_encodingDataIndex; + + Opcode opcode; + uint32_t isign4; + uint32_t instFlags; + + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_* rmRel = nullptr; + + uint32_t multipleOpData[4]; + uint32_t multipleOpCount; + + // These are only used when instruction uses a relative displacement. + OffsetFormat offsetFormat; // Offset format. + uint64_t offsetValue; // Offset value (if known). + + if (ASMJIT_UNLIKELY(Support::test(options, kRequiresSpecialHandling))) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + + // Unknown instruction. + if (ASMJIT_UNLIKELY(instId == 0)) + goto InvalidInstruction; + + // Condition code can only be used with 'B' instruction. + if (ASMJIT_UNLIKELY(instCC != CondCode::kAL && instId != Inst::kIdB)) + goto InvalidInstruction; + + // Grow request, happens rarely. + err = writer.ensureSpace(this, 4); + if (ASMJIT_UNLIKELY(err)) + goto Failed; + +#ifndef ASMJIT_NO_VALIDATION + // Strict validation. + if (hasDiagnosticOption(DiagnosticOptions::kValidateAssembler)) { + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone); + if (ASMJIT_UNLIKELY(err)) + goto Failed; + } +#endif + } + + // Signature of the first 4 operands. + isign4 = (uint32_t(o0.opType()) ) + + (uint32_t(o1.opType()) << 3) + + (uint32_t(o2.opType()) << 6) + + (uint32_t(o3.opType()) << 9); + instFlags = instInfo->flags(); + + switch (instInfo->_encoding) { + // ------------------------------------------------------------------------ + // [Base - Universal] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseOp: { + const InstDB::EncodingData::BaseOp& opData = InstDB::EncodingData::baseOp[encodingIndex]; + + if (isign4 == 0) { + opcode.reset(opData.opcode); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseOpImm: { + const InstDB::EncodingData::BaseOpImm& opData = InstDB::EncodingData::baseOpImm[encodingIndex]; + + if (isign4 == ENC_OPS1(Imm)) { + uint64_t imm = o0.as().valueAs(); + uint32_t immMax = 1u << opData.immBits; + + if (imm >= immMax) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(imm, opData.immOffset); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseR: { + const InstDB::EncodingData::BaseR& opData = InstDB::EncodingData::baseR[encodingIndex]; + + if (isign4 == ENC_OPS1(Reg)) { + if (!checkGpType(o0, opData.rType)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.rHiId)) + goto InvalidPhysId; + + opcode.reset(opData.opcode); + opcode.addReg(o0, opData.rShift); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseRR: { + const InstDB::EncodingData::BaseRR& opData = InstDB::EncodingData::baseRR[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + uint32_t x; + if (!checkGpType(o0, opData.aType, &x)) + goto InvalidInstruction; + + if (!checkGpType(o1, opData.bType)) + goto InvalidInstruction; + + if (opData.uniform && !checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.aHiId)) + goto InvalidPhysId; + + if (!checkGpId(o1, opData.bHiId)) + goto InvalidPhysId; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addReg(o1, opData.bShift); + opcode.addReg(o0, opData.aShift); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseRRR: { + const InstDB::EncodingData::BaseRRR& opData = InstDB::EncodingData::baseRRR[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + uint32_t x; + if (!checkGpType(o0, opData.aType, &x)) + goto InvalidInstruction; + + if (!checkGpType(o1, opData.bType)) + goto InvalidInstruction; + + if (!checkGpType(o2, opData.cType)) + goto InvalidInstruction; + + if (opData.uniform && !checkSignature(o0, o1, o2)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.aHiId)) + goto InvalidPhysId; + + if (!checkGpId(o1, opData.bHiId)) + goto InvalidPhysId; + + if (!checkGpId(o2, opData.cHiId)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, 31); + opcode.addReg(o2, 16); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseRRRR: { + const InstDB::EncodingData::BaseRRRR& opData = InstDB::EncodingData::baseRRRR[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { + uint32_t x; + if (!checkGpType(o0, opData.aType, &x)) + goto InvalidInstruction; + + if (!checkGpType(o1, opData.bType)) + goto InvalidInstruction; + + if (!checkGpType(o2, opData.cType)) + goto InvalidInstruction; + + if (!checkGpType(o3, opData.dType)) + goto InvalidInstruction; + + if (opData.uniform && !checkSignature(o0, o1, o2, o3)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.aHiId)) + goto InvalidPhysId; + + if (!checkGpId(o1, opData.bHiId)) + goto InvalidPhysId; + + if (!checkGpId(o2, opData.cHiId)) + goto InvalidPhysId; + + if (!checkGpId(o3, opData.dHiId)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, 31); + opcode.addReg(o2, 16); + opcode.addReg(o3, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseRRII: { + const InstDB::EncodingData::BaseRRII& opData = InstDB::EncodingData::baseRRII[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + if (!checkGpType(o0, opData.aType)) + goto InvalidInstruction; + + if (!checkGpType(o1, opData.bType)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.aHiId)) + goto InvalidPhysId; + + if (!checkGpId(o1, opData.bHiId)) + goto InvalidPhysId; + + if (o2.as().valueAs() >= Support::bitMask(opData.aImmSize + opData.aImmDiscardLsb) || + o3.as().valueAs() >= Support::bitMask(opData.bImmSize + opData.bImmDiscardLsb)) + goto InvalidImmediate; + + uint32_t aImm = o2.as().valueAs() >> opData.aImmDiscardLsb; + uint32_t bImm = o3.as().valueAs() >> opData.bImmDiscardLsb; + + if ((aImm << opData.aImmDiscardLsb) != o2.as().valueAs() || + (bImm << opData.bImmDiscardLsb) != o3.as().valueAs()) + goto InvalidImmediate; + + opcode.reset(opData.opcode()); + opcode.addImm(aImm, opData.aImmOffset); + opcode.addImm(bImm, opData.bImmOffset); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Mov] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseMov: { + // MOV is a pseudo instruction that uses various instructions depending on its signature. + uint32_t x = diff(o0.as().type(), RegType::kARM_GpW); + if (x > 1) + goto InvalidInstruction; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (!o0.as().isGp()) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + bool hasSP = o0.as().isSP() || o1.as().isSP(); + if (hasSP) { + // Cannot be combined with ZR. + if (!checkGpId(o0, o1, kSP)) + goto InvalidPhysId; + + // MOV Rd, Rm -> ADD Rd, Rn, #0. + opcode.reset(0b00010001000000000000000000000000); + opcode.addImm(x, 31); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + else { + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + // MOV Rd, Rm -> ORR Rd, , Rm. + opcode.reset(0b00101010000000000000001111100000); + opcode.addImm(x, 31); + opcode.addReg(o1, 16); + opcode.addReg(o0, 0); + goto EmitOp; + } + } + + if (isign4 == ENC_OPS2(Reg, Imm)) { + if (!o0.as().isGp()) + goto InvalidInstruction; + + uint64_t immValue = o1.as().valueAs(); + if (!x) + immValue &= 0xFFFFFFFFu; + + // Prefer a single MOVN/MOVZ instruction over a logical instruction. + multipleOpCount = encodeMovSequence64(multipleOpData, immValue, o0.id() & 31, x); + if (multipleOpCount == 1 && !o0.as().isSP()) { + opcode.reset(multipleOpData[0]); + goto EmitOp; + } + + // Logical instructions use 13-bit immediate pattern encoded as N:ImmR:ImmS. + LogicalImm logicalImm; + if (!o0.as().isZR()) { + if (Utils::encodeLogicalImm(immValue, x ? 64 : 32, &logicalImm)) { + if (!checkGpId(o0, kSP)) + goto InvalidPhysId; + + opcode.reset(0b00110010000000000000001111100000); + opcode.addImm(x, 31); + opcode.addLogicalImm(logicalImm); + opcode.addReg(o0, 0); + goto EmitOp; + } + } + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + goto EmitOp_Multiple; + } + + break; + } + + case InstDB::kEncodingBaseMovKNZ: { + const InstDB::EncodingData::BaseMovKNZ& opData = InstDB::EncodingData::baseMovKNZ[encodingIndex]; + + uint32_t x = diff(o0.as().type(), RegType::kARM_GpW); + if (x > 1) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + + if (isign4 == ENC_OPS2(Reg, Imm)) { + uint64_t imm16 = o1.as().valueAs(); + if (imm16 > 0xFFFFu) + goto InvalidImmediate; + + opcode.addImm(imm16, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + if (isign4 == ENC_OPS3(Reg, Imm, Imm)) { + uint64_t imm16 = o1.as().valueAs(); + uint32_t shiftType = o2.as().predicate(); + uint64_t shiftValue = o2.as().valueAs(); + + if (imm16 > 0xFFFFu || shiftValue > 48 || shiftType != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + // Convert shift value to 'hw' field. + uint32_t hw = uint32_t(shiftValue) >> 4; + if ((hw << 4) != uint32_t(shiftValue)) + goto InvalidImmediate; + + opcode.addImm(hw, 21); + opcode.addImm(imm16, 5); + opcode.addReg(o0, 0); + + if (!x && hw > 1u) + goto InvalidImmediate; + + goto EmitOp; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Adr] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseAdr: { + const InstDB::EncodingData::BaseAdr& opData = InstDB::EncodingData::baseAdr[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Label) || isign4 == ENC_OPS2(Reg, Imm)) { + if (!o0.as().isGpX()) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addReg(o0, 0); + offsetFormat.resetToImmValue(opData.offsetType, 4, 5, 21, 0); + + if (instId == Inst::kIdAdrp) + offsetFormat._immDiscardLsb = 12; + + rmRel = &o1; + goto EmitOp_Rel; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Arithmetic and Logical] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseAddSub: { + const InstDB::EncodingData::BaseAddSub& opData = InstDB::EncodingData::baseAddSub[encodingIndex]; + + uint32_t x; + if (!checkGpType(o0, o1, kWX, &x)) + goto InvalidInstruction; + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) || isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + opcode.reset(uint32_t(opData.immediateOp) << 24); + + // ADD | SUB (immediate) - ZR is not allowed. + // ADDS|SUBS (immediate) - ZR allowed in Rd, SP allowed in Rn. + uint32_t aHiId = opcode.get() & B(29) ? kZR : kSP; + uint32_t bHiId = kSP; + + if (!checkGpId(o0, aHiId) || !checkGpId(o1, bHiId)) + goto InvalidPhysId; + + // ADD|SUB (immediate) use 12-bit immediate optionally shifted by 'LSL #12'. + uint64_t imm = o2.as().valueAs(); + uint32_t shift = 0; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + if (o3.as().predicate() != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + if (o3.as().value() != 0 && o3.as().value() != 12) + goto InvalidImmediate; + + shift = uint32_t(o3.as().value() != 0); + } + + // Accept immediate value of '0x00XXX000' by setting 'shift' to 12. + if (imm > 0xFFFu) { + if (shift || (imm & ~uint64_t(0xFFFu << 12)) != 0) + goto InvalidImmediate; + shift = 1; + imm >>= 12; + } + + opcode.addImm(x, 31); + opcode.addImm(shift, 22); + opcode.addImm(imm, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Reg) || isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + if (!checkSignature(o1, o2)) + goto InvalidInstruction; + + uint32_t opSize = x ? 64 : 32; + uint64_t shift = 0; + uint32_t sType = uint32_t(ShiftOp::kLSL); + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + sType = o3.as().predicate(); + shift = o3.as().valueAs(); + } + + if (!checkGpId(o2, kZR)) + goto InvalidPhysId; + + // Shift operation - LSL, LSR, ASR. + if (sType <= uint32_t(ShiftOp::kASR)) { + bool hasSP = o0.as().isSP() || o1.as().isSP(); + if (!hasSP) { + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + if (shift >= opSize) + goto InvalidImmediate; + + opcode.reset(uint32_t(opData.shiftedOp) << 21); + opcode.addImm(x, 31); + opcode.addImm(sType, 22); + opcode.addReg(o2, 16); + opcode.addImm(shift, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + // SP register can only be used with LSL or Extend. + if (sType != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + sType = x ? uint32_t(ShiftOp::kUXTX) : uint32_t(ShiftOp::kUXTW); + } + + // Extend operation - UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX. + opcode.reset(uint32_t(opData.extendedOp) << 21); + sType -= uint32_t(ShiftOp::kUXTB); + + if (sType > 7 || shift > 4) + goto InvalidImmediate; + + if (!(opcode.get() & B(29))) { + // ADD|SUB (extend) - ZR is not allowed. + if (!checkGpId(o0, o1, kSP)) + goto InvalidPhysId; + } + else { + // ADDS|SUBS (extend) - ZR allowed in Rd, SP allowed in Rn. + if (!checkGpId(o0, kZR) || !checkGpId(o1, kSP)) + goto InvalidPhysId; + } + + opcode.addImm(x, 31); + opcode.addReg(o2, 16); + opcode.addImm(sType, 13); + opcode.addImm(shift, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseLogical: { + const InstDB::EncodingData::BaseLogical& opData = InstDB::EncodingData::baseLogical[encodingIndex]; + + uint32_t x; + if (!checkGpType(o0, o1, kWX, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + uint32_t opSize = x ? 64 : 32; + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) && opData.immediateOp != 0) { + opcode.reset(uint32_t(opData.immediateOp) << 23); + + // AND|ANDS|BIC|BICS|ORR|EOR (immediate) uses a LogicalImm format described by N:R:S values. + uint64_t immMask = Support::lsbMask(opSize); + uint64_t immValue = o2.as().valueAs(); + + if (opData.negateImm) + immValue ^= immMask; + + // Logical instructions use 13-bit immediate pattern encoded as N:ImmS:ImmR. + LogicalImm logicalImm; + if (!Utils::encodeLogicalImm(immValue & immMask, opSize, &logicalImm)) + goto InvalidImmediate; + + // AND|BIC|ORR|EOR (immediate) can have SP on destination, but ANDS|BICS (immediate) cannot. + uint32_t kOpANDS = 0x3 << 29; + bool isANDS = (opcode.get() & kOpANDS) == kOpANDS; + + if (!checkGpId(o0, isANDS ? kZR : kSP) || !checkGpId(o1, kZR)) + goto InvalidPhysId; + + opcode.addImm(x, 31); + opcode.addLogicalImm(logicalImm); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + if (!checkSignature(o1, o2)) + goto InvalidInstruction; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!checkGpId(o0, o1, o2, kZR)) + goto InvalidPhysId; + + opcode.reset(uint32_t(opData.shiftedOp) << 21); + opcode.addImm(x, 31); + opcode.addReg(o2, 16); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + if (!checkGpId(o0, o1, o2, kZR)) + goto InvalidPhysId; + + uint32_t shiftType = o3.as().predicate(); + uint64_t opShift = o3.as().valueAs(); + + if (shiftType > 0x3 || opShift >= opSize) + goto InvalidImmediate; + + opcode.reset(uint32_t(opData.shiftedOp) << 21); + opcode.addImm(x, 31); + opcode.addImm(shiftType, 22); + opcode.addReg(o2, 16); + opcode.addImm(opShift, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseCmpCmn: { + const InstDB::EncodingData::BaseCmpCmn& opData = InstDB::EncodingData::baseCmpCmn[encodingIndex]; + + uint32_t x; + if (!checkGpType(o0, kWX, &x)) + goto InvalidInstruction; + + if (isign4 == ENC_OPS2(Reg, Imm)) { + // CMN|CMP (immediate) - ZR is not allowed. + if (!checkGpId(o0, kSP)) + goto InvalidPhysId; + + // CMN|CMP (immediate) use 12-bit immediate optionally shifted by 'LSL #12'. + const Imm& imm12 = o1.as(); + uint32_t immShift = 0; + uint64_t immValue = imm12.valueAs(); + + if (immValue > 0xFFFu) { + if ((immValue & ~uint64_t(0xFFFu << 12)) != 0) + goto InvalidImmediate; + immShift = 1; + immValue >>= 12; + } + + opcode.reset(uint32_t(opData.immediateOp) << 24); + opcode.addImm(x, 31); + opcode.addImm(immShift, 22); + opcode.addImm(immValue, 10); + opcode.addReg(o0, 5); + opcode.addReg(Gp::kIdZr, 0); + goto EmitOp; + } + + if (isign4 == ENC_OPS2(Reg, Reg) || isign4 == ENC_OPS3(Reg, Reg, Imm)) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + uint32_t opSize = x ? 64 : 32; + uint32_t sType = 0; + uint64_t shift = 0; + + if (isign4 == ENC_OPS3(Reg, Reg, Imm)) { + sType = o2.as().predicate(); + shift = o2.as().valueAs(); + } + + bool hasSP = o0.as().isSP() || o1.as().isSP(); + + // Shift operation - LSL, LSR, ASR. + if (sType <= uint32_t(ShiftOp::kASR)) { + if (!hasSP) { + if (shift >= opSize) + goto InvalidImmediate; + + opcode.reset(uint32_t(opData.shiftedOp) << 21); + opcode.addImm(x, 31); + opcode.addImm(sType, 22); + opcode.addReg(o1, 16); + opcode.addImm(shift, 10); + opcode.addReg(o0, 5); + opcode.addReg(Gp::kIdZr, 0); + goto EmitOp; + } + + // SP register can only be used with LSL or Extend. + if (sType != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + sType = x ? uint32_t(ShiftOp::kUXTX) : uint32_t(ShiftOp::kUXTW); + } + + // Extend operation - UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX. + sType -= uint32_t(ShiftOp::kUXTB); + if (sType > 7 || shift > 4) + goto InvalidImmediate; + + opcode.reset(uint32_t(opData.extendedOp) << 21); + opcode.addImm(x, 31); + opcode.addReg(o1, 16); + opcode.addImm(sType, 13); + opcode.addImm(shift, 10); + opcode.addReg(o0, 5); + opcode.addReg(Gp::kIdZr, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseMvnNeg: { + const InstDB::EncodingData::BaseMvnNeg& opData = InstDB::EncodingData::baseMvnNeg[encodingIndex]; + + uint32_t x; + if (!checkGpType(o0, o1, kWX, &x)) + goto InvalidInstruction; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addReg(o1, 16); + opcode.addReg(o0, 0); + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + goto EmitOp; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Imm)) { + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + uint32_t opSize = x ? 64 : 32; + uint32_t shiftType = o2.as().predicate(); + uint64_t opShift = o2.as().valueAs(); + + if (shiftType > uint32_t(ShiftOp::kROR) || opShift >= opSize) + goto InvalidImmediate; + + opcode.addImm(shiftType, 22); + opcode.addImm(opShift, 10); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseTst: { + const InstDB::EncodingData::BaseTst& opData = InstDB::EncodingData::baseTst[encodingIndex]; + + uint32_t x; + if (!checkGpType(o0, kWX, &x)) + goto InvalidInstruction; + + uint32_t opSize = x ? 64 : 32; + + if (isign4 == ENC_OPS2(Reg, Imm) && opData.immediateOp != 0) { + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + // TST (immediate) uses a LogicalImm format described by N:R:S values. + uint64_t immMask = Support::lsbMask(opSize); + uint64_t immValue = o1.as().valueAs(); + + // Logical instructions use 13-bit immediate pattern encoded as N:ImmS:ImmR. + LogicalImm logicalImm; + if (!Utils::encodeLogicalImm(immValue & immMask, opSize, &logicalImm)) + goto InvalidImmediate; + + opcode.reset(uint32_t(opData.immediateOp) << 22); + opcode.addLogicalImm(logicalImm); + opcode.addImm(x, 31); + opcode.addReg(o0, 5); + opcode.addReg(Gp::kIdZr, 0); + goto EmitOp; + } + + opcode.reset(uint32_t(opData.shiftedOp) << 21); + opcode.addImm(x, 31); + opcode.addReg(o1, 16); + opcode.addReg(o0, 5); + opcode.addReg(Gp::kIdZr, 0); + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + goto EmitOp; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Imm)) { + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + uint32_t shiftType = o2.as().predicate(); + uint64_t opShift = o2.as().valueAs(); + + if (shiftType > 0x3 || opShift >= opSize) + goto InvalidImmediate; + + opcode.addImm(shiftType, 22); + opcode.addImm(opShift, 10); + goto EmitOp; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Bit Manipulation] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseBfc: { + const InstDB::EncodingData::BaseBfc& opData = InstDB::EncodingData::baseBfc[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Imm, Imm)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0)) + goto InvalidPhysId; + + uint64_t lsb = o1.as().valueAs(); + uint64_t width = o2.as().valueAs(); + uint32_t opSize = x ? 64 : 32; + + if (lsb >= opSize || width == 0 || width > opSize) + goto InvalidImmediate; + + uint32_t lsb32 = Support::neg(uint32_t(lsb)) & (opSize - 1); + uint32_t width32 = uint32_t(width) - 1; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addImm(lsb32, 16); + opcode.addImm(width32, 10); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseBfi: { + const InstDB::EncodingData::BaseBfi& opData = InstDB::EncodingData::baseBfi[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1)) + goto InvalidPhysId; + + uint64_t lsb = o2.as().valueAs(); + uint64_t width = o3.as().valueAs(); + uint32_t opSize = x ? 64 : 32; + + if (lsb >= opSize || width == 0 || width > opSize) + goto InvalidImmediate; + + uint32_t lImm = Support::neg(uint32_t(lsb)) & (opSize - 1); + uint32_t wImm = uint32_t(width) - 1; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addImm(lImm, 16); + opcode.addImm(wImm, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseBfm: { + const InstDB::EncodingData::BaseBfm& opData = InstDB::EncodingData::baseBfm[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1)) + goto InvalidPhysId; + + uint64_t immR = o2.as().valueAs(); + uint64_t immS = o3.as().valueAs(); + uint32_t opSize = x ? 64 : 32; + + if ((immR | immS) >= opSize) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addImm(immR, 16); + opcode.addImm(immS, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseBfx: { + const InstDB::EncodingData::BaseBfx& opData = InstDB::EncodingData::baseBfx[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1)) + goto InvalidPhysId; + + uint64_t lsb = o2.as().valueAs(); + uint64_t width = o3.as().valueAs(); + uint32_t opSize = x ? 64 : 32; + + if (lsb >= opSize || width == 0 || width > opSize) + goto InvalidImmediate; + + uint32_t lsb32 = uint32_t(lsb); + uint32_t width32 = lsb32 + uint32_t(width) - 1u; + + if (width32 >= opSize) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addImm(lsb32, 16); + opcode.addImm(width32, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseExtend: { + const InstDB::EncodingData::BaseExtend& opData = InstDB::EncodingData::baseExtend[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + uint32_t x; + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!o1.as().isGpW()) + goto InvalidInstruction; + + if (!checkGpId(o0, o1)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseExtract: { + const InstDB::EncodingData::BaseExtract& opData = InstDB::EncodingData::baseExtract[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + uint32_t x; + if (!checkGpType(o0, kWX, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1, o2)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, o2)) + goto InvalidPhysId; + + uint64_t lsb = o3.as().valueAs(); + uint32_t opSize = x ? 64 : 32; + + if (lsb >= opSize) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addReg(o2, 16); + opcode.addImm(lsb, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseRev: { + if (isign4 == ENC_OPS2(Reg, Reg)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1)) + goto InvalidPhysId; + + opcode.reset(0b01011010110000000000100000000000); + opcode.addImm(x, 31); + opcode.addImm(x, 10); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseShift: { + const InstDB::EncodingData::BaseShift& opData = InstDB::EncodingData::baseShift[encodingIndex]; + + uint32_t x; + if (!checkGpType(o0, kWX, &x)) + goto InvalidInstruction; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!checkSignature(o0, o1, o2)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, o2, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.registerOp()); + opcode.addImm(x, 31); + opcode.addReg(o2, 16); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) && opData.immediateOp()) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + uint64_t immR = o2.as().valueAs(); + uint32_t opSize = x ? 64 : 32; + + if (immR >= opSize) + goto InvalidImmediate; + + opcode.reset(opData.immediateOp()); + opcode.addImm(x, 31); + opcode.addImm(x, 22); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + + if (opcode.get() & B(10)) { + // ASR and LSR (immediate) has the same logic. + opcode.addImm(x, 15); + opcode.addImm(immR, 16); + goto EmitOp; + } + + if (opData.ror == 0) { + // LSL (immediate) is an alias to UBFM + uint32_t ubfmImmR = Support::neg(uint32_t(immR)) & (opSize - 1); + uint32_t ubfmImmS = opSize - 1 - uint32_t(immR); + + opcode.addImm(ubfmImmR, 16); + opcode.addImm(ubfmImmS, 10); + goto EmitOp; + } + else { + // ROR (immediate) is an alias to EXTR. + opcode.addImm(immR, 10); + opcode.addReg(o1, 16); + goto EmitOp; + } + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Conditionals] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseCCmp: { + const InstDB::EncodingData::BaseCCmp& opData = InstDB::EncodingData::baseCCmp[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm) || isign4 == ENC_OPS4(Reg, Imm, Imm, Imm)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + uint64_t nzcv = o2.as().valueAs(); + uint64_t cond = o3.as().valueAs(); + + if ((nzcv | cond) > 0xFu) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(condCodeToOpcodeCond(uint32_t(cond)), 12); + opcode.addImm(nzcv, 0); + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + // CCMN|CCMP (register) form. + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o1, kZR)) + goto InvalidPhysId; + + opcode.addReg(o1, 16); + opcode.addReg(o0, 5); + goto EmitOp; + } + else { + // CCMN|CCMP (immediate) form. + uint64_t imm5 = o1.as().valueAs(); + if (imm5 > 0x1F) + goto InvalidImmediate; + + opcode.addImm(1, 11); + opcode.addImm(imm5, 16); + opcode.addReg(o0, 5); + goto EmitOp; + } + } + + break; + } + + case InstDB::kEncodingBaseCInc: { + const InstDB::EncodingData::BaseCInc& opData = InstDB::EncodingData::baseCInc[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Imm)) { + uint32_t x; + if (!checkGpType(o0, o1, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + uint64_t cond = o2.as().valueAs(); + if (cond - 2u > 0xEu) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addReg(o1, 16); + opcode.addImm(condCodeToOpcodeCond(uint32_t(cond)) ^ 1u, 12); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseCSel: { + const InstDB::EncodingData::BaseCSel& opData = InstDB::EncodingData::baseCSel[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + uint32_t x; + if (!checkGpType(o0, o1, o2, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, o2, kZR)) + goto InvalidPhysId; + + uint64_t cond = o3.as().valueAs(); + if (cond > 0xFu) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addReg(o2, 16); + opcode.addImm(condCodeToOpcodeCond(uint32_t(cond)), 12); + opcode.addReg(o1, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseCSet: { + const InstDB::EncodingData::BaseCSet& opData = InstDB::EncodingData::baseCSet[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Imm)) { + uint32_t x; + if (!checkGpType(o0, InstDB::kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + uint64_t cond = o1.as().valueAs(); + if (cond - 2u >= 0xEu) + goto InvalidImmediate; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addImm(condCodeToOpcodeCond(uint32_t(cond)) ^ 1u, 12); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Special] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseAtDcIcTlbi: { + const InstDB::EncodingData::BaseAtDcIcTlbi& opData = InstDB::EncodingData::baseAtDcIcTlbi[encodingIndex]; + + if (isign4 == ENC_OPS1(Imm) || isign4 == ENC_OPS2(Imm, Reg)) { + if (opData.mandatoryReg && isign4 != ENC_OPS2(Imm, Reg)) + goto InvalidInstruction; + + if (o0.as().valueAs() > 0x7FFFu) + goto InvalidImmediate; + + uint32_t imm = o0.as().valueAs(); + if ((imm & opData.immVerifyMask) != opData.immVerifyData) + goto InvalidImmediate; + + uint32_t rt = 31; + if (o1.isReg()) { + if (!o1.as().isGpX()) + goto InvalidInstruction; + + if (!checkGpId(o1, kZR)) + goto InvalidPhysId; + + rt = o1.id() & 31; + } + + opcode.reset(0b11010101000010000000000000000000); + opcode.addImm(imm, 5); + opcode.addReg(rt, 0); + goto EmitOp; + } + break; + } + + case InstDB::kEncodingBaseMrs: { + if (isign4 == ENC_OPS2(Reg, Imm)) { + if (!o0.as().isGpX()) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + if (o1.as().valueAs() > 0xFFFFu) + goto InvalidImmediate; + + uint32_t imm = o1.as().valueAs(); + if (!(imm & B(15))) + goto InvalidImmediate; + + opcode.reset(0b11010101001100000000000000000000); + opcode.addImm(imm, 5); + opcode.addReg(o0, 0); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseMsr: { + if (isign4 == ENC_OPS2(Imm, Reg)) { + if (!o1.as().isGpX()) + goto InvalidInstruction; + + if (o0.as().valueAs() > 0xFFFFu) + goto InvalidImmediate; + + uint32_t imm = o0.as().valueAs(); + if (!(imm & B(15))) + goto InvalidImmediate; + + if (!checkGpId(o1, kZR)) + goto InvalidPhysId; + + opcode.reset(0b11010101000100000000000000000000); + opcode.addImm(imm, 5); + opcode.addReg(o1, 0); + goto EmitOp; + } + + if (isign4 == ENC_OPS2(Imm, Imm)) { + if (o0.as().valueAs() > 0x1Fu) + goto InvalidImmediate; + + if (o1.as().valueAs() > 0xFu) + goto InvalidImmediate; + + uint32_t op = o0.as().valueAs(); + uint32_t cRm = o1.as().valueAs(); + + uint32_t op1 = uint32_t(op) >> 3; + uint32_t op2 = uint32_t(op) & 0x7u; + + opcode.reset(0b11010101000000000100000000011111); + opcode.addImm(op1, 16); + opcode.addImm(cRm, 8); + opcode.addImm(op2, 5); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseSys: { + if (isign4 == ENC_OPS4(Imm, Imm, Imm, Imm)) { + if (o0.as().valueAs() > 0x7u || + o1.as().valueAs() > 0xFu || + o2.as().valueAs() > 0xFu || + o3.as().valueAs() > 0x7u) + goto InvalidImmediate; + + uint32_t op1 = o0.as().valueAs(); + uint32_t cRn = o1.as().valueAs(); + uint32_t cRm = o2.as().valueAs(); + uint32_t op2 = o3.as().valueAs(); + uint32_t rt = 31; + + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + if (o4.isReg()) { + if (!o4.as().isGpX()) + goto InvalidInstruction; + + if (!checkGpId(o4, kZR)) + goto InvalidPhysId; + + rt = o4.id() & 31; + } + else if (!o4.isNone()) { + goto InvalidInstruction; + } + + opcode.reset(0b11010101000010000000000000000000); + opcode.addImm(op1, 16); + opcode.addImm(cRn, 12); + opcode.addImm(cRm, 8); + opcode.addImm(op2, 5); + opcode.addImm(rt, 0); + goto EmitOp; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Branch] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseBranchReg: { + const InstDB::EncodingData::BaseBranchReg& opData = InstDB::EncodingData::baseBranchReg[encodingIndex]; + + if (isign4 == ENC_OPS1(Reg)) { + if (!o0.as().isGpX()) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode); + opcode.addReg(o0, 5); + goto EmitOp; + } + + break; + } + + case InstDB::kEncodingBaseBranchRel: { + const InstDB::EncodingData::BaseBranchRel& opData = InstDB::EncodingData::baseBranchRel[encodingIndex]; + + if (isign4 == ENC_OPS1(Label) || isign4 == ENC_OPS1(Imm)) { + opcode.reset(opData.opcode); + rmRel = &o0; + + if (instCC != CondCode::kAL) { + opcode |= B(30); + opcode.addImm(condCodeToOpcodeCond(uint32_t(instCC)), 0); + offsetFormat.resetToImmValue(OffsetType::kSignedOffset, 4, 5, 19, 2); + goto EmitOp_Rel; + } + + offsetFormat.resetToImmValue(OffsetType::kSignedOffset, 4, 0, 26, 2); + goto EmitOp_Rel; + } + + break; + } + + case InstDB::kEncodingBaseBranchCmp: { + const InstDB::EncodingData::BaseBranchCmp& opData = InstDB::EncodingData::baseBranchCmp[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Label) || isign4 == ENC_OPS2(Reg, Imm)) { + uint32_t x; + if (!checkGpType(o0, kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode); + opcode.addImm(x, 31); + opcode.addReg(o0, 0); + offsetFormat.resetToImmValue(OffsetType::kSignedOffset, 4, 5, 19, 2); + + rmRel = &o1; + goto EmitOp_Rel; + } + + break; + } + + case InstDB::kEncodingBaseBranchTst: { + const InstDB::EncodingData::BaseBranchTst& opData = InstDB::EncodingData::baseBranchTst[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Imm, Label) || isign4 == ENC_OPS3(Reg, Imm, Imm)) { + uint32_t x; + if (!checkGpType(o0, kWX, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + uint64_t imm = o1.as().valueAs(); + + opcode.reset(opData.opcode); + if (imm >= 32) { + if (!x) + goto InvalidImmediate; + opcode.addImm(x, 31); + imm &= 0x1F; + } + + opcode.addReg(o0, 0); + opcode.addImm(imm, 19); + offsetFormat.resetToImmValue(OffsetType::kSignedOffset, 4, 5, 14, 2); + + rmRel = &o2; + goto EmitOp_Rel; + } + + break; + } + + // ------------------------------------------------------------------------ + // [Base - Load / Store] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingBaseLdSt: { + const InstDB::EncodingData::BaseLdSt& opData = InstDB::EncodingData::baseLdSt[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + rmRel = &m; + + uint32_t x; + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + // Instructions that work with either word or dword have the unsigned + // offset shift set to 2 (word), so we set it to 3 (dword) if this is + // X version of the instruction. + uint32_t xShiftMask = uint32_t(opData.uOffsetShift == 2); + uint32_t immShift = uint32_t(opData.uOffsetShift) + (x & xShiftMask); + + if (!armCheckMemBaseIndexRel(m)) + goto InvalidAddress; + + int64_t offset = m.offset(); + if (m.hasBaseReg()) { + // [Base {Offset | Index}] + if (m.hasIndex()) { + uint32_t opt = armShiftOpToLdStOptMap[m.predicate()]; + if (opt == 0xFF) + goto InvalidAddress; + + uint32_t shift = m.shift(); + uint32_t s = shift != 0; + + if (s && shift != immShift) + goto InvalidAddressScale; + + opcode.reset(uint32_t(opData.registerOp) << 21); + opcode.xorImm(x, opData.xOffset); + opcode.addImm(opt, 13); + opcode.addImm(s, 12); + opcode |= B(11); + opcode.addReg(o0, 0); + goto EmitOp_MemBaseIndex_Rn5_Rm16; + } + + // Makes it easier to work with the offset especially on 32-bit arch. + if (!Support::isInt32(offset)) + goto InvalidDisplacement; + int32_t offset32 = int32_t(offset); + + if (m.isPreOrPost()) { + if (!Support::isInt9(offset32)) + goto InvalidDisplacement; + + opcode.reset(uint32_t(opData.prePostOp) << 21); + opcode.xorImm(x, opData.xOffset); + opcode.addImm(offset32 & 0x1FF, 12); + opcode.addImm(m.isPreIndex(), 11); + opcode |= B(10); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + else { + uint32_t imm12 = uint32_t(offset32) >> immShift; + + // Alternative form of LDUR/STUR and related instructions as described by AArch64 reference manual: + // + // If this instruction is not encodable with scaled unsigned offset, try unscaled signed offset. + if (!Support::isUInt12(imm12) || (imm12 << immShift) != uint32_t(offset32)) { + instId = opData.uAltInstId; + instInfo = &InstDB::_instInfoTable[instId]; + encodingIndex = instInfo->_encodingDataIndex; + goto Case_BaseLdurStur; + } + + opcode.reset(uint32_t(opData.uOffsetOp) << 22); + opcode.xorImm(x, opData.xOffset); + opcode.addImm(imm12, 10); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + } + else { + if (!opData.literalOp) + goto InvalidAddress; + + opcode.reset(uint32_t(opData.literalOp) << 24); + opcode.xorImm(x, opData.xOffset); + opcode.addReg(o0, 0); + offsetFormat.resetToImmValue(OffsetType::kSignedOffset, 4, 5, 19, 2); + goto EmitOp_Rel; + } + } + + break; + } + + case InstDB::kEncodingBaseLdpStp: { + const InstDB::EncodingData::BaseLdpStp& opData = InstDB::EncodingData::baseLdpStp[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Mem)) { + const Mem& m = o2.as(); + rmRel = &m; + + uint32_t x; + if (!checkGpType(o0, o1, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + if (m.baseType() != RegType::kARM_GpX || m.hasIndex()) + goto InvalidAddress; + + if (m.isOffset64Bit()) + goto InvalidDisplacement; + + uint32_t offsetShift = opData.offsetShift + x; + int32_t offset32 = m.offsetLo32() >> offsetShift; + + // Make sure we didn't lose bits by applying the mandatory offset shift. + if (uint32_t(offset32) << offsetShift != uint32_t(m.offsetLo32())) + goto InvalidDisplacement; + + // Offset is encoded as 7-bit immediate. + if (!Support::isInt7(offset32)) + goto InvalidDisplacement; + + if (m.isPreOrPost() && offset32 != 0) { + if (!opData.prePostOp) + goto InvalidAddress; + + opcode.reset(uint32_t(opData.prePostOp) << 22); + opcode.addImm(m.isPreIndex(), 24); + } + else { + opcode.reset(uint32_t(opData.offsetOp) << 22); + } + + opcode.addImm(x, opData.xOffset); + opcode.addImm(offset32 & 0x7F, 15); + opcode.addReg(o1, 10); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseStx: { + const InstDB::EncodingData::BaseStx& opData = InstDB::EncodingData::baseStx[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Mem)) { + const Mem& m = o2.as(); + uint32_t x; + + if (!o0.as().isGpW() || !checkGpType(o1, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o0, 16); + opcode.addReg(o1, 0); + + rmRel = &m; + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseLdxp: { + const InstDB::EncodingData::BaseLdxp& opData = InstDB::EncodingData::baseLdxp[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Mem)) { + const Mem& m = o2.as(); + uint32_t x; + + if (!checkGpType(o0, opData.rType, &x) || !checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o1, 10); + opcode.addReg(o0, 0); + + rmRel = &m; + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseStxp: { + const InstDB::EncodingData::BaseStxp& opData = InstDB::EncodingData::baseStxp[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) { + const Mem& m = o3.as(); + uint32_t x; + + if (!o0.as().isGpW() || !checkGpType(o1, opData.rType, &x) || !checkSignature(o1, o2)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, o2, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o0, 16); + opcode.addReg(o2, 10); + opcode.addReg(o1, 0); + + rmRel = &m; + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseRM_NoImm: { + const InstDB::EncodingData::BaseRM_NoImm& opData = InstDB::EncodingData::baseRM_NoImm[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + rmRel = &m; + + uint32_t x; + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.rHiId)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o0, 0); + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseRM_SImm9: { +Case_BaseLdurStur: + const InstDB::EncodingData::BaseRM_SImm9& opData = InstDB::EncodingData::baseRM_SImm9[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + rmRel = &m; + + uint32_t x; + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.rHiId)) + goto InvalidPhysId; + + if (m.hasBaseReg() && !m.hasIndex()) { + if (m.isOffset64Bit()) + goto InvalidDisplacement; + + int32_t offset32 = m.offsetLo32() >> opData.immShift; + if (Support::shl(offset32, opData.immShift) != m.offsetLo32()) + goto InvalidDisplacement; + + if (!Support::isInt9(offset32)) + goto InvalidDisplacement; + + if (m.isFixedOffset()) { + opcode.reset(opData.offsetOp()); + } + else { + if (!opData.prePostOp()) + goto InvalidInstruction; + + opcode.reset(opData.prePostOp()); + opcode.xorImm(m.isPreIndex(), 11); + } + + opcode.xorImm(x, opData.xOffset); + opcode.addImm(offset32 & 0x1FF, 12); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + + goto InvalidAddress; + } + + break; + } + + case InstDB::kEncodingBaseRM_SImm10: { + const InstDB::EncodingData::BaseRM_SImm10& opData = InstDB::EncodingData::baseRM_SImm10[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + rmRel = &m; + + uint32_t x; + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, opData.rHiId)) + goto InvalidPhysId; + + if (m.hasBaseReg() && !m.hasIndex()) { + if (m.isOffset64Bit()) + goto InvalidDisplacement; + + int32_t offset32 = m.offsetLo32() >> opData.immShift; + if (Support::shl(offset32, opData.immShift) != m.offsetLo32()) + goto InvalidDisplacement; + + if (!Support::isInt10(offset32)) + goto InvalidDisplacement; + + if (m.isPostIndex()) + goto InvalidAddress; + + // Offset has 10 bits, sign is stored in the 10th bit. + offset32 &= 0x3FF; + + opcode.reset(opData.opcode()); + opcode.xorImm(m.isPreIndex(), 11); + opcode.xorImm(x, opData.xOffset); + opcode.addImm(offset32 >> 9, 22); + opcode.addImm(offset32, 12); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + + goto InvalidAddress; + } + + break; + } + + case InstDB::kEncodingBaseAtomicOp: { + const InstDB::EncodingData::BaseAtomicOp& opData = InstDB::EncodingData::baseAtomicOp[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Mem)) { + const Mem& m = o2.as(); + uint32_t x; + + if (!checkGpType(o0, opData.rType, &x) || !checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkGpId(o0, o1, kZR)) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o0, 16); + opcode.addReg(o1, 0); + + rmRel = &m; + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseAtomicSt: { + const InstDB::EncodingData::BaseAtomicSt& opData = InstDB::EncodingData::baseAtomicSt[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + uint32_t x; + + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkGpId(o0, kZR)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o0, 16); + opcode.addReg(Gp::kIdZr, 0); + + rmRel = &m; + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + case InstDB::kEncodingBaseAtomicCasp: { + const InstDB::EncodingData::BaseAtomicCasp& opData = InstDB::EncodingData::baseAtomicCasp[encodingIndex]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg) && o4.isMem()) { + const Mem& m = o4.as(); + uint32_t x; + + if (!checkGpType(o0, opData.rType, &x)) + goto InvalidInstruction; + + if (!checkSignature(o0, o1, o2, o3)) + goto InvalidInstruction; + + if (!checkEven(o0, o2) || !checkGpId(o0, o2, kZR)) + goto InvalidPhysId; + + if (!checkConsecutive(o0, o1) || !checkConsecutive(o2, o3)) + goto InvalidPhysId; + + opcode.reset(opData.opcode()); + opcode.addImm(x, opData.xOffset); + opcode.addReg(o0, 16); + opcode.addReg(o2, 0); + + rmRel = &m; + goto EmitOp_MemBaseNoImm_Rn5; + } + + break; + } + + // ------------------------------------------------------------------------ + // [FSimd - Instructions] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingFSimdSV: { + const InstDB::EncodingData::FSimdSV& opData = InstDB::EncodingData::fSimdSV[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + uint32_t q = diff(o1.as().type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + if (o0.as().hasElementType()) + goto InvalidInstruction; + + // This operation is only defined for: + // hD, vS.{4|8}h (16-bit) + // sD, vS.4s (32-bit) + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + uint32_t elementSz = o1.as().elementType() - Vec::kElementTypeH; + + // Size greater than 1 means 64-bit elements, not supported. + if ((sz | elementSz) > 1 || sz != elementSz) + goto InvalidInstruction; + + // Size 1 (32-bit float) requires at least 4 elements. + if (sz && !q) + goto InvalidInstruction; + + // Bit flipping according to sz. + static const uint32_t szBits[] = { B(29), 0 }; + + opcode.reset(opData.opcode << 10); + opcode ^= szBits[sz]; + opcode.addImm(q, 30); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingFSimdVV: { + const InstDB::EncodingData::FSimdVV& opData = InstDB::EncodingData::fSimdVV[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + if (!pickFpOpcode(o0.as(), opData.scalarOp(), opData.scalarHf(), opData.vectorOp(), opData.vectorHf(), &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingFSimdVVV: { + const InstDB::EncodingData::FSimdVVV& opData = InstDB::EncodingData::fSimdVVV[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + if (!pickFpOpcode(o0.as(), opData.scalarOp(), opData.scalarHf(), opData.vectorOp(), opData.vectorHf(), &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingFSimdVVVe: { + const InstDB::EncodingData::FSimdVVVe& opData = InstDB::EncodingData::fSimdVVVe[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!o2.as().hasElementIndex()) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + if (!pickFpOpcode(o0.as(), opData.scalarOp(), opData.scalarHf(), opData.vectorOp(), opData.vectorHf(), &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5_Rm16; + } + else { + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + uint32_t q = o1.as().isVecQ(); + uint32_t sz; + + if (!pickFpOpcode(o0.as(), opData.elementScalarOp(), InstDB::kHF_D, opData.elementVectorOp(), InstDB::kHF_D, &opcode, &sz)) + goto InvalidInstruction; + + if (sz == 0 && o2.as().id() > 15) + goto InvalidPhysId; + + uint32_t elementIndex = o2.as().elementIndex(); + if (elementIndex > (7u >> sz)) + goto InvalidElementIndex; + + uint32_t hlm = elementIndex << sz; + opcode.addImm(q, 30); + opcode.addImm(hlm & 3u, 20); + opcode.addImm(hlm >> 2, 11); + goto EmitOp_Rd0_Rn5_Rm16; + } + } + + break; + } + + case InstDB::kEncodingFSimdVVVV: { + const InstDB::EncodingData::FSimdVVVV& opData = InstDB::EncodingData::fSimdVVVV[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { + if (!matchSignature(o0, o1, o2, o3, instFlags)) + goto InvalidInstruction; + + if (!pickFpOpcode(o0.as(), opData.scalarOp(), opData.scalarHf(), opData.vectorOp(), opData.vectorHf(), &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5_Rm16_Ra10; + } + + break; + } + + case InstDB::kEncodingSimdFcadd: { + const InstDB::EncodingData::SimdFcadd& opData = InstDB::EncodingData::simdFcadd[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + if (!checkSignature(o0, o1, o2) || o0.as().hasElementIndex()) + goto InvalidInstruction; + + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + uint32_t sz = o0.as().elementType() - Vec::kElementTypeB; + if (sz == 0 || sz > 3) + goto InvalidInstruction; + + // 0 <- 90deg. + // 1 <- 270deg. + uint32_t rot = 0; + if (o3.as().value() == 270) + rot = 1; + else if (o3.as().value() != 90) + goto InvalidImmediate; + + opcode.reset(opData.opcode()); + opcode.addImm(q, 30); + opcode.addImm(sz, 22); + opcode.addImm(rot, 12); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingSimdFccmpFccmpe: { + const InstDB::EncodingData::SimdFccmpFccmpe& opData = InstDB::EncodingData::simdFccmpFccmpe[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + if (sz > 2) + goto InvalidInstruction; + + if (!checkSignature(o0, o1) || o0.as().hasElementType()) + goto InvalidInstruction; + + uint64_t nzcv = o2.as().valueAs(); + uint64_t cond = o3.as().valueAs(); + + if ((nzcv | cond) > 0xFu) + goto InvalidImmediate; + + uint32_t type = (sz - 1) & 0x3u; + + opcode.reset(opData.opcode()); + opcode.addImm(type, 22); + opcode.addImm(condCodeToOpcodeCond(uint32_t(cond)), 12); + opcode.addImm(nzcv, 0); + + goto EmitOp_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingSimdFcm: { + const InstDB::EncodingData::SimdFcm& opData = InstDB::EncodingData::simdFcm[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg) && opData.hasRegisterOp()) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + if (!pickFpOpcode(o0.as(), opData.registerScalarOp(), opData.registerScalarHf(), opData.registerVectorOp(), opData.registerVectorHf(), &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5_Rm16; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) && opData.hasZeroOp()) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (o2.as().value() != 0 || o2.as().predicate() != 0) + goto InvalidImmediate; + + if (!pickFpOpcode(o0.as(), opData.zeroScalarOp(), InstDB::kHF_B, opData.zeroVectorOp(), InstDB::kHF_B, &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdFcmla: { + const InstDB::EncodingData::SimdFcmla& opData = InstDB::EncodingData::simdFcmla[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + uint32_t sz = o0.as().elementType() - Vec::kElementTypeB; + if (sz == 0 || sz > 3) + goto InvalidInstruction; + + uint32_t rot = 0; + switch (o3.as().value()) { + case 0 : rot = 0; break; + case 90 : rot = 1; break; + case 180: rot = 2; break; + case 270: rot = 3; break; + default: + goto InvalidImmediate; + } + + if (!o2.as().hasElementIndex()) { + if (!checkSignature(o1, o2)) + goto InvalidInstruction; + + opcode.reset(opData.regularOp()); + opcode.addImm(q, 30); + opcode.addImm(sz, 22); + opcode.addImm(rot, 11); + goto EmitOp_Rd0_Rn5_Rm16; + } + else { + if (o0.as().elementType() != o2.as().elementType()) + goto InvalidInstruction; + + // Only allowed vectors are: 4H, 8H, and 4S. + if (!(sz == 1 || (q == 1 && sz == 2))) + goto InvalidInstruction; + + // Element index ranges: + // 4H - ElementIndex[0..1] (index 2..3 is UNDEFINED). + // 8H - ElementIndex[0..3]. + // 4S - ElementIndex[0..1]. + uint32_t elementIndex = o2.as().elementIndex(); + uint32_t hlFieldShift = sz == 1 ? 0u : 1u; + uint32_t maxElementIndex = q == 1 && sz == 1 ? 3u : 1u; + + if (elementIndex > maxElementIndex) + goto InvalidElementIndex; + + uint32_t hl = elementIndex << hlFieldShift; + + opcode.reset(opData.elementOp()); + opcode.addImm(q, 30); + opcode.addImm(sz, 22); + opcode.addImm(hl & 1u, 21); // L field. + opcode.addImm(hl >> 1, 11); // H field. + opcode.addImm(rot, 13); + goto EmitOp_Rd0_Rn5_Rm16; + } + } + + break; + } + + case InstDB::kEncodingSimdFcmpFcmpe: { + const InstDB::EncodingData::SimdFcmpFcmpe& opData = InstDB::EncodingData::simdFcmpFcmpe[encodingIndex]; + + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + uint32_t type = (sz - 1) & 0x3u; + + if (sz > 2) + goto InvalidInstruction; + + if (o0.as().hasElementType()) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + opcode.addImm(type, 22); + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + goto EmitOp_Rn5_Rm16; + } + + if (isign4 == ENC_OPS2(Reg, Imm)) { + if (o1.as().value() != 0 || o1.as().predicate() != 0) + goto InvalidInstruction; + + opcode |= B(3); + goto EmitOp_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdFcsel: { + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + if (!checkSignature(o0, o1, o2)) + goto InvalidInstruction; + + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + uint32_t type = (sz - 1) & 0x3u; + + if (sz > 2 || o0.as().hasElementType()) + goto InvalidInstruction; + + uint64_t cond = o3.as().valueAs(); + if (cond > 0xFu) + goto InvalidImmediate; + + opcode.reset(0b00011110001000000000110000000000); + opcode.addImm(type, 22); + opcode.addImm(condCodeToOpcodeCond(uint32_t(cond)), 12); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingSimdFcvt: { + if (isign4 == ENC_OPS2(Reg, Reg)) { + uint32_t dstSz = diff(o0.as().type(), RegType::kARM_VecH); + uint32_t srcSz = diff(o1.as().type(), RegType::kARM_VecH); + + if ((dstSz | srcSz) > 3) + goto InvalidInstruction; + + if (o0.as().hasElementType() || o1.as().hasElementType()) + goto InvalidInstruction; + + // Table that provides 'type' and 'opc' according to the dst/src combination. + static const uint8_t table[] = { + 0xFFu, // H <- H (Invalid). + 0x03u, // H <- S (type=00 opc=11). + 0x13u, // H <- D (type=01 opc=11). + 0xFFu, // H <- Q (Invalid). + 0x30u, // S <- H (type=11 opc=00). + 0xFFu, // S <- S (Invalid). + 0x10u, // S <- D (type=01 opc=00). + 0xFFu, // S <- Q (Invalid). + 0x31u, // D <- H (type=11 opc=01). + 0x01u, // D <- S (type=00 opc=01). + 0xFFu, // D <- D (Invalid). + 0xFFu, // D <- Q (Invalid). + 0xFFu, // Q <- H (Invalid). + 0xFFu, // Q <- S (Invalid). + 0xFFu, // Q <- D (Invalid). + 0xFFu // Q <- Q (Invalid). + }; + + uint32_t typeOpc = table[(dstSz << 2) | srcSz]; + opcode.reset(0b0001111000100010010000 << 10); + opcode.addImm(typeOpc >> 4, 22); + opcode.addImm(typeOpc & 15, 15); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdFcvtLN: { + const InstDB::EncodingData::SimdFcvtLN& opData = InstDB::EncodingData::simdFcvtLN[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + // Scalar form - only FCVTXN. + if (o0.as().isVecS() && o1.as().isVecD()) { + if (!opData.hasScalar()) + goto InvalidInstruction; + + if (o0.as().hasElementType() || o1.as().hasElementType()) + goto InvalidInstruction; + + opcode.reset(opData.scalarOp()); + opcode |= B(22); // sz bit must be 1, the only supported combination of FCVTXN. + goto EmitOp_Rd0_Rn5; + } + + opcode.reset(opData.vectorOp()); + + const Vec& rL = (instFlags & InstDB::kInstFlagLong) ? o0.as() : o1.as(); + const Vec& rN = (instFlags & InstDB::kInstFlagLong) ? o1.as() : o0.as(); + + uint32_t q = diff(rN.type(), RegType::kARM_VecD); + if (uint32_t(opcode.hasQ()) != q) + goto InvalidInstruction; + + if (rL.isVecS4() && rN.elementType() == Vec::kElementTypeH && !opData.isCvtxn()) { + goto EmitOp_Rd0_Rn5; + } + + if (rL.isVecD2() && rN.elementType() == Vec::kElementTypeS) { + opcode |= B(22); + goto EmitOp_Rd0_Rn5; + } + } + + break; + } + + case InstDB::kEncodingSimdFcvtSV: { + const InstDB::EncodingData::SimdFcvtSV& opData = InstDB::EncodingData::simdFcvtSV[encodingIndex]; + + // So we can support both IntToFloat and FloatToInt conversions. + const Operand_& oGp = opData.isFloatToInt() ? o0 : o1; + const Operand_& oVec = opData.isFloatToInt() ? o1 : o0; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (oGp.as().isGp() && oVec.as().isVec()) { + uint32_t x = oGp.as().isGpX(); + uint32_t type = diff(oVec.as().type(), RegType::kARM_VecH); + + if (type > 2u) + goto InvalidInstruction; + + type = (type - 1u) & 0x3; + opcode.reset(opData.generalOp()); + opcode.addImm(type, 22); + opcode.addImm(x, 31); + goto EmitOp_Rd0_Rn5; + } + + if (o0.as().isVec() && o1.as().isVec()) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!pickFpOpcode(o0.as(), opData.scalarIntOp(), InstDB::kHF_B, opData.vectorIntOp(), InstDB::kHF_B, &opcode)) + goto InvalidInstruction; + + goto EmitOp_Rd0_Rn5; + } + } + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) && opData.isFixedPoint()) { + if (o2.as().valueAs() >= 64) + goto InvalidInstruction; + + uint32_t scale = o2.as().valueAs(); + if (scale == 0) + goto InvalidInstruction; + + if (oGp.as().isGp() && oVec.as().isVec()) { + uint32_t x = oGp.as().isGpX(); + uint32_t type = diff(oVec.as().type(), RegType::kARM_VecH); + + uint32_t scaleLimit = 32u << x; + if (scale > scaleLimit) + goto InvalidInstruction; + + type = (type - 1u) & 0x3; + opcode.reset(opData.generalOp() ^ B(21)); + opcode.addImm(type, 22); + opcode.addImm(x, 31); + opcode.addImm(64u - scale, 10); + goto EmitOp_Rd0_Rn5; + } + + if (o0.as().isVec() && o1.as().isVec()) { + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + uint32_t sz; + if (!pickFpOpcode(o0.as(), opData.scalarFpOp(), InstDB::kHF_0, opData.vectorFpOp(), InstDB::kHF_0, &opcode, &sz)) + goto InvalidInstruction; + + uint32_t scaleLimit = 16u << sz; + if (scale > scaleLimit) + goto InvalidInstruction; + + uint32_t imm = Support::neg(scale) & Support::lsbMask(sz + 4 + 1); + opcode.addImm(imm, 16); + goto EmitOp_Rd0_Rn5; + } + } + + break; + } + + case InstDB::kEncodingSimdFmlal: { + const InstDB::EncodingData::SimdFmlal& opData = InstDB::EncodingData::simdFmlal[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + uint32_t qIsOptional = opData.optionalQ(); + + if (qIsOptional) { + // This instruction works with either 64-bit or 128-bit registers, + // encoded by Q bit. + if (q > 1) + goto InvalidInstruction; + } + else { + // This instruction requires 128-bit vector registers. + if (q != 1) + goto InvalidInstruction; + + // The instruction is ehtier B (bottom) or T (top), which is part of + // the opcode, which uses Q bit, so we have to clear it explicitly. + q = 0; + } + + if (uint32_t(o0.as().type()) != uint32_t(o1.as().type()) + qIsOptional || + o0.as().elementType() != opData.tA || + o1.as().elementType() != opData.tB) + goto InvalidInstruction; + + if (!o2.as().hasElementIndex()) { + if (!checkSignature(o1, o2)) + goto InvalidInstruction; + + opcode.reset(opData.vectorOp()); + opcode.addImm(q, 30); + goto EmitOp_Rd0_Rn5_Rm16; + } + else { + if (o2.as().elementType() != opData.tElement) + goto InvalidInstruction; + + if (o2.as().id() > 15) + goto InvalidPhysId; + + uint32_t elementIndex = o2.as().elementIndex(); + if (elementIndex > 7u) + goto InvalidElementIndex; + + opcode.reset(opData.elementOp()); + opcode.addImm(q, 30); + opcode.addImm(elementIndex & 3u, 20); + opcode.addImm(elementIndex >> 2, 11); + goto EmitOp_Rd0_Rn5_Rm16; + } + } + + break; + } + + case InstDB::kEncodingSimdFmov: { + if (isign4 == ENC_OPS2(Reg, Reg)) { + // FMOV Gp <-> Vec opcode: + opcode.reset(0b00011110001001100000000000000000); + + if (o0.as().isGp() && o1.as().isVec()) { + // FMOV Wd, Hn (sf=0 type=11 rmode=00 op=110) + // FMOV Xd, Hn (sf=1 type=11 rmode=00 op=110) + // FMOV Wd, Sn (sf=0 type=00 rmode=00 op=110) + // FMOV Xd, Dn (sf=1 type=11 rmode=00 op=110) + // FMOV Xd, Vn.d[1] (sf=1 type=10 rmode=01 op=110) + uint32_t x = o0.as().isGpX(); + uint32_t sz = diff(o1.as().type(), RegType::kARM_VecH); + + uint32_t type = (sz - 1) & 0x3u; + uint32_t rModeOp = 0b00110; + + if (o1.as().hasElementIndex()) { + // Special case. + if (!x || !o1.as().isVecD2() || o1.as().elementIndex() != 1) + goto InvalidInstruction; + type = 0b10; + rModeOp = 0b01110; + } + else { + // Must be scalar. + if (sz > 2) + goto InvalidInstruction; + + if (o1.as().hasElementType()) + goto InvalidInstruction; + + if (o1.as().isVecS() && x) + goto InvalidInstruction; + + if (o1.as().isVecD() && !x) + goto InvalidInstruction; + } + + opcode.addImm(x, 31); + opcode.addImm(type, 22); + opcode.addImm(rModeOp, 16); + goto EmitOp_Rd0_Rn5; + } + + if (o0.as().isVec() && o1.as().isGp()) { + // FMOV Hd, Wn (sf=0 type=11 rmode=00 op=111) + // FMOV Hd, Xn (sf=1 type=11 rmode=00 op=111) + // FMOV Sd, Wn (sf=0 type=00 rmode=00 op=111) + // FMOV Dd, Xn (sf=1 type=11 rmode=00 op=111) + // FMOV Vd.d[1], Xn (sf=1 type=10 rmode=01 op=111) + uint32_t x = o1.as().isGpX(); + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + + uint32_t type = (sz - 1) & 0x3u; + uint32_t rModeOp = 0b00111; + + if (o0.as().hasElementIndex()) { + // Special case. + if (!x || !o0.as().isVecD2() || o0.as().elementIndex() != 1) + goto InvalidInstruction; + type = 0b10; + rModeOp = 0b01111; + } + else { + // Must be scalar. + if (sz > 2) + goto InvalidInstruction; + + if (o0.as().hasElementType()) + goto InvalidInstruction; + + if (o0.as().isVecS() && x) + goto InvalidInstruction; + + if (o0.as().isVecD() && !x) + goto InvalidInstruction; + } + + opcode.addImm(x, 31); + opcode.addImm(type, 22); + opcode.addImm(rModeOp, 16); + goto EmitOp_Rd0_Rn5; + } + + if (checkSignature(o0, o1)) { + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + if (sz > 2) + goto InvalidInstruction; + + if (o0.as().hasElementType()) + goto InvalidInstruction; + + uint32_t type = (sz - 1) & 0x3; + opcode.reset(0b00011110001000000100000000000000); + opcode.addImm(type, 22); + goto EmitOp_Rd0_Rn5; + } + } + + if (isign4 == ENC_OPS2(Reg, Imm)) { + if (o0.as().isVec()) { + double fpValue; + if (o1.as().isDouble()) + fpValue = o1.as().valueAs(); + else if (o1.as().isInt32()) + fpValue = o1.as().valueAs(); + else + goto InvalidImmediate; + + if (!Utils::isFP64Imm8(fpValue)) + goto InvalidImmediate; + + uint32_t imm8 = Utils::encodeFP64ToImm8(fpValue); + if (!o0.as().hasElementType()) { + // FMOV (scalar, immediate). + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + uint32_t type = (sz - 1u) & 0x3u; + + if (sz > 2) + goto InvalidInstruction; + + opcode.reset(0b00011110001000000001000000000000); + opcode.addImm(type, 22); + opcode.addImm(imm8, 13); + goto EmitOp_Rd0; + } + else { + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + uint32_t sz = o0.as().elementType() - Vec::kElementTypeH; + + if (q > 1 || sz > 2) + goto InvalidInstruction; + + static const uint32_t szBits[3] = { B(11), B(0), B(29) }; + opcode.reset(0b00001111000000001111010000000000); + opcode ^= szBits[sz]; + opcode.addImm(q, 30); + opcode.addImm(imm8 >> 5, 16); + opcode.addImm(imm8 & 31, 5); + goto EmitOp_Rd0; + } + } + } + + break; + } + + case InstDB::kEncodingFSimdPair: { + const InstDB::EncodingData::FSimdPair& opData = InstDB::EncodingData::fSimdPair[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + // This operation is only defined for: + // hD, vS.2h (16-bit) + // sD, vS.2s (32-bit) + // dD, vS.2d (64-bit) + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); + if (sz > 2) + goto InvalidInstruction; + + static const uint32_t szSignatures[3] = { + VecS::kSignature | (Vec::kSignatureElementH), + VecD::kSignature | (Vec::kSignatureElementS), + VecV::kSignature | (Vec::kSignatureElementD) + }; + + if (o1.signature() != szSignatures[sz]) + goto InvalidInstruction; + + static const uint32_t szBits[] = { B(29), 0, B(22) }; + opcode.reset(opData.scalarOp()); + opcode ^= szBits[sz]; + goto EmitOp_Rd0_Rn5; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!checkSignature(o0, o1, o2)) + goto InvalidInstruction; + + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + uint32_t sz = o0.as().elementType() - Vec::kElementTypeH; + if (sz > 2) + goto InvalidInstruction; + + static const uint32_t szBits[3] = { B(22) | B(21) | B(15) | B(14), 0, B(22) }; + opcode.reset(opData.vectorOp()); + opcode ^= szBits[sz]; + opcode.addImm(q, 30); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + // ------------------------------------------------------------------------ + // [ISimd - Instructions] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingISimdSV: { + const InstDB::EncodingData::ISimdSV& opData = InstDB::EncodingData::iSimdSV[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + // The first destination operand is scalar, which matches element-type of source vectors. + uint32_t L = (instFlags & InstDB::kInstFlagLong) != 0; + if (diff(o0.as().type(), RegType::kARM_VecB) != o1.as().elementType() - Vec::kElementTypeB + L) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o1.as().type(), o1.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + opcode.addImm(sizeOp.q(), 30); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingISimdVV: { + const InstDB::EncodingData::ISimdVV& opData = InstDB::EncodingData::iSimdVV[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + const Operand_& sop = significantSimdOp(o0, o1, instFlags); + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, sop.as().type(), sop.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingISimdVVx: { + const InstDB::EncodingData::ISimdVVx& opData = InstDB::EncodingData::iSimdVVx[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (o0.signature() != opData.op0Signature || + o1.signature() != opData.op1Signature) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingISimdVVV: { + const InstDB::EncodingData::ISimdVVV& opData = InstDB::EncodingData::iSimdVVV[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + const Operand_& sop = significantSimdOp(o0, o1, instFlags); + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, sop.as().type(), sop.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingISimdVVVx: { + const InstDB::EncodingData::ISimdVVVx& opData = InstDB::EncodingData::iSimdVVVx[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (o0.signature() != opData.op0Signature || + o1.signature() != opData.op1Signature || + o2.signature() != opData.op2Signature) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingISimdWWV: { + // Special case for wide add/sub [s|b][add|sub][w]{2}. + const InstDB::EncodingData::ISimdWWV& opData = InstDB::EncodingData::iSimdWWV[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o2.as().type(), o2.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (!checkSignature(o0, o1) || !o0.as().isVecV() || o0.as().elementType() != o2.as().elementType() + 1) + goto InvalidInstruction; + + opcode.reset(opData.opcode()); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingISimdVVVe: { + const InstDB::EncodingData::ISimdVVVe& opData = InstDB::EncodingData::iSimdVVVe[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + const Operand_& sop = significantSimdOp(o0, o1, instFlags); + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + if (!o2.as().hasElementIndex()) { + SizeOp sizeOp = armElementTypeToSizeOp(opData.regularVecType, sop.as().type(), sop.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (!checkSignature(o1, o2)) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.regularOp) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16; + } + else { + SizeOp sizeOp = armElementTypeToSizeOp(opData.elementVecType, sop.as().type(), sop.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + uint32_t elementIndex = o2.as().elementIndex(); + LMHImm lmh; + + if (!encodeLMH(sizeOp.size(), elementIndex, &lmh)) + goto InvalidElementIndex; + + if (o2.as().id() > lmh.maxRmId) + goto InvalidPhysId; + + opcode.reset(uint32_t(opData.elementOp) << 10); + opcode.addImm(sizeOp.q(), 30); + opcode.addImm(sizeOp.size(), 22); + opcode.addImm(lmh.lm, 20); + opcode.addImm(lmh.h, 11); + goto EmitOp_Rd0_Rn5_Rm16; + } + } + + break; + } + + case InstDB::kEncodingISimdVVVI: { + const InstDB::EncodingData::ISimdVVVI& opData = InstDB::EncodingData::iSimdVVVI[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { + const Operand_& sop = significantSimdOp(o0, o1, instFlags); + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, sop.as().type(), sop.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + uint64_t immValue = o3.as().valueAs(); + uint32_t immSize = opData.immSize; + + if (opData.imm64HasOneBitLess && !sizeOp.q()) + immSize--; + + uint32_t immMax = 1u << immSize; + if (immValue >= immMax) + goto InvalidImmediate; + + opcode.reset(opData.opcode()); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + opcode.addImm(immValue, opData.immShift); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingISimdVVVV: { + const InstDB::EncodingData::ISimdVVVV& opData = InstDB::EncodingData::iSimdVVVV[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { + const Operand_& sop = significantSimdOp(o0, o1, instFlags); + if (!matchSignature(o0, o1, o2, o3, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, sop.as().type(), sop.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16_Ra10; + } + + break; + } + + case InstDB::kEncodingISimdVVVVx: { + const InstDB::EncodingData::ISimdVVVVx& opData = InstDB::EncodingData::iSimdVVVVx[encodingIndex]; + + if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { + if (o0.signature() != opData.op0Signature || + o1.signature() != opData.op1Signature || + o2.signature() != opData.op2Signature || + o3.signature() != opData.op3Signature) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.opcode) << 10); + goto EmitOp_Rd0_Rn5_Rm16_Ra10; + } + + break; + } + + + case InstDB::kEncodingISimdPair: { + const InstDB::EncodingData::ISimdPair& opData = InstDB::EncodingData::iSimdPair[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg) && opData.opcode2) { + if (o0.as().isVecD1() && o1.as().isVecD2()) { + opcode.reset(uint32_t(opData.opcode2) << 10); + opcode.addImm(0x3, 22); // size. + goto EmitOp_Rd0_Rn5; + } + } + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.opType3, o0.as().type(), o0.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.opcode3) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingSimdBicOrr: { + const InstDB::EncodingData::SimdBicOrr& opData = InstDB::EncodingData::simdBicOrr[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(InstDB::kVO_V_B, o0.as().type(), o0.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.registerOp) << 10); + opcode.addImm(sizeOp.q(), 30); + goto EmitOp_Rd0_Rn5_Rm16; + } + + if (isign4 == ENC_OPS2(Reg, Imm) || isign4 == ENC_OPS3(Reg, Imm, Imm)) { + SizeOp sizeOp = armElementTypeToSizeOp(InstDB::kVO_V_HS, o0.as().type(), o0.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (o1.as().valueAs() > 0xFFFFFFFFu) + goto InvalidImmediate; + + uint32_t imm = o1.as().valueAs(); + uint32_t shift = 0; + uint32_t maxShift = (8u << sizeOp.size()) - 8u; + + if (o2.isImm()) { + if (o2.as().predicate() != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + if (imm > 0xFFu || o2.as().valueAs() > maxShift) + goto InvalidImmediate; + + shift = o2.as().valueAs(); + if ((shift & 0x7u) != 0u) + goto InvalidImmediate; + } + else if (imm) { + shift = Support::ctz(imm) & 0x7u; + imm >>= shift; + + if (imm > 0xFFu || shift > maxShift) + goto InvalidImmediate; + } + + uint32_t cmode = 0x1u | ((shift / 8u) << 1); + if (sizeOp.size() == 1) + cmode |= B(3); + + // The immediate value is split into ABC and DEFGH parts. + uint32_t abc = (imm >> 5) & 0x7u; + uint32_t defgh = imm & 0x1Fu; + + opcode.reset(uint32_t(opData.immediateOp) << 10); + opcode.addImm(sizeOp.q(), 30); + opcode.addImm(abc, 16); + opcode.addImm(cmode, 12); + opcode.addImm(defgh, 5); + goto EmitOp_Rd0; + } + + break; + } + + case InstDB::kEncodingSimdCmp: { + const InstDB::EncodingData::SimdCmp& opData = InstDB::EncodingData::simdCmp[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg) && opData.regOp) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o0.as().type(), o0.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.regOp) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) && opData.zeroOp) { + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + if (o2.as().value() != 0) + goto InvalidImmediate; + + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o0.as().type(), o0.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.zeroOp) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdDot: { + const InstDB::EncodingData::SimdDot& opData = InstDB::EncodingData::simdDot[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + uint32_t size = 2; + + if (q > 1u) + goto InvalidInstruction; + + if (!o2.as().hasElementIndex()) { + if (!opData.vectorOp) + goto InvalidInstruction; + + if (o0.as().type() != o1.as().type() || o1.as().type() != o2.as().type()) + goto InvalidInstruction; + + if (o0.as().elementType() != opData.tA || + o1.as().elementType() != opData.tB || + o2.as().elementType() != opData.tB) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.vectorOp) << 10); + opcode.addImm(q, 30); + goto EmitOp_Rd0_Rn5_Rm16; + } + else { + if (!opData.elementOp) + goto InvalidInstruction; + + if (o0.as().type() != o1.as().type() || !o2.as().isVecV()) + goto InvalidInstruction; + + if (o0.as().elementType() != opData.tA || + o1.as().elementType() != opData.tB || + o2.as().elementType() != opData.tElement) + goto InvalidInstruction; + + uint32_t elementIndex = o2.as().elementIndex(); + LMHImm lmh; + + if (!encodeLMH(size, elementIndex, &lmh)) + goto InvalidElementIndex; + + if (o2.as().id() > lmh.maxRmId) + goto InvalidPhysId; + + opcode.reset(uint32_t(opData.elementOp) << 10); + opcode.addImm(q, 30); + opcode.addImm(lmh.lm, 20); + opcode.addImm(lmh.h, 11); + goto EmitOp_Rd0_Rn5_Rm16; + } + } + + break; + } + + case InstDB::kEncodingSimdDup: SimdDup: { + if (isign4 == ENC_OPS2(Reg, Reg)) { + // Truth table of valid encodings of `Q:1|ElementType:3` + uint32_t kValidEncodings = B(Vec::kElementTypeB + 0) | + B(Vec::kElementTypeH + 0) | + B(Vec::kElementTypeS + 0) | + B(Vec::kElementTypeB + 8) | + B(Vec::kElementTypeH + 8) | + B(Vec::kElementTypeS + 8) | + B(Vec::kElementTypeD + 8) ; + + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + + if (o1.as().isGp()) { + // DUP - Vec (scalar|vector) <- GP register. + // + // NOTE: This is only scalar for `dup d, x` case, otherwise the value + // would be duplicated across all vector elements (1, 2, 4, 8, or 16). + uint32_t elementType = o0.as().elementType(); + if (q > 1 || !Support::bitTest(kValidEncodings, (q << 3) | elementType)) + goto InvalidInstruction; + + uint32_t lsbIndex = elementType - 1u; + uint32_t imm5 = 1u << lsbIndex; + + opcode.reset(0b0000111000000000000011 << 10); + opcode.addImm(q, 30); + opcode.addImm(imm5, 16); + goto EmitOp_Rd0_Rn5; + } + + if (!o1.as().isVec() || !o1.as().hasElementIndex()) + goto InvalidInstruction; + + uint32_t dstIndex = o1.as().elementIndex(); + if (!o0.as().hasElementType()) { + // DUP - Vec (scalar) <- Vec[N]. + uint32_t lsbIndex = diff(o0.as().type(), RegType::kARM_VecB); + + if (lsbIndex != o1.as().elementType() - Vec::kElementTypeB || lsbIndex > 3) + goto InvalidInstruction; + + uint32_t imm5 = ((dstIndex << 1) | 1u) << lsbIndex; + if (imm5 > 31) + goto InvalidElementIndex; + + opcode.reset(0b0101111000000000000001 << 10); + opcode.addImm(imm5, 16); + goto EmitOp_Rd0_Rn5; + } + else { + // DUP - Vec (all) <- Vec[N]. + uint32_t elementType = o0.as().elementType(); + if (q > 1 || !Support::bitTest(kValidEncodings, (q << 3) | elementType)) + goto InvalidInstruction; + + uint32_t lsbIndex = elementType - 1u; + uint32_t imm5 = ((dstIndex << 1) | 1u) << lsbIndex; + + if (imm5 > 31) + goto InvalidElementIndex; + + opcode.reset(0b0000111000000000000001 << 10); + opcode.addImm(q, 30); + opcode.addImm(imm5, 16); + goto EmitOp_Rd0_Rn5; + } + } + + break; + } + + case InstDB::kEncodingSimdIns: SimdIns: { + if (isign4 == ENC_OPS2(Reg, Reg) && o0.as().isVecV()) { + if (!o0.as().hasElementIndex()) + goto InvalidInstruction; + + uint32_t elementType = o0.as().elementType(); + uint32_t dstIndex = o0.as().elementIndex(); + uint32_t lsbIndex = elementType - 1u; + + uint32_t imm5 = ((dstIndex << 1) | 1u) << lsbIndex; + if (imm5 > 31) + goto InvalidElementIndex; + + if (o1.as().isGp()) { + // INS - Vec[N] <- GP register. + opcode.reset(0b0100111000000000000111 << 10); + opcode.addImm(imm5, 16); + goto EmitOp_Rd0_Rn5; + } + else if (o1.as().isVecV() && o1.as().hasElementIndex()) { + // INS - Vec[N] <- Vec[M]. + if (o0.as().elementType() != o1.as().elementType()) + goto InvalidInstruction; + + uint32_t srcIndex = o1.as().elementIndex(); + if (o0.as().type() != o1.as().type()) + goto InvalidInstruction; + + uint32_t imm4 = srcIndex << lsbIndex; + if (imm4 > 15) + goto InvalidElementIndex; + + opcode.reset(0b0110111000000000000001 << 10); + opcode.addImm(imm5, 16); + opcode.addImm(imm4, 11); + goto EmitOp_Rd0_Rn5; + } + } + + break; + } + + case InstDB::kEncodingSimdMov: { + if (isign4 == ENC_OPS2(Reg, Reg)) { + if (o0.as().isVec() && o1.as().isVec()) { + // INS v.x[index], v.x[index]. + if (o0.as().hasElementIndex() && o1.as().hasElementIndex()) + goto SimdIns; + + // DUP {b|h|s|d}, v.{b|h|s|d}[index]. + if (o1.as().hasElementIndex()) + goto SimdDup; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + // ORR Vd, Vn, Vm + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + opcode.reset(0b0000111010100000000111 << 10); + opcode.addImm(q, 30); + opcode.addReg(o1, 16); // Vn == Vm. + goto EmitOp_Rd0_Rn5; + } + + if (o0.as().isVec() && o1.as().isGp()) { + // INS v.x[index], Rn. + if (o0.as().hasElementIndex()) + goto SimdIns; + + goto InvalidInstruction; + } + + if (o0.as().isGp() && o1.as().isVec()) { + // UMOV Rd, V.{s|d}[index]. + encodingIndex = 1; + goto SimdUmov; + } + } + + break; + } + + case InstDB::kEncodingSimdMoviMvni: { + const InstDB::EncodingData::SimdMoviMvni& opData = InstDB::EncodingData::simdMoviMvni[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Imm) || isign4 == ENC_OPS3(Reg, Imm, Imm)) { + SizeOp sizeOp = armElementTypeToSizeOp(InstDB::kVO_V_Any, o0.as().type(), o0.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + uint64_t imm64 = o1.as().valueAs(); + uint32_t imm8 = 0; + uint32_t cmode = 0; + uint32_t inverted = opData.inverted; + uint32_t op = 0; + uint32_t shift = 0; + uint32_t shiftOp = uint32_t(ShiftOp::kLSL); + + if (sizeOp.size() == 3u) { + // The second immediate should not be present, however, we accept + // an immediate value of zero as some user code may still pass it. + if (o2.isImm() && o0.as().value() != 0) + goto InvalidImmediate; + + if (Utils::isByteMaskImm8(imm64)) { + imm8 = encodeImm64ByteMaskToImm8(imm64); + } + else { + // Change from D to S and from 64-bit imm to 32-bit imm if this + // is not a byte-mask pattern. + if ((imm64 >> 32) == (imm64 & 0xFFFFFFFFu)) { + imm64 &= 0xFFFFFFFFu; + sizeOp.decrementSize(); + } + else { + goto InvalidImmediate; + } + } + } + + if (sizeOp.size() < 3u) { + if (imm64 > 0xFFFFFFFFu) + goto InvalidImmediate; + imm8 = uint32_t(imm64); + + if (sizeOp.size() == 2) { + if ((imm8 >> 16) == (imm8 & 0xFFFFu)) { + imm8 >>= 16; + sizeOp.decrementSize(); + } + } + + if (sizeOp.size() == 1) { + if (imm8 > 0xFFFFu) + goto InvalidImmediate; + + if ((imm8 >> 8) == (imm8 & 0xFFu)) { + imm8 >>= 8; + sizeOp.decrementSize(); + } + } + + uint32_t maxShift = (8u << sizeOp.size()) - 8u; + if (o2.isImm()) { + if (imm8 > 0xFFu || o2.as().valueAs() > maxShift) + goto InvalidImmediate; + + shift = o2.as().valueAs(); + shiftOp = o2.as().predicate(); + } + else if (imm8) { + shift = Support::ctz(imm8) & ~0x7u; + imm8 >>= shift; + + if (imm8 > 0xFFu || shift > maxShift) + goto InvalidImmediate; + } + + if ((shift & 0x7u) != 0u) + goto InvalidImmediate; + } + + shift /= 8u; + + switch (sizeOp.size()) { + case 0: + if (shiftOp != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + if (inverted) { + imm8 = ~imm8 & 0xFFu; + inverted = 0; + } + + cmode = B(3) | B(2) | B(1); + break; + + case 1: + if (shiftOp != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + cmode = B(3) | (shift << 1); + op = inverted; + break; + + case 2: + if (shiftOp == uint32_t(ShiftOp::kLSL)) { + cmode = shift << 1; + } + else if (shiftOp == uint32_t(ShiftOp::kMSL)) { + if (shift == 0 || shift > 2) + goto InvalidImmediate; + cmode = B(3) | B(2) | (shift - 1u); + } + else { + goto InvalidImmediate; + } + + op = inverted; + break; + + case 3: + if (inverted) { + imm8 = ~imm8 & 0xFFu; + inverted = 0; + } + + op = 1; + cmode = B(3) | B(2) | B(1); + break; + } + + // The immediate value is split into ABC and DEFGH parts. + uint32_t abc = (imm8 >> 5) & 0x7u; + uint32_t defgh = imm8 & 0x1Fu; + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(sizeOp.q(), 30); + opcode.addImm(op, 29); + opcode.addImm(abc, 16); + opcode.addImm(cmode, 12); + opcode.addImm(defgh, 5); + goto EmitOp_Rd0; + } + + break; + } + + case InstDB::kEncodingSimdShift: { + const InstDB::EncodingData::SimdShift& opData = InstDB::EncodingData::simdShift[encodingIndex]; + + const Operand_& sop = significantSimdOp(o0, o1, instFlags); + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, sop.as().type(), sop.as().elementType()); + + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (isign4 == ENC_OPS3(Reg, Reg, Imm) && opData.immediateOp) { + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + if (o2.as().valueAs() > 63) + goto InvalidImmediate; + + uint32_t lsbShift = sizeOp.size() + 3u; + uint32_t lsbMask = (1u << lsbShift) - 1u; + uint32_t imm = o2.as().valueAs(); + + // Some instructions use IMM and some X - IMM, so negate if required. + if (opData.invertedImm) { + if (imm == 0 || imm > (1u << lsbShift)) + goto InvalidImmediate; + imm = Support::neg(imm) & lsbMask; + } + + if (imm > lsbMask) + goto InvalidImmediate; + imm |= (1u << lsbShift); + + opcode.reset(uint32_t(opData.immediateOp) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(imm, 16); + goto EmitOp_Rd0_Rn5; + } + + if (isign4 == ENC_OPS3(Reg, Reg, Reg) && opData.registerOp) { + if (!matchSignature(o0, o1, o2, instFlags)) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.registerOp) << 10); + opcode.addImm(sizeOp.qs(), 30); + opcode.addImm(sizeOp.scalar(), 28); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5_Rm16; + } + + break; + } + + case InstDB::kEncodingSimdShiftES: { + const InstDB::EncodingData::SimdShiftES& opData = InstDB::EncodingData::simdShiftES[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Imm)) { + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o1.as().type(), o1.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + // The immediate value must match the element size. + uint64_t shift = o2.as().valueAs(); + uint32_t shiftOp = o2.as().predicate(); + + if (shift != (8u << sizeOp.size()) || shiftOp != uint32_t(ShiftOp::kLSL)) + goto InvalidImmediate; + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(sizeOp.q(), 30); + opcode.addImm(sizeOp.size(), 22); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdSm3tt: { + const InstDB::EncodingData::SimdSm3tt& opData = InstDB::EncodingData::simdSm3tt[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg)) { + if (o0.as().isVecS4() && o1.as().isVecS4() && o2.as().isVecS4() && o2.as().hasElementIndex()) { + uint32_t imm2 = o2.as().elementIndex(); + if (imm2 > 3) + goto InvalidElementIndex; + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(imm2, 12); + goto EmitOp_Rd0_Rn5_Rm16; + } + } + + break; + } + + + case InstDB::kEncodingSimdSmovUmov: SimdUmov: { + const InstDB::EncodingData::SimdSmovUmov& opData = InstDB::EncodingData::simdSmovUmov[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg) && o0.as().isGp() && o1.as().isVec()) { + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o1.as().type(), o1.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (!o1.as().hasElementIndex()) + goto InvalidInstruction; + + uint32_t x = o0.as().isGpX(); + uint32_t gpMustBeX = uint32_t(sizeOp.size() >= 3u - opData.isSigned); + + if (opData.isSigned) { + if (gpMustBeX && !x) + goto InvalidInstruction; + } + else { + if (x != gpMustBeX) + goto InvalidInstruction; + } + + uint32_t elementIndex = o1.as().elementIndex(); + uint32_t maxElementIndex = 15u >> sizeOp.size(); + + if (elementIndex > maxElementIndex) + goto InvalidElementIndex; + + uint32_t imm5 = (1u | (elementIndex << 1)) << sizeOp.size(); + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(x, 30); + opcode.addImm(imm5, 16); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdSxtlUxtl: { + const InstDB::EncodingData::SimdSxtlUxtl& opData = InstDB::EncodingData::simdSxtlUxtl[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Reg)) { + SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o1.as().type(), o1.as().elementType()); + if (!sizeOp.isValid()) + goto InvalidInstruction; + + if (!matchSignature(o0, o1, instFlags)) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(sizeOp.q(), 30); + opcode.addImm(1u, sizeOp.size() + 19); + goto EmitOp_Rd0_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdTblTbx: { + const InstDB::EncodingData::SimdTblTbx& opData = InstDB::EncodingData::simdTblTbx[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Reg) || isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { + // TBL/TBX ., { .16B }, . + // TBL/TBX ., { .16B, .16B }, . + // TBL/TBX ., { .16B, .16B, .16B }, . + // TBL/TBX ., { .16B, .16B, .16B, .16B }, . + opcode.reset(uint32_t(opData.opcode) << 10); + + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + const Operand_& o5 = opExt[EmitterUtils::kOp5]; + + uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); + if (q > 1 || o0.as().hasElementIndex()) + goto InvalidInstruction; + + if (!o1.as().isVecB16() || o1.as().hasElementIndex()) + goto InvalidInstruction; + + uint32_t len = uint32_t(!o3.isNone()) + uint32_t(!o4.isNone()) + uint32_t(!o5.isNone()); + opcode.addImm(q, 30); + opcode.addImm(len, 13); + + switch (len) { + case 0: + if (!checkSignature(o0, o2)) + goto InvalidInstruction; + + if (o2.id() > 31) + goto InvalidPhysId; + + opcode.addReg(o2, 16); + goto EmitOp_Rd0_Rn5; + + case 1: + if (!checkSignature(o0, o3)) + goto InvalidInstruction; + + if (o3.id() > 31) + goto InvalidPhysId; + + opcode.addReg(o3, 16); + goto EmitOp_Rd0_Rn5; + + case 2: + if (!checkSignature(o0, o4)) + goto InvalidInstruction; + + if (o4.id() > 31) + goto InvalidPhysId; + + opcode.addReg(o4, 16); + goto EmitOp_Rd0_Rn5; + + case 3: + if (!checkSignature(o0, o5)) + goto InvalidInstruction; + + if (o5.id() > 31) + goto InvalidPhysId; + + opcode.addReg(o5, 16); + goto EmitOp_Rd0_Rn5; + + default: + // Should never happen. + goto InvalidInstruction; + } + } + + break; + } + + // ------------------------------------------------------------------------ + // [Simd - Load / Store] + // ------------------------------------------------------------------------ + + case InstDB::kEncodingSimdLdSt: { + const InstDB::EncodingData::SimdLdSt& opData = InstDB::EncodingData::simdLdSt[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + rmRel = &m; + + // Width | SZ | XY | XSZ + // -------+----------+-----------+----- + // 8-bit | size==00 | opc == 01 | 000 + // 16-bit | size==01 | opc == 01 | 001 + // 32-bit | size==10 | opc == 01 | 010 + // 64-bit | size==11 | opc == 01 | 011 + // 128-bit| size==00 | opc == 11 | 100 + uint32_t xsz = diff(o0.as().type(), RegType::kARM_VecB); + if (xsz > 4u || o0.as().hasElementIndex()) + goto InvalidRegType; + + if (!checkVecId(o0)) + goto InvalidPhysId; + + if (!armCheckMemBaseIndexRel(m)) + goto InvalidAddress; + + int64_t offset = m.offset(); + if (m.hasBaseReg()) { + // [Base {Offset | Index}] + if (m.hasIndex()) { + uint32_t opt = armShiftOpToLdStOptMap[m.predicate()]; + if (opt == 0xFFu) + goto InvalidAddress; + + uint32_t shift = m.shift(); + uint32_t s = (shift != 0); + + if (s && shift != xsz) + goto InvalidAddressScale; + + opcode.reset(uint32_t(opData.registerOp) << 21); + opcode.addImm(xsz & 3u, 30); + opcode.addImm(xsz >> 2, 23); + opcode.addImm(opt, 13); + opcode.addImm(s, 12); + opcode |= B(11); + opcode.addReg(o0, 0); + goto EmitOp_MemBaseIndex_Rn5_Rm16; + } + + // Makes it easier to work with the offset especially on 32-bit arch. + if (!Support::isInt32(offset)) + goto InvalidDisplacement; + int32_t offset32 = int32_t(offset); + + if (m.isPreOrPost()) { + if (!Support::isInt9(offset32)) + goto InvalidDisplacement; + + opcode.reset(uint32_t(opData.prePostOp) << 21); + opcode.addImm(xsz & 3u, 30); + opcode.addImm(xsz >> 2, 23); + opcode.addImm(offset32 & 0x1FF, 12); + opcode.addImm(m.isPreIndex(), 11); + opcode |= B(10); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + else { + uint32_t imm12 = uint32_t(offset32) >> xsz; + + // If this instruction is not encodable with scaled unsigned offset, try unscaled signed offset. + if (!Support::isUInt12(imm12) || (imm12 << xsz) != uint32_t(offset32)) { + instId = opData.uAltInstId; + instInfo = &InstDB::_instInfoTable[instId]; + encodingIndex = instInfo->_encodingDataIndex; + goto Case_SimdLdurStur; + } + + opcode.reset(uint32_t(opData.uOffsetOp) << 22); + opcode.addImm(xsz & 3u, 30); + opcode.addImm(xsz >> 2, 23); + opcode.addImm(imm12, 10); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + } + else { + if (!opData.literalOp) + goto InvalidAddress; + + if (xsz < 2u) + goto InvalidRegType; + + uint32_t opc = xsz - 2u; + opcode.reset(uint32_t(opData.literalOp) << 24); + opcode.addImm(opc, 30); + opcode.addReg(o0, 0); + offsetFormat.resetToImmValue(OffsetType::kSignedOffset, 4, 5, 19, 2); + goto EmitOp_Rel; + } + } + + break; + } + + case InstDB::kEncodingSimdLdpStp: { + const InstDB::EncodingData::SimdLdpStp& opData = InstDB::EncodingData::simdLdpStp[encodingIndex]; + + if (isign4 == ENC_OPS3(Reg, Reg, Mem)) { + const Mem& m = o2.as(); + rmRel = &m; + + uint32_t opc = diff(o0.as().type(), RegType::kARM_VecS); + if (opc > 2u || o0.as().hasElementTypeOrIndex()) + goto InvalidInstruction; + + if (!checkSignature(o0, o1)) + goto InvalidInstruction; + + if (!checkVecId(o0, o1)) + goto InvalidPhysId; + + if (m.baseType() != RegType::kARM_GpX || m.hasIndex()) + goto InvalidAddress; + + if (m.isOffset64Bit()) + goto InvalidDisplacement; + + uint32_t offsetShift = 2u + opc; + int32_t offset32 = m.offsetLo32() >> offsetShift; + + // Make sure we didn't lose bits by applying the mandatory offset shift. + if (Support::shl(offset32, offsetShift) != m.offsetLo32()) + goto InvalidDisplacement; + + // Offset is encoded as a 7-bit immediate. + if (!Support::isInt7(offset32)) + goto InvalidDisplacement; + + if (m.isPreOrPost() && offset32 != 0) { + if (!opData.prePostOp) + goto InvalidAddress; + + opcode.reset(uint32_t(opData.prePostOp) << 22); + opcode.addImm(m.isPreIndex(), 24); + } + else { + opcode.reset(uint32_t(opData.offsetOp) << 22); + } + + opcode.addImm(opc, 30); + opcode.addImm(offset32 & 0x7F, 15); + opcode.addReg(o1, 10); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + + break; + } + + case InstDB::kEncodingSimdLdurStur: { +Case_SimdLdurStur: + const InstDB::EncodingData::SimdLdurStur& opData = InstDB::EncodingData::simdLdurStur[encodingIndex]; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + const Mem& m = o1.as(); + rmRel = &m; + + uint32_t sz = diff(o0.as().type(), RegType::kARM_VecB); + if (sz > 4 || o0.as().hasElementTypeOrIndex()) + goto InvalidInstruction; + + if (!checkVecId(o0)) + goto InvalidPhysId; + + if (!armCheckMemBaseIndexRel(m)) + goto InvalidAddress; + + if (m.hasBaseReg() && !m.hasIndex() && !m.isPreOrPost()) { + if (m.isOffset64Bit()) + goto InvalidDisplacement; + + int32_t offset32 = m.offsetLo32(); + if (!Support::isInt9(offset32)) + goto InvalidDisplacement; + + opcode.reset(uint32_t(opData.opcode) << 10); + opcode.addImm(sz & 3u, 30); + opcode.addImm(sz >> 2, 23); + opcode.addImm(offset32 & 0x1FF, 12); + opcode.addReg(o0, 0); + goto EmitOp_MemBase_Rn5; + } + + goto InvalidAddress; + } + + break; + } + + case InstDB::kEncodingSimdLdNStN: { + const InstDB::EncodingData::SimdLdNStN& opData = InstDB::EncodingData::simdLdNStN[encodingIndex]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + + uint32_t n = 1; + + if (isign4 == ENC_OPS2(Reg, Mem)) { + if (opData.n != 1) + goto InvalidInstruction; + + rmRel = &o1; + } + else if (isign4 == ENC_OPS3(Reg, Reg, Mem)) { + if (opData.n != 1 && opData.n != 2) + goto InvalidInstruction; + + if (!checkSignature(o0, o1) || !checkConsecutive(o0, o1)) + goto InvalidInstruction; + + n = 2; + rmRel = &o2; + } + else if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem) && o4.isNone()) { + if (opData.n != 1 && opData.n != 3) + goto InvalidInstruction; + + if (!checkSignature(o0, o1, o2) || !checkConsecutive(o0, o1, o2)) + goto InvalidInstruction; + + n = 3; + rmRel = &o3; + } + else if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg) && o4.isMem()) { + if (opData.n != 1 && opData.n != 4) + goto InvalidInstruction; + + if (!checkSignature(o0, o1, o2, o3) || !checkConsecutive(o0, o1, o2, o3)) + goto InvalidInstruction; + + n = 4; + rmRel = &o4; + } + else { + goto InvalidInstruction; + } + + // We will use `v` and `m` from now as those are relevant for encoding. + const Vec& v = o0.as(); + const Mem& m = rmRel->as(); + + uint32_t q = 0; + uint32_t rm = 0; + uint32_t rn = m.baseId(); + uint32_t sz = v.elementType() - Vec::kElementTypeB; + uint32_t opcSsize = sz; + uint32_t offsetPossibility = 0; + + if (sz > 3) + goto InvalidInstruction; + + if (m.baseType() != RegType::kARM_GpX) + goto InvalidAddress; + + // Rn cannot be ZR, but can be SP. + if (rn > 30 && rn != Gp::kIdSp) + goto InvalidAddress; + + rn &= 31; + + if (opData.replicate) { + if (n != opData.n) + goto InvalidInstruction; + + // Replicates to the whole register, element index cannot be used. + if (v.hasElementIndex()) + goto InvalidInstruction; + + q = diff(v.type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + opcode.reset(uint32_t(opData.singleOp) << 10); + offsetPossibility = (1u << sz) * n; + } + else if (v.hasElementIndex()) { + if (n != opData.n) + goto InvalidInstruction; + + // LDx/STx (single structure). + static const uint8_t opcSsizeBySzS[] = { 0x0u << 3, 0x2u << 3, 0x4u << 3, (0x4u << 3) | 1u }; + + opcode.reset(uint32_t(opData.singleOp) << 10); + opcSsize = opcSsizeBySzS[sz]; + offsetPossibility = (1u << sz) * opData.n; + + uint32_t elementIndex = v.elementIndex(); + uint32_t maxElementIndex = 15 >> sz; + + if (elementIndex > maxElementIndex) + goto InvalidElementIndex; + + elementIndex <<= sz; + q = elementIndex >> 3; + opcSsize |= elementIndex & 0x7u; + } + else { + // LDx/STx (multiple structures). + static const uint8_t opcSsizeByN[] = { 0u, 0x7u << 2, 0xAu << 2, 0x6u << 2, 0x2u << 2 }; + + q = diff(v.type(), RegType::kARM_VecD); + if (q > 1) + goto InvalidInstruction; + + if (opData.n == 1) + opcSsize |= opcSsizeByN[n]; + + opcode.reset(uint32_t(opData.multipleOp) << 10); + offsetPossibility = (8u << q) * n; + } + + if (m.hasIndex()) { + if (m.hasOffset() || !m.isPostIndex()) + goto InvalidAddress; + + rm = m.indexId(); + if (rm > 30) + goto InvalidAddress; + + // Bit 23 - PostIndex. + opcode |= B(23); + } + else { + if (m.hasOffset()) { + if (m.offset() != int32_t(offsetPossibility) || !m.isPostIndex()) + goto InvalidAddress; + rm = 31; + + // Bit 23 - PostIndex. + opcode |= B(23); + } + } + + opcode.addImm(q, 30); + opcode.addImm(rm, 16); + opcode.addImm(opcSsize, 10); + opcode.addImm(rn, 5); + goto EmitOp_Rd0; + } + + default: + break; + } + + goto InvalidInstruction; + + // -------------------------------------------------------------------------- + // [EmitGp - Single] + // -------------------------------------------------------------------------- + +EmitOp_Rd0: + if (!checkValidRegs(o0)) + goto InvalidPhysId; + + opcode.addReg(o0, 0); + goto EmitOp; + +EmitOp_Rn5: + if (!checkValidRegs(o0)) + goto InvalidPhysId; + + opcode.addReg(o0, 5); + goto EmitOp; + +EmitOp_Rn5_Rm16: + if (!checkValidRegs(o0, o1)) + goto InvalidPhysId; + + opcode.addReg(o0, 5); + opcode.addReg(o1, 16); + goto EmitOp; + +EmitOp_Rd0_Rn5: + if (!checkValidRegs(o0, o1)) + goto InvalidPhysId; + + opcode.addReg(o0, 0); + opcode.addReg(o1, 5); + goto EmitOp; + +EmitOp_Rd0_Rn5_Rm16_Ra10: + if (!checkValidRegs(o0, o1, o2, o3)) + goto InvalidPhysId; + + opcode.addReg(o0, 0); + opcode.addReg(o1, 5); + opcode.addReg(o2, 16); + opcode.addReg(o3, 10); + goto EmitOp; + +EmitOp_Rd0_Rn5_Rm16: + if (!checkValidRegs(o0, o1, o3)) + goto InvalidPhysId; + + opcode.addReg(o0, 0); + opcode.addReg(o1, 5); + opcode.addReg(o2, 16); + goto EmitOp; + + // -------------------------------------------------------------------------- + // [EmitGp - Multiple] + // -------------------------------------------------------------------------- + +EmitOp_Multiple: + { + ASMJIT_ASSERT(multipleOpCount > 0); + err = writer.ensureSpace(this, multipleOpCount * 4u); + if (ASMJIT_UNLIKELY(err)) + goto Failed; + + for (uint32_t i = 0; i < multipleOpCount; i++) + writer.emit32uLE(multipleOpData[i]); + + goto EmitDone; + } + + // -------------------------------------------------------------------------- + // [EmitGp - Memory] + // -------------------------------------------------------------------------- + +EmitOp_MemBase_Rn5: + if (!checkMemBase(rmRel->as())) + goto InvalidAddress; + + opcode.addReg(rmRel->as().baseId(), 5); + goto EmitOp; + +EmitOp_MemBaseNoImm_Rn5: + if (!checkMemBase(rmRel->as()) || rmRel->as().hasIndex()) + goto InvalidAddress; + + if (rmRel->as().hasOffset()) + goto InvalidDisplacement; + + opcode.addReg(rmRel->as().baseId(), 5); + goto EmitOp; + +EmitOp_MemBaseIndex_Rn5_Rm16: + if (!rmRel->as().hasBaseReg()) + goto InvalidAddress; + + if (rmRel->as().indexId() > 30 && rmRel->as().indexId() != Gp::kIdZr) + goto InvalidPhysId; + + opcode.addReg(rmRel->as().indexId(), 16); + opcode.addReg(rmRel->as().baseId(), 5); + goto EmitOp; + + // -------------------------------------------------------------------------- + // [EmitOp - PC Relative] + // -------------------------------------------------------------------------- + +EmitOp_Rel: + { + if (rmRel->isLabel() || rmRel->isMem()) { + uint32_t labelId; + int64_t labelOffset = 0; + + if (rmRel->isLabel()) { + labelId = rmRel->as