mirror of
https://github.com/MariaDB/server.git
synced 2025-06-22 08:22:01 +03:00
8.41
This commit is contained in:
@ -191,7 +191,7 @@ IF (MINGW)
|
||||
ENDIF(MINGW)
|
||||
|
||||
IF(MSVC)
|
||||
OPTION(PCRE_STATIC_RUNTIME OFF CACHE BOOL
|
||||
OPTION(PCRE_STATIC_RUNTIME
|
||||
"ON=Compile against the static runtime (/MT)."
|
||||
OFF)
|
||||
OPTION(INSTALL_MSVC_PDB
|
||||
|
@ -4,6 +4,53 @@ ChangeLog for PCRE
|
||||
Note that the PCRE 8.xx series (PCRE1) is now in a bugfix-only state. All
|
||||
development is happening in the PCRE2 10.xx series.
|
||||
|
||||
Version 8.41 05-July-2017
|
||||
-------------------------
|
||||
|
||||
1. Fixed typo in CMakeLists.txt (wrong number of arguments for
|
||||
PCRE_STATIC_RUNTIME (affects MSVC only).
|
||||
|
||||
2. Issue 1 for 8.40 below was not correctly fixed. If pcregrep in multiline
|
||||
mode with --only-matching matched several lines, it restarted scanning at the
|
||||
next line instead of moving on to the end of the matched string, which can be
|
||||
several lines after the start.
|
||||
|
||||
3. Fix a missing else in the JIT compiler reported by 'idaifish'.
|
||||
|
||||
4. A (?# style comment is now ignored between a basic quantifier and a
|
||||
following '+' or '?' (example: /X+(?#comment)?Y/.
|
||||
|
||||
5. Avoid use of a potentially overflowing buffer in pcregrep (patch by Petr
|
||||
Pisar).
|
||||
|
||||
6. Fuzzers have reported issues in pcretest. These are NOT serious (it is,
|
||||
after all, just a test program). However, to stop the reports, some easy ones
|
||||
are fixed:
|
||||
|
||||
(a) Check for values < 256 when calling isprint() in pcretest.
|
||||
(b) Give an error for too big a number after \O.
|
||||
|
||||
7. In the 32-bit library in non-UTF mode, an attempt to find a Unicode
|
||||
property for a character with a code point greater than 0x10ffff (the Unicode
|
||||
maximum) caused a crash.
|
||||
|
||||
8. The alternative matching function, pcre_dfa_exec() misbehaved if it
|
||||
encountered a character class with a possessive repeat, for example [a-f]{3}+.
|
||||
|
||||
9. When pcretest called pcre_copy_substring() in 32-bit mode, it set the buffer
|
||||
length incorrectly, which could result in buffer overflow.
|
||||
|
||||
10. Remove redundant line of code (accidentally left in ages ago).
|
||||
|
||||
11. Applied C++ patch from Irfan Adilovic to guard 'using std::' directives
|
||||
with namespace pcrecpp (Bugzilla #2084).
|
||||
|
||||
12. Remove a duplication typo in pcre_tables.c.
|
||||
|
||||
13. Fix returned offsets from regexec() when REG_STARTEND is used with a
|
||||
starting offset greater than zero.
|
||||
|
||||
|
||||
Version 8.40 11-January-2017
|
||||
----------------------------
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
News about PCRE releases
|
||||
------------------------
|
||||
|
||||
Release 8.41 13-June-2017
|
||||
-------------------------
|
||||
|
||||
This is a bug-fix release.
|
||||
|
||||
|
||||
Release 8.40 11-January-2017
|
||||
----------------------------
|
||||
|
||||
|
10
pcre/aclocal.m4
vendored
10
pcre/aclocal.m4
vendored
@ -20,9 +20,9 @@ You have another version of autoconf. It may work, but is not guaranteed to.
|
||||
If you have problems, you may need to regenerate the build system entirely.
|
||||
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
|
||||
|
||||
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
dnl serial 11 (pkg-config-0.29.1)
|
||||
dnl
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 12 (pkg-config-0.29.2)
|
||||
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
@ -63,7 +63,7 @@ dnl
|
||||
dnl See the "Since" comment for each macro you use to see what version
|
||||
dnl of the macros you require.
|
||||
m4_defun([PKG_PREREQ],
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29.1])
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29.2])
|
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||
])dnl PKG_PREREQ
|
||||
@ -164,7 +164,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||
|
||||
pkg_failed=no
|
||||
AC_MSG_CHECKING([for $1])
|
||||
AC_MSG_CHECKING([for $2])
|
||||
|
||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||
|
@ -235,7 +235,7 @@ sure both macros are undefined; an emulation function will then be used. */
|
||||
#define PACKAGE_NAME "PCRE"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "PCRE 8.40"
|
||||
#define PACKAGE_STRING "PCRE 8.41"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "pcre"
|
||||
@ -244,7 +244,7 @@ sure both macros are undefined; an emulation function will then be used. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "8.40"
|
||||
#define PACKAGE_VERSION "8.41"
|
||||
|
||||
/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested
|
||||
parentheses (of any kind) in a pattern. This limits the amount of system
|
||||
@ -336,7 +336,7 @@ sure both macros are undefined; an emulation function will then be used. */
|
||||
/* #undef SUPPORT_VALGRIND */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "8.40"
|
||||
#define VERSION "8.41"
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
36
pcre/configure
vendored
36
pcre/configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for PCRE 8.40.
|
||||
# Generated by GNU Autoconf 2.69 for PCRE 8.41.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@ -587,8 +587,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='PCRE'
|
||||
PACKAGE_TARNAME='pcre'
|
||||
PACKAGE_VERSION='8.40'
|
||||
PACKAGE_STRING='PCRE 8.40'
|
||||
PACKAGE_VERSION='8.41'
|
||||
PACKAGE_STRING='PCRE 8.41'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@ -1418,7 +1418,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures PCRE 8.40 to adapt to many kinds of systems.
|
||||
\`configure' configures PCRE 8.41 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1488,7 +1488,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of PCRE 8.40:";;
|
||||
short | recursive ) echo "Configuration of PCRE 8.41:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1662,7 +1662,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
PCRE configure 8.40
|
||||
PCRE configure 8.41
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@ -2419,7 +2419,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by PCRE $as_me 8.40, which was
|
||||
It was created by PCRE $as_me 8.41, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@ -3283,7 +3283,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='pcre'
|
||||
VERSION='8.40'
|
||||
VERSION='8.41'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@ -17634,9 +17634,9 @@ _ACEOF
|
||||
# Versioning
|
||||
|
||||
PCRE_MAJOR="8"
|
||||
PCRE_MINOR="40"
|
||||
PCRE_MINOR="41"
|
||||
PCRE_PRERELEASE=""
|
||||
PCRE_DATE="2017-01-11"
|
||||
PCRE_DATE="2017-07-05"
|
||||
|
||||
if test "$PCRE_MINOR" = "08" -o "$PCRE_MINOR" = "09"
|
||||
then
|
||||
@ -19658,16 +19658,16 @@ esac
|
||||
# (Note: The libpcre*_version bits are m4 variables, assigned above)
|
||||
|
||||
EXTRA_LIBPCRE_LDFLAGS="$EXTRA_LIBPCRE_LDFLAGS \
|
||||
$NO_UNDEFINED -version-info 3:8:2"
|
||||
$NO_UNDEFINED -version-info 3:9:2"
|
||||
|
||||
EXTRA_LIBPCRE16_LDFLAGS="$EXTRA_LIBPCRE16_LDFLAGS \
|
||||
$NO_UNDEFINED -version-info 2:8:2"
|
||||
$NO_UNDEFINED -version-info 2:9:2"
|
||||
|
||||
EXTRA_LIBPCRE32_LDFLAGS="$EXTRA_LIBPCRE32_LDFLAGS \
|
||||
$NO_UNDEFINED -version-info 0:8:0"
|
||||
$NO_UNDEFINED -version-info 0:9:0"
|
||||
|
||||
EXTRA_LIBPCREPOSIX_LDFLAGS="$EXTRA_LIBPCREPOSIX_LDFLAGS \
|
||||
$NO_UNDEFINED -version-info 0:4:0"
|
||||
$NO_UNDEFINED -version-info 0:5:0"
|
||||
|
||||
EXTRA_LIBPCRECPP_LDFLAGS="$EXTRA_LIBPCRECPP_LDFLAGS \
|
||||
$NO_UNDEFINED -version-info 0:1:0 \
|
||||
@ -19872,8 +19872,8 @@ $as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND" >&5
|
||||
$as_echo_n "checking for VALGRIND... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for valgrind" >&5
|
||||
$as_echo_n "checking for valgrind... " >&6; }
|
||||
|
||||
if test -n "$VALGRIND_CFLAGS"; then
|
||||
pkg_cv_VALGRIND_CFLAGS="$VALGRIND_CFLAGS"
|
||||
@ -20719,7 +20719,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by PCRE $as_me 8.40, which was
|
||||
This file was extended by PCRE $as_me 8.41, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -20785,7 +20785,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
PCRE config.status 8.40
|
||||
PCRE config.status 8.41
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
@ -9,18 +9,18 @@ dnl The PCRE_PRERELEASE feature is for identifying release candidates. It might
|
||||
dnl be defined as -RC2, for example. For real releases, it should be empty.
|
||||
|
||||
m4_define(pcre_major, [8])
|
||||
m4_define(pcre_minor, [40])
|
||||
m4_define(pcre_minor, [41])
|
||||
m4_define(pcre_prerelease, [])
|
||||
m4_define(pcre_date, [2017-01-11])
|
||||
m4_define(pcre_date, [2017-07-05])
|
||||
|
||||
# NOTE: The CMakeLists.txt file searches for the above variables in the first
|
||||
# 50 lines of this file. Please update that if the variables above are moved.
|
||||
|
||||
# Libtool shared library interface versions (current:revision:age)
|
||||
m4_define(libpcre_version, [3:8:2])
|
||||
m4_define(libpcre16_version, [2:8:2])
|
||||
m4_define(libpcre32_version, [0:8:0])
|
||||
m4_define(libpcreposix_version, [0:4:0])
|
||||
m4_define(libpcre_version, [3:9:2])
|
||||
m4_define(libpcre16_version, [2:9:2])
|
||||
m4_define(libpcre32_version, [0:9:0])
|
||||
m4_define(libpcreposix_version, [0:5:0])
|
||||
m4_define(libpcrecpp_version, [0:1:0])
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
|
@ -79,9 +79,12 @@ API that is JIT-specific.
|
||||
</P>
|
||||
<P>
|
||||
If your program may sometimes be linked with versions of PCRE that are older
|
||||
than 8.20, but you want to use JIT when it is available, you can test
|
||||
the values of PCRE_MAJOR and PCRE_MINOR, or the existence of a JIT macro such
|
||||
as PCRE_CONFIG_JIT, for compile-time control of your code.
|
||||
than 8.20, but you want to use JIT when it is available, you can test the
|
||||
values of PCRE_MAJOR and PCRE_MINOR, or the existence of a JIT macro such as
|
||||
PCRE_CONFIG_JIT, for compile-time control of your code. Also beware that the
|
||||
<b>pcre_jit_exec()</b> function was not available at all before 8.32,
|
||||
and may not be available at all if PCRE isn't compiled with
|
||||
--enable-jit. See the "JIT FAST PATH API" section below for details.
|
||||
</P>
|
||||
<br><a name="SEC4" href="#TOC1">SIMPLE USE OF JIT</a><br>
|
||||
<P>
|
||||
@ -119,6 +122,20 @@ when you call <b>pcre_study()</b>:
|
||||
PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE
|
||||
PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
|
||||
</pre>
|
||||
If using <b>pcre_jit_exec()</b> and supporting a pre-8.32 version of
|
||||
PCRE, you can insert:
|
||||
<pre>
|
||||
#if PCRE_MAJOR >= 8 && PCRE_MINOR >= 32
|
||||
pcre_jit_exec(...);
|
||||
#else
|
||||
pcre_exec(...)
|
||||
#endif
|
||||
</pre>
|
||||
but as described in the "JIT FAST PATH API" section below this assumes
|
||||
version 8.32 and later are compiled with --enable-jit, which may
|
||||
break.
|
||||
<br>
|
||||
<br>
|
||||
The JIT compiler generates different optimized code for each of the three
|
||||
modes (normal, soft partial, hard partial). When <b>pcre_exec()</b> is called,
|
||||
the appropriate code is run if it is available. Otherwise, the pattern is
|
||||
@ -428,6 +445,36 @@ fast path, and if invalid data is passed, the result is undefined.
|
||||
Bypassing the sanity checks and the <b>pcre_exec()</b> wrapping can give
|
||||
speedups of more than 10%.
|
||||
</P>
|
||||
<P>
|
||||
Note that the <b>pcre_jit_exec()</b> function is not available in versions of
|
||||
PCRE before 8.32 (released in November 2012). If you need to support versions
|
||||
that old you must either use the slower <b>pcre_exec()</b>, or switch between
|
||||
the two codepaths by checking the values of PCRE_MAJOR and PCRE_MINOR.
|
||||
</P>
|
||||
<P>
|
||||
Due to an unfortunate implementation oversight, even in versions 8.32
|
||||
and later there will be no <b>pcre_jit_exec()</b> stub function defined
|
||||
when PCRE is compiled with --disable-jit, which is the default, and
|
||||
there's no way to detect whether PCRE was compiled with --enable-jit
|
||||
via a macro.
|
||||
</P>
|
||||
<P>
|
||||
If you need to support versions older than 8.32, or versions that may
|
||||
not build with --enable-jit, you must either use the slower
|
||||
<b>pcre_exec()</b>, or switch between the two codepaths by checking the
|
||||
values of PCRE_MAJOR and PCRE_MINOR.
|
||||
</P>
|
||||
<P>
|
||||
Switching between the two by checking the version assumes that all the
|
||||
versions being targeted are built with --enable-jit. To also support
|
||||
builds that may use --disable-jit either <b>pcre_exec()</b> must be
|
||||
used, or a compile-time check for JIT via <b>pcre_config()</b> (which
|
||||
assumes the runtime environment will be the same), or as the Git
|
||||
project decided to do, simply assume that <b>pcre_jit_exec()</b> is
|
||||
present in 8.32 or later unless a compile-time flag is provided, see
|
||||
the "grep: un-break building with PCRE >= 8.32 without --enable-jit"
|
||||
commit in git.git for an example of that.
|
||||
</P>
|
||||
<br><a name="SEC12" href="#TOC1">SEE ALSO</a><br>
|
||||
<P>
|
||||
<b>pcreapi</b>(3)
|
||||
@ -443,9 +490,9 @@ Cambridge CB2 3QH, England.
|
||||
</P>
|
||||
<br><a name="SEC14" href="#TOC1">REVISION</a><br>
|
||||
<P>
|
||||
Last updated: 17 March 2013
|
||||
Last updated: 05 July 2017
|
||||
<br>
|
||||
Copyright © 1997-2013 University of Cambridge.
|
||||
Copyright © 1997-2017 University of Cambridge.
|
||||
<br>
|
||||
<p>
|
||||
Return to the <a href="index.html">PCRE index page</a>.
|
||||
|
@ -74,6 +74,11 @@ newline as data characters. However, in some Windows environments character 26
|
||||
maximum portability, therefore, it is safest to use only ASCII characters in
|
||||
<b>pcretest</b> input files.
|
||||
</P>
|
||||
<P>
|
||||
The input is processed using using C's string functions, so must not
|
||||
contain binary zeroes, even though in Unix-like environments, <b>fgets()</b>
|
||||
treats any bytes other than newline as data characters.
|
||||
</P>
|
||||
<br><a name="SEC3" href="#TOC1">PCRE's 8-BIT, 16-BIT AND 32-BIT LIBRARIES</a><br>
|
||||
<P>
|
||||
From release 8.30, two separate PCRE libraries can be built. The original one
|
||||
@ -1149,9 +1154,9 @@ Cambridge CB2 3QH, England.
|
||||
</P>
|
||||
<br><a name="SEC17" href="#TOC1">REVISION</a><br>
|
||||
<P>
|
||||
Last updated: 09 February 2014
|
||||
Last updated: 23 February 2017
|
||||
<br>
|
||||
Copyright © 1997-2014 University of Cambridge.
|
||||
Copyright © 1997-2017 University of Cambridge.
|
||||
<br>
|
||||
<p>
|
||||
Return to the <a href="index.html">PCRE index page</a>.
|
||||
|
@ -8366,6 +8366,10 @@ AVAILABILITY OF JIT SUPPORT
|
||||
older than 8.20, but you want to use JIT when it is available, you can
|
||||
test the values of PCRE_MAJOR and PCRE_MINOR, or the existence of a JIT
|
||||
macro such as PCRE_CONFIG_JIT, for compile-time control of your code.
|
||||
Also beware that the pcre_jit_exec() function was not available at all
|
||||
before 8.32, and may not be available at all if PCRE isn't compiled
|
||||
with --enable-jit. See the "JIT FAST PATH API" section below for
|
||||
details.
|
||||
|
||||
|
||||
SIMPLE USE OF JIT
|
||||
@ -8407,6 +8411,18 @@ SIMPLE USE OF JIT
|
||||
PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE
|
||||
PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
|
||||
|
||||
If using pcre_jit_exec() and supporting a pre-8.32 version of PCRE, you
|
||||
can insert:
|
||||
|
||||
#if PCRE_MAJOR >= 8 && PCRE_MINOR >= 32
|
||||
pcre_jit_exec(...);
|
||||
#else
|
||||
pcre_exec(...)
|
||||
#endif
|
||||
|
||||
but as described in the "JIT FAST PATH API" section below this assumes
|
||||
version 8.32 and later are compiled with --enable-jit, which may break.
|
||||
|
||||
The JIT compiler generates different optimized code for each of the
|
||||
three modes (normal, soft partial, hard partial). When pcre_exec() is
|
||||
called, the appropriate code is run if it is available. Otherwise, the
|
||||
@ -8696,6 +8712,33 @@ JIT FAST PATH API
|
||||
Bypassing the sanity checks and the pcre_exec() wrapping can give
|
||||
speedups of more than 10%.
|
||||
|
||||
Note that the pcre_jit_exec() function is not available in versions of
|
||||
PCRE before 8.32 (released in November 2012). If you need to support
|
||||
versions that old you must either use the slower pcre_exec(), or switch
|
||||
between the two codepaths by checking the values of PCRE_MAJOR and
|
||||
PCRE_MINOR.
|
||||
|
||||
Due to an unfortunate implementation oversight, even in versions 8.32
|
||||
and later there will be no pcre_jit_exec() stub function defined when
|
||||
PCRE is compiled with --disable-jit, which is the default, and there's
|
||||
no way to detect whether PCRE was compiled with --enable-jit via a
|
||||
macro.
|
||||
|
||||
If you need to support versions older than 8.32, or versions that may
|
||||
not build with --enable-jit, you must either use the slower
|
||||
pcre_exec(), or switch between the two codepaths by checking the values
|
||||
of PCRE_MAJOR and PCRE_MINOR.
|
||||
|
||||
Switching between the two by checking the version assumes that all the
|
||||
versions being targeted are built with --enable-jit. To also support
|
||||
builds that may use --disable-jit either pcre_exec() must be used, or a
|
||||
compile-time check for JIT via pcre_config() (which assumes the runtime
|
||||
environment will be the same), or as the Git project decided to do,
|
||||
simply assume that pcre_jit_exec() is present in 8.32 or later unless a
|
||||
compile-time flag is provided, see the "grep: un-break building with
|
||||
PCRE >= 8.32 without --enable-jit" commit in git.git for an example of
|
||||
that.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
||||
@ -8711,8 +8754,8 @@ AUTHOR
|
||||
|
||||
REVISION
|
||||
|
||||
Last updated: 17 March 2013
|
||||
Copyright (c) 1997-2013 University of Cambridge.
|
||||
Last updated: 05 July 2017
|
||||
Copyright (c) 1997-2017 University of Cambridge.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH PCREJIT 3 "17 March 2013" "PCRE 8.33"
|
||||
.TH PCREJIT 3 "05 July 2017" "PCRE 8.41"
|
||||
.SH NAME
|
||||
PCRE - Perl-compatible regular expressions
|
||||
.SH "PCRE JUST-IN-TIME COMPILER SUPPORT"
|
||||
@ -54,9 +54,12 @@ programs that need the best possible performance, there is also a "fast path"
|
||||
API that is JIT-specific.
|
||||
.P
|
||||
If your program may sometimes be linked with versions of PCRE that are older
|
||||
than 8.20, but you want to use JIT when it is available, you can test
|
||||
the values of PCRE_MAJOR and PCRE_MINOR, or the existence of a JIT macro such
|
||||
as PCRE_CONFIG_JIT, for compile-time control of your code.
|
||||
than 8.20, but you want to use JIT when it is available, you can test the
|
||||
values of PCRE_MAJOR and PCRE_MINOR, or the existence of a JIT macro such as
|
||||
PCRE_CONFIG_JIT, for compile-time control of your code. Also beware that the
|
||||
\fBpcre_jit_exec()\fP function was not available at all before 8.32,
|
||||
and may not be available at all if PCRE isn't compiled with
|
||||
--enable-jit. See the "JIT FAST PATH API" section below for details.
|
||||
.
|
||||
.
|
||||
.SH "SIMPLE USE OF JIT"
|
||||
@ -96,6 +99,19 @@ when you call \fBpcre_study()\fP:
|
||||
PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE
|
||||
PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
|
||||
.sp
|
||||
If using \fBpcre_jit_exec()\fP and supporting a pre-8.32 version of
|
||||
PCRE, you can insert:
|
||||
.sp
|
||||
#if PCRE_MAJOR >= 8 && PCRE_MINOR >= 32
|
||||
pcre_jit_exec(...);
|
||||
#else
|
||||
pcre_exec(...)
|
||||
#endif
|
||||
.sp
|
||||
but as described in the "JIT FAST PATH API" section below this assumes
|
||||
version 8.32 and later are compiled with --enable-jit, which may
|
||||
break.
|
||||
.sp
|
||||
The JIT compiler generates different optimized code for each of the three
|
||||
modes (normal, soft partial, hard partial). When \fBpcre_exec()\fP is called,
|
||||
the appropriate code is run if it is available. Otherwise, the pattern is
|
||||
@ -404,6 +420,32 @@ fast path, and if invalid data is passed, the result is undefined.
|
||||
.P
|
||||
Bypassing the sanity checks and the \fBpcre_exec()\fP wrapping can give
|
||||
speedups of more than 10%.
|
||||
.P
|
||||
Note that the \fBpcre_jit_exec()\fP function is not available in versions of
|
||||
PCRE before 8.32 (released in November 2012). If you need to support versions
|
||||
that old you must either use the slower \fBpcre_exec()\fP, or switch between
|
||||
the two codepaths by checking the values of PCRE_MAJOR and PCRE_MINOR.
|
||||
.P
|
||||
Due to an unfortunate implementation oversight, even in versions 8.32
|
||||
and later there will be no \fBpcre_jit_exec()\fP stub function defined
|
||||
when PCRE is compiled with --disable-jit, which is the default, and
|
||||
there's no way to detect whether PCRE was compiled with --enable-jit
|
||||
via a macro.
|
||||
.P
|
||||
If you need to support versions older than 8.32, or versions that may
|
||||
not build with --enable-jit, you must either use the slower
|
||||
\fBpcre_exec()\fP, or switch between the two codepaths by checking the
|
||||
values of PCRE_MAJOR and PCRE_MINOR.
|
||||
.P
|
||||
Switching between the two by checking the version assumes that all the
|
||||
versions being targeted are built with --enable-jit. To also support
|
||||
builds that may use --disable-jit either \fBpcre_exec()\fP must be
|
||||
used, or a compile-time check for JIT via \fBpcre_config()\fP (which
|
||||
assumes the runtime environment will be the same), or as the Git
|
||||
project decided to do, simply assume that \fBpcre_jit_exec()\fP is
|
||||
present in 8.32 or later unless a compile-time flag is provided, see
|
||||
the "grep: un-break building with PCRE >= 8.32 without --enable-jit"
|
||||
commit in git.git for an example of that.
|
||||
.
|
||||
.
|
||||
.SH "SEE ALSO"
|
||||
@ -426,6 +468,6 @@ Cambridge CB2 3QH, England.
|
||||
.rs
|
||||
.sp
|
||||
.nf
|
||||
Last updated: 17 March 2013
|
||||
Copyright (c) 1997-2013 University of Cambridge.
|
||||
Last updated: 05 July 2017
|
||||
Copyright (c) 1997-2017 University of Cambridge.
|
||||
.fi
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH PCRETEST 1 "09 February 2014" "PCRE 8.35"
|
||||
.TH PCRETEST 1 "23 February 2017" "PCRE 8.41"
|
||||
.SH NAME
|
||||
pcretest - a program for testing Perl-compatible regular expressions.
|
||||
.SH SYNOPSIS
|
||||
@ -50,6 +50,10 @@ newline as data characters. However, in some Windows environments character 26
|
||||
(hex 1A) causes an immediate end of file, and no further data is read. For
|
||||
maximum portability, therefore, it is safest to use only ASCII characters in
|
||||
\fBpcretest\fP input files.
|
||||
.P
|
||||
The input is processed using using C's string functions, so must not
|
||||
contain binary zeroes, even though in Unix-like environments, \fBfgets()\fP
|
||||
treats any bytes other than newline as data characters.
|
||||
.
|
||||
.
|
||||
.SH "PCRE's 8-BIT, 16-BIT AND 32-BIT LIBRARIES"
|
||||
@ -1151,6 +1155,6 @@ Cambridge CB2 3QH, England.
|
||||
.rs
|
||||
.sp
|
||||
.nf
|
||||
Last updated: 09 February 2014
|
||||
Copyright (c) 1997-2014 University of Cambridge.
|
||||
Last updated: 23 February 2017
|
||||
Copyright (c) 1997-2017 University of Cambridge.
|
||||
.fi
|
||||
|
@ -39,6 +39,10 @@ INPUT DATA FORMAT
|
||||
For maximum portability, therefore, it is safest to use only ASCII
|
||||
characters in pcretest input files.
|
||||
|
||||
The input is processed using using C's string functions, so must not
|
||||
contain binary zeroes, even though in Unix-like environments, fgets()
|
||||
treats any bytes other than newline as data characters.
|
||||
|
||||
|
||||
PCRE's 8-BIT, 16-BIT AND 32-BIT LIBRARIES
|
||||
|
||||
@ -1083,5 +1087,5 @@ AUTHOR
|
||||
|
||||
REVISION
|
||||
|
||||
Last updated: 09 February 2014
|
||||
Copyright (c) 1997-2014 University of Cambridge.
|
||||
Last updated: 23 February 2017
|
||||
Copyright (c) 1997-2017 University of Cambridge.
|
||||
|
@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
/* The current PCRE version information. */
|
||||
|
||||
#define PCRE_MAJOR 8
|
||||
#define PCRE_MINOR 40
|
||||
#define PCRE_MINOR 41
|
||||
#define PCRE_PRERELEASE
|
||||
#define PCRE_DATE 2017-01-11
|
||||
#define PCRE_DATE 2017-07-05
|
||||
|
||||
/* When an application links to a PCRE DLL in Windows, the symbols that are
|
||||
imported have to be identified as such. When building PCRE, the appropriate
|
||||
|
@ -5739,6 +5739,21 @@ for (;; ptr++)
|
||||
ptr = p - 1; /* Character before the next significant one. */
|
||||
}
|
||||
|
||||
/* We also need to skip over (?# comments, which are not dependent on
|
||||
extended mode. */
|
||||
|
||||
if (ptr[1] == CHAR_LEFT_PARENTHESIS && ptr[2] == CHAR_QUESTION_MARK &&
|
||||
ptr[3] == CHAR_NUMBER_SIGN)
|
||||
{
|
||||
ptr += 4;
|
||||
while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
|
||||
if (*ptr == CHAR_NULL)
|
||||
{
|
||||
*errorcodeptr = ERR18;
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the next character is '+', we have a possessive quantifier. This
|
||||
implies greediness, whatever the setting of the PCRE_UNGREEDY option.
|
||||
If the next character is '?' this is a minimizing repeat, by default,
|
||||
@ -8210,7 +8225,6 @@ for (;; ptr++)
|
||||
|
||||
if (mclength == 1 || req_caseopt == 0)
|
||||
{
|
||||
firstchar = mcbuffer[0] | req_caseopt;
|
||||
firstchar = mcbuffer[0];
|
||||
firstcharflags = req_caseopt;
|
||||
|
||||
|
@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language (but see
|
||||
below for why this module is different).
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
Copyright (c) 1997-2017 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -2625,7 +2625,7 @@ for (;;)
|
||||
if (isinclass)
|
||||
{
|
||||
int max = (int)GET2(ecode, 1 + IMM2_SIZE);
|
||||
if (*ecode == OP_CRPOSRANGE)
|
||||
if (*ecode == OP_CRPOSRANGE && count >= (int)GET2(ecode, 1))
|
||||
{
|
||||
active_count--; /* Remove non-match possibility */
|
||||
next_active_state--;
|
||||
|
@ -669,7 +669,7 @@ if (ecode == NULL)
|
||||
return match((PCRE_PUCHAR)&rdepth, NULL, NULL, 0, NULL, NULL, 1);
|
||||
else
|
||||
{
|
||||
int len = (char *)&rdepth - (char *)eptr;
|
||||
int len = (int)((char *)&rdepth - (char *)eptr);
|
||||
return (len > 0)? -len : len;
|
||||
}
|
||||
}
|
||||
|
@ -2772,6 +2772,9 @@ extern const pcre_uint8 PRIV(ucd_stage1)[];
|
||||
extern const pcre_uint16 PRIV(ucd_stage2)[];
|
||||
extern const pcre_uint32 PRIV(ucp_gentype)[];
|
||||
extern const pcre_uint32 PRIV(ucp_gbtable)[];
|
||||
#ifdef COMPILE_PCRE32
|
||||
extern const ucd_record PRIV(dummy_ucd_record)[];
|
||||
#endif
|
||||
#ifdef SUPPORT_JIT
|
||||
extern const int PRIV(ucp_typerange)[];
|
||||
#endif
|
||||
@ -2780,10 +2783,16 @@ extern const int PRIV(ucp_typerange)[];
|
||||
/* UCD access macros */
|
||||
|
||||
#define UCD_BLOCK_SIZE 128
|
||||
#define GET_UCD(ch) (PRIV(ucd_records) + \
|
||||
#define REAL_GET_UCD(ch) (PRIV(ucd_records) + \
|
||||
PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \
|
||||
UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE])
|
||||
|
||||
#ifdef COMPILE_PCRE32
|
||||
#define GET_UCD(ch) ((ch > 0x10ffff)? PRIV(dummy_ucd_record) : REAL_GET_UCD(ch))
|
||||
#else
|
||||
#define GET_UCD(ch) REAL_GET_UCD(ch)
|
||||
#endif
|
||||
|
||||
#define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype
|
||||
#define UCD_SCRIPT(ch) GET_UCD(ch)->script
|
||||
#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -57,6 +57,7 @@
|
||||
} while (0)
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using pcrecpp::StringPiece;
|
||||
using pcrecpp::Scanner;
|
||||
|
||||
|
@ -52,12 +52,12 @@
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
namespace pcrecpp {
|
||||
|
||||
using std::memcmp;
|
||||
using std::strlen;
|
||||
using std::string;
|
||||
|
||||
namespace pcrecpp {
|
||||
|
||||
class PCRECPP_EXP_DEFN StringPiece {
|
||||
private:
|
||||
const char* ptr_;
|
||||
|
@ -24,6 +24,7 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
using std::string;
|
||||
using pcrecpp::StringPiece;
|
||||
|
||||
static void CheckSTLComparator() {
|
||||
|
@ -6,7 +6,7 @@
|
||||
and semantics are as close as possible to those of the Perl 5 language.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
Copyright (c) 1997-2017 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -161,7 +161,7 @@ const pcre_uint32 PRIV(ucp_gbtable[]) = {
|
||||
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark), /* 5 SpacingMark */
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbL)| /* 6 L */
|
||||
(1<<ucp_gbL)|(1<<ucp_gbV)|(1<<ucp_gbLV)|(1<<ucp_gbLVT),
|
||||
(1<<ucp_gbV)|(1<<ucp_gbLV)|(1<<ucp_gbLVT),
|
||||
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbV)| /* 7 V */
|
||||
(1<<ucp_gbT),
|
||||
|
@ -38,6 +38,20 @@ const pcre_uint16 PRIV(ucd_stage2)[] = {0};
|
||||
const pcre_uint32 PRIV(ucd_caseless_sets)[] = {0};
|
||||
#else
|
||||
|
||||
/* If the 32-bit library is run in non-32-bit mode, character values
|
||||
greater than 0x10ffff may be encountered. For these we set up a
|
||||
special record. */
|
||||
|
||||
#ifdef COMPILE_PCRE32
|
||||
const ucd_record PRIV(dummy_ucd_record)[] = {{
|
||||
ucp_Common, /* script */
|
||||
ucp_Cn, /* type unassigned */
|
||||
ucp_gbOther, /* grapheme break property */
|
||||
0, /* case set */
|
||||
0, /* other case */
|
||||
}};
|
||||
#endif
|
||||
|
||||
/* When recompiling tables with a new Unicode version, please check the
|
||||
types in this structure definition from pcre_internal.h (the actual
|
||||
field names will be different):
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <vector>
|
||||
#include "pcrecpp.h"
|
||||
|
||||
using std::string;
|
||||
using pcrecpp::StringPiece;
|
||||
using pcrecpp::RE;
|
||||
using pcrecpp::RE_Options;
|
||||
|
@ -1804,11 +1804,6 @@ while (ptr < endptr)
|
||||
if (line_buffered) fflush(stdout);
|
||||
rc = 0; /* Had some success */
|
||||
|
||||
/* If the current match ended past the end of the line (only possible
|
||||
in multiline mode), we are done with this line. */
|
||||
|
||||
if ((unsigned int)offsets[1] > linelength) goto END_ONE_MATCH;
|
||||
|
||||
startoffset = offsets[1]; /* Restart after the match */
|
||||
if (startoffset <= oldstartoffset)
|
||||
{
|
||||
@ -1818,6 +1813,22 @@ while (ptr < endptr)
|
||||
if (utf8)
|
||||
while ((matchptr[startoffset] & 0xc0) == 0x80) startoffset++;
|
||||
}
|
||||
|
||||
/* If the current match ended past the end of the line (only possible
|
||||
in multiline mode), we must move on to the line in which it did end
|
||||
before searching for more matches. */
|
||||
|
||||
while (startoffset > (int)linelength)
|
||||
{
|
||||
matchptr = ptr += linelength + endlinelength;
|
||||
filepos += (int)(linelength + endlinelength);
|
||||
linenumber++;
|
||||
startoffset -= (int)(linelength + endlinelength);
|
||||
t = end_of_line(ptr, endptr, &endlinelength);
|
||||
linelength = t - ptr - endlinelength;
|
||||
length = (size_t)(endptr - ptr);
|
||||
}
|
||||
|
||||
goto ONLY_MATCHING_RESTART;
|
||||
}
|
||||
}
|
||||
@ -3179,9 +3190,11 @@ for (j = 1, cp = patterns; cp != NULL; j++, cp = cp->next)
|
||||
cp->hint = pcre_study(cp->compiled, study_options, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
char s[16];
|
||||
if (patterns->next == NULL) s[0] = 0; else sprintf(s, " number %d", j);
|
||||
fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error);
|
||||
if (patterns->next == NULL)
|
||||
fprintf(stderr, "pcregrep: Error while studying regex: %s\n", error);
|
||||
else
|
||||
fprintf(stderr, "pcregrep: Error while studying regex number %d: %s\n",
|
||||
j, error);
|
||||
goto EXIT2;
|
||||
}
|
||||
#ifdef SUPPORT_PCREGREP_JIT
|
||||
|
@ -6,7 +6,7 @@
|
||||
and semantics are as close as possible to those of the Perl 5 language.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2016 University of Cambridge
|
||||
Copyright (c) 1997-2017 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -389,8 +389,8 @@ if (rc >= 0)
|
||||
{
|
||||
for (i = 0; i < (size_t)rc; i++)
|
||||
{
|
||||
pmatch[i].rm_so = ovector[i*2];
|
||||
pmatch[i].rm_eo = ovector[i*2+1];
|
||||
pmatch[i].rm_so = ovector[i*2] + so;
|
||||
pmatch[i].rm_eo = ovector[i*2+1] + so;
|
||||
}
|
||||
if (allocated_ovector) free(ovector);
|
||||
for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
|
||||
|
@ -177,7 +177,7 @@ that differ in their output from isprint() even in the "C" locale. */
|
||||
#define PRINTABLE(c) ((c) >= 32 && (c) < 127)
|
||||
#endif
|
||||
|
||||
#define PRINTOK(c) (locale_set? isprint(c) : PRINTABLE(c))
|
||||
#define PRINTOK(c) (locale_set? (((c) < 256) && isprint(c)) : PRINTABLE(c))
|
||||
|
||||
/* Posix support is disabled in 16 or 32 bit only mode. */
|
||||
#if !defined SUPPORT_PCRE8 && !defined NOPOSIX
|
||||
@ -426,11 +426,11 @@ argument, the casting might be incorrectly applied. */
|
||||
#define PCRE_COPY_NAMED_SUBSTRING32(rc, re, bptr, offsets, count, \
|
||||
namesptr, cbuffer, size) \
|
||||
rc = pcre32_copy_named_substring((pcre32 *)re, (PCRE_SPTR32)bptr, offsets, \
|
||||
count, (PCRE_SPTR32)namesptr, (PCRE_UCHAR32 *)cbuffer, size/2)
|
||||
count, (PCRE_SPTR32)namesptr, (PCRE_UCHAR32 *)cbuffer, size/4)
|
||||
|
||||
#define PCRE_COPY_SUBSTRING32(rc, bptr, offsets, count, i, cbuffer, size) \
|
||||
rc = pcre32_copy_substring((PCRE_SPTR32)bptr, offsets, count, i, \
|
||||
(PCRE_UCHAR32 *)cbuffer, size/2)
|
||||
(PCRE_UCHAR32 *)cbuffer, size/4)
|
||||
|
||||
#define PCRE_DFA_EXEC32(count, re, extra, bptr, len, start_offset, options, \
|
||||
offsets, size_offsets, workspace, size_workspace) \
|
||||
@ -4834,7 +4834,16 @@ while (!done)
|
||||
continue;
|
||||
|
||||
case 'O':
|
||||
while(isdigit(*p)) n = n * 10 + *p++ - '0';
|
||||
while(isdigit(*p))
|
||||
{
|
||||
if (n > (INT_MAX-10)/10) /* Hack to stop fuzzers */
|
||||
{
|
||||
printf("** \\O argument is too big\n");
|
||||
yield = 1;
|
||||
goto EXIT;
|
||||
}
|
||||
n = n * 10 + *p++ - '0';
|
||||
}
|
||||
if (n > size_offsets_max)
|
||||
{
|
||||
size_offsets_max = n;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -90,7 +90,7 @@
|
||||
|
||||
/* Executable code allocation:
|
||||
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
|
||||
define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_ENABLE_EXEC. */
|
||||
define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
|
||||
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
/* Enabled by default. */
|
||||
#define SLJIT_EXECUTABLE_ALLOCATOR 1
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -187,14 +187,6 @@
|
||||
/* External function definitions. */
|
||||
/**********************************/
|
||||
|
||||
#if !(defined SLJIT_STD_MACROS_DEFINED && SLJIT_STD_MACROS_DEFINED)
|
||||
|
||||
/* These libraries are needed for the macros below. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* SLJIT_STD_MACROS_DEFINED */
|
||||
|
||||
/* General macros:
|
||||
Note: SLJIT is designed to be independent from them as possible.
|
||||
|
||||
@ -304,6 +296,13 @@
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
ppc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
@ -316,13 +315,6 @@
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
cacheflush((long)(from), (long)(to), 0)
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
ppc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
|
||||
@ -401,7 +393,9 @@ typedef double sljit_f64;
|
||||
#ifndef SLJIT_W
|
||||
|
||||
/* Defining long constants. */
|
||||
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
#define SLJIT_W(w) (w##l)
|
||||
#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
#define SLJIT_W(w) (w##ll)
|
||||
#else
|
||||
#define SLJIT_W(w) (w)
|
||||
@ -547,10 +541,10 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
|
||||
#define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr)
|
||||
|
||||
#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_enable_exec(void* from, void *to);
|
||||
#define SLJIT_ENABLE_EXEC(from, to) sljit_enable_exec((from), (to))
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
|
||||
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
|
||||
#else
|
||||
#define SLJIT_ENABLE_EXEC(from, to)
|
||||
#define SLJIT_EXEC_OFFSET(ptr) 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -561,37 +555,37 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_enable_exec(void* from, void *to);
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 10
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 7
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 9
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((2 + 4) * sizeof(sljit_sw))
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#else
|
||||
/* Maximum 3 arguments are passed on the stack, +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1 + 4) * sizeof(sljit_sw))
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* SLJIT_X86_32_FASTCALL */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
|
||||
#ifndef _WIN64
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 13
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (sizeof(sljit_sw))
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#else
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 13
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((4 + 2) * sizeof(sljit_sw))
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* _WIN64 */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 11
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 11
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 7
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
@ -615,7 +609,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_enable_exec(void* from, void *to);
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 17
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 21
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (4 * sizeof(sljit_sw))
|
||||
@ -671,7 +665,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_enable_exec(void* from, void *to);
|
||||
|
||||
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
|
||||
|
||||
#if !defined(SLJIT_ASSERT) || !defined(SLJIT_ASSERT_STOP)
|
||||
#if !defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE)
|
||||
|
||||
/* SLJIT_HALT_PROCESS must halt the process. */
|
||||
#ifndef SLJIT_HALT_PROCESS
|
||||
@ -683,7 +677,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_enable_exec(void* from, void *to);
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif /* !SLJIT_ASSERT || !SLJIT_ASSERT_STOP */
|
||||
#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */
|
||||
|
||||
/* Feel free to redefine these two macros. */
|
||||
#ifndef SLJIT_ASSERT
|
||||
@ -698,34 +692,33 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_enable_exec(void* from, void *to);
|
||||
|
||||
#endif /* !SLJIT_ASSERT */
|
||||
|
||||
#ifndef SLJIT_ASSERT_STOP
|
||||
#ifndef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_ASSERT_STOP() \
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { \
|
||||
printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_ASSERT_STOP */
|
||||
#endif /* !SLJIT_UNREACHABLE */
|
||||
|
||||
#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
/* Forcing empty, but valid statements. */
|
||||
#undef SLJIT_ASSERT
|
||||
#undef SLJIT_ASSERT_STOP
|
||||
#undef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { } while (0)
|
||||
#define SLJIT_ASSERT_STOP() \
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { } while (0)
|
||||
|
||||
#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
#ifndef SLJIT_COMPILE_ASSERT
|
||||
|
||||
/* Should be improved eventually. */
|
||||
#define SLJIT_COMPILE_ASSERT(x, description) \
|
||||
SLJIT_ASSERT(x)
|
||||
switch(0) { case 0: case ((x) ? 1 : 0): break; }
|
||||
|
||||
#endif /* !SLJIT_COMPILE_ASSERT */
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -180,8 +180,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
||||
sljit_uw chunk_size;
|
||||
|
||||
allocator_grab_lock();
|
||||
if (size < sizeof(struct free_block))
|
||||
size = sizeof(struct free_block);
|
||||
if (size < (64 - sizeof(struct block_header)))
|
||||
size = (64 - sizeof(struct block_header));
|
||||
size = ALIGN_SIZE(size);
|
||||
|
||||
free_block = free_blocks;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -120,8 +120,8 @@ of sljitConfigInternal.h */
|
||||
If an architecture provides two scratch and three saved registers,
|
||||
its scratch and saved register sets are the following:
|
||||
|
||||
R0 | [S4] | R0 and S4 represent the same physical register
|
||||
R1 | [S3] | R1 and S3 represent the same physical register
|
||||
R0 | | R0 is always a scratch register
|
||||
R1 | | R1 is always a scratch register
|
||||
[R2] | S2 | R2 and S2 represent the same physical register
|
||||
[R3] | S1 | R3 and S1 represent the same physical register
|
||||
[R4] | S0 | R4 and S0 represent the same physical register
|
||||
@ -129,38 +129,35 @@ of sljitConfigInternal.h */
|
||||
Note: SLJIT_NUMBER_OF_SCRATCH_REGISTERS would be 2 and
|
||||
SLJIT_NUMBER_OF_SAVED_REGISTERS would be 3 for this architecture.
|
||||
|
||||
Note: On all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 10
|
||||
and SLJIT_NUMBER_OF_SAVED_REGISTERS >= 5. However, 4 registers
|
||||
Note: On all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 12
|
||||
and SLJIT_NUMBER_OF_SAVED_REGISTERS >= 6. However, 6 registers
|
||||
are virtual on x86-32. See below.
|
||||
|
||||
The purpose of this definition is convenience. Although a register
|
||||
is either scratch register or saved register, SLJIT allows accessing
|
||||
them from the other set. For example, four registers can be used as
|
||||
scratch registers and the fifth one as saved register on the architecture
|
||||
above. Of course the last two scratch registers (R2 and R3) from this
|
||||
four will be saved on the stack, because they are defined as saved
|
||||
registers in the application binary interface. Still R2 and R3 can be
|
||||
used for referencing to these registers instead of S2 and S1, which
|
||||
makes easier to write platform independent code. Scratch registers
|
||||
can be saved registers in a similar way, but these extra saved
|
||||
registers will not be preserved across function calls! Hence the
|
||||
application must save them on those platforms, where the number of
|
||||
saved registers is too low. This can be done by copy them onto
|
||||
the stack and restore them after a function call.
|
||||
The purpose of this definition is convenience: saved registers can
|
||||
be used as extra scratch registers. For example four registers can
|
||||
be specified as scratch registers and the fifth one as saved register
|
||||
on the CPU above and any user code which requires four scratch
|
||||
registers can run unmodified. The SLJIT compiler automatically saves
|
||||
the content of the two extra scrath register on the stack. Scratch
|
||||
registers can also be preserved by saving their value on the stack
|
||||
but this needs to be done manually.
|
||||
|
||||
Note: To emphasize that registers assigned to R2-R4 are saved
|
||||
registers, they are enclosed by square brackets. S3-S4
|
||||
are marked in a similar way.
|
||||
registers, they are enclosed by square brackets.
|
||||
|
||||
Note: sljit_emit_enter and sljit_set_context defines whether a register
|
||||
is S or R register. E.g: when 3 scratches and 1 saved is mapped
|
||||
by sljit_emit_enter, the allowed register set will be: R0-R2 and
|
||||
S0. Although S2 is mapped to the same position as R2, it does not
|
||||
available in the current configuration. Furthermore the R3 (S1)
|
||||
register does not available as well.
|
||||
available in the current configuration. Furthermore the S1 register
|
||||
is not available at all.
|
||||
*/
|
||||
|
||||
/* When SLJIT_UNUSED is specified as destination, the result is discarded. */
|
||||
/* When SLJIT_UNUSED is specified as the destination of sljit_emit_op1 and
|
||||
and sljit_emit_op2 operations the result is discarded. If no status
|
||||
flags are set, no instructions are emitted for these operations. Data
|
||||
prefetch is a special exception, see SLJIT_MOV operation. Other SLJIT
|
||||
operations do not support SLJIT_UNUSED as a destination operand. */
|
||||
#define SLJIT_UNUSED 0
|
||||
|
||||
/* Scratch registers. */
|
||||
@ -325,19 +322,22 @@ struct sljit_compiler {
|
||||
sljit_s32 local_size;
|
||||
/* Code size. */
|
||||
sljit_uw size;
|
||||
/* For statistical purposes. */
|
||||
/* Relative offset of the executable mapping from the writable mapping. */
|
||||
sljit_uw executable_offset;
|
||||
/* Executable size for statistical purposes. */
|
||||
sljit_uw executable_size;
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
sljit_s32 args;
|
||||
sljit_s32 locals_offset;
|
||||
sljit_s32 saveds_offset;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
sljit_s32 mode32;
|
||||
#ifdef _WIN64
|
||||
sljit_s32 locals_offset;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
sljit_s32 flags_saved;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
|
||||
@ -354,13 +354,6 @@ struct sljit_compiler {
|
||||
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
/* Temporary fields. */
|
||||
sljit_uw shift_imm;
|
||||
sljit_s32 cache_arg;
|
||||
sljit_sw cache_argw;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
sljit_s32 cache_arg;
|
||||
sljit_sw cache_argw;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
@ -397,6 +390,9 @@ struct sljit_compiler {
|
||||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|
||||
|| (defined SLJIT_DEBUG && SLJIT_DEBUG)
|
||||
/* Flags specified by the last arithmetic instruction.
|
||||
It contains the type of the variable flag. */
|
||||
sljit_s32 last_flags;
|
||||
/* Local size passed to the functions. */
|
||||
sljit_s32 logical_local_size;
|
||||
#endif
|
||||
@ -404,6 +400,7 @@ struct sljit_compiler {
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|
||||
|| (defined SLJIT_DEBUG && SLJIT_DEBUG) \
|
||||
|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
/* Trust arguments when the API function is called. */
|
||||
sljit_s32 skip_checks;
|
||||
#endif
|
||||
};
|
||||
@ -457,10 +454,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compile
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose);
|
||||
#endif
|
||||
|
||||
/* Returns with non-zero if dynamic code modification is enabled. */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_dyn_code_modification_enabled(void);
|
||||
|
||||
/*
|
||||
Create executable code from the sljit instruction stream. This is the final step
|
||||
of the code generation so no more instructions can be added after this call.
|
||||
@ -473,15 +466,55 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code);
|
||||
|
||||
/*
|
||||
After the machine code generation is finished we can retrieve the allocated
|
||||
executable memory size, although this area may not be fully filled with
|
||||
instructions depending on some optimizations. This function is useful only
|
||||
for statistical purposes.
|
||||
When the protected executable allocator is used the JIT code is mapped
|
||||
twice. The first mapping has read/write and the second mapping has read/exec
|
||||
permissions. This function returns with the relative offset of the executable
|
||||
mapping using the writable mapping as the base after the machine code is
|
||||
successfully generated. The returned value is always 0 for the normal executable
|
||||
allocator, since it uses only one mapping with read/write/exec permissions.
|
||||
Dynamic code modifications requires this value.
|
||||
|
||||
Before a successful code generation, this function returns with 0.
|
||||
*/
|
||||
static SLJIT_INLINE sljit_sw sljit_get_executable_offset(struct sljit_compiler *compiler) { return compiler->executable_offset; }
|
||||
|
||||
/*
|
||||
The executable memory consumption of the generated code can be retrieved by
|
||||
this function. The returned value can be used for statistical purposes.
|
||||
|
||||
Before a successful code generation, this function returns with 0.
|
||||
*/
|
||||
static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler *compiler) { return compiler->executable_size; }
|
||||
|
||||
/* Returns with non-zero if the feature or limitation type passed as its
|
||||
argument is present on the current CPU.
|
||||
|
||||
Some features (e.g. floating point operations) require hardware (CPU)
|
||||
support while others (e.g. move with update) are emulated if not available.
|
||||
However even if a feature is emulated, specialized code paths can be faster
|
||||
than the emulation. Some limitations are emulated as well so their general
|
||||
case is supported but it has extra performance costs. */
|
||||
|
||||
/* [Not emulated] Floating-point support is available. */
|
||||
#define SLJIT_HAS_FPU 0
|
||||
/* [Limitation] Some registers are virtual registers. */
|
||||
#define SLJIT_HAS_VIRTUAL_REGISTERS 1
|
||||
/* [Emulated] Some forms of move with pre update is supported. */
|
||||
#define SLJIT_HAS_PRE_UPDATE 2
|
||||
/* [Emulated] Count leading zero is supported. */
|
||||
#define SLJIT_HAS_CLZ 3
|
||||
/* [Emulated] Conditional move is supported. */
|
||||
#define SLJIT_HAS_CMOV 4
|
||||
/* [Limitation] [Emulated] Shifting with register is limited to SLJIT_PREF_SHIFT_REG. */
|
||||
#define SLJIT_HAS_PREF_SHIFT_REG 5
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
/* [Not emulated] SSE2 support is available on x86. */
|
||||
#define SLJIT_HAS_SSE2 100
|
||||
#endif
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type);
|
||||
|
||||
/* Instruction generation. Returns with any error code. If there is no
|
||||
error, they return with SLJIT_SUCCESS. */
|
||||
|
||||
@ -526,8 +559,8 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler
|
||||
*/
|
||||
|
||||
/* The absolute address returned by sljit_get_local_base with
|
||||
offset 0 is aligned to sljit_d. Otherwise it is aligned to sljit_uw. */
|
||||
#define SLJIT_DOUBLE_ALIGNMENT 0x00000001
|
||||
offset 0 is aligned to sljit_f64. Otherwise it is aligned to sljit_sw. */
|
||||
#define SLJIT_F64_ALIGNMENT 0x00000001
|
||||
|
||||
/* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */
|
||||
#define SLJIT_MAX_LOCAL_SIZE 65536
|
||||
@ -569,7 +602,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
|
||||
and setting up a new stack frame would cost too much performance. However, it is still
|
||||
possible to return to the address of the caller (or anywhere else). */
|
||||
|
||||
/* Note: flags are not changed (unlike sljit_emit_enter / sljit_emit_return). */
|
||||
/* Note: may destroy flags. */
|
||||
|
||||
/* Note: although sljit_emit_fast_return could be replaced by an ijump, it is not suggested,
|
||||
since many architectures do clever branch prediction on call / return instruction pairs. */
|
||||
@ -638,57 +671,97 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler
|
||||
#define SLJIT_MEM2(r1, r2) (SLJIT_MEM | (r1) | ((r2) << 8))
|
||||
#define SLJIT_IMM 0x40
|
||||
|
||||
/* Set 32 bit operation mode (I) on 64 bit CPUs. This flag is ignored on 32
|
||||
bit CPUs. When this flag is set for an arithmetic operation, only the
|
||||
lower 32 bit of the input register(s) are used, and the CPU status flags
|
||||
are set according to the 32 bit result. Although the higher 32 bit of
|
||||
the input and the result registers are not defined by SLJIT, it might be
|
||||
defined by the CPU architecture (e.g. MIPS). To satisfy these requirements
|
||||
all source registers must be computed by operations where this flag is
|
||||
also set. In other words 32 and 64 bit arithmetic operations cannot be
|
||||
mixed. The only exception is SLJIT_IMOV and SLJIT_IMOVU whose source
|
||||
register can hold any 32 or 64 bit value. This source register is
|
||||
converted to a 32 bit compatible format. SLJIT does not generate any
|
||||
instructions on certain CPUs (e.g. on x86 and ARM) if the source and
|
||||
destination operands are the same registers. Affects sljit_emit_op0,
|
||||
sljit_emit_op1 and sljit_emit_op2. */
|
||||
/* Set 32 bit operation mode (I) on 64 bit CPUs. This option is ignored on
|
||||
32 bit CPUs. When this option is set for an arithmetic operation, only
|
||||
the lower 32 bit of the input registers are used, and the CPU status
|
||||
flags are set according to the 32 bit result. Although the higher 32 bit
|
||||
of the input and the result registers are not defined by SLJIT, it might
|
||||
be defined by the CPU architecture (e.g. MIPS). To satisfy these CPU
|
||||
requirements all source registers must be the result of those operations
|
||||
where this option was also set. Memory loads read 32 bit values rather
|
||||
than 64 bit ones. In other words 32 bit and 64 bit operations cannot
|
||||
be mixed. The only exception is SLJIT_MOV32 and SLJIT_MOVU32 whose source
|
||||
register can hold any 32 or 64 bit value, and it is converted to a 32 bit
|
||||
compatible format first. This conversion is free (no instructions are
|
||||
emitted) on most CPUs. A 32 bit value can also be coverted to a 64 bit
|
||||
value by SLJIT_MOV_S32 (sign extension) or SLJIT_MOV_U32 (zero extension).
|
||||
|
||||
Note: memory addressing always uses 64 bit values on 64 bit systems so
|
||||
the result of a 32 bit operation must not be used with SLJIT_MEMx
|
||||
macros.
|
||||
|
||||
This option is part of the instruction name, so there is no need to
|
||||
manually set it. E.g:
|
||||
|
||||
SLJIT_ADD32 == (SLJIT_ADD | SLJIT_I32_OP) */
|
||||
#define SLJIT_I32_OP 0x100
|
||||
|
||||
/* F32 precision mode (SP). This flag is similar to SLJIT_I32_OP, just
|
||||
it applies to floating point registers (it is even the same bit). When
|
||||
this flag is passed, the CPU performs 32 bit floating point operations.
|
||||
Similar to SLJIT_I32_OP, all register arguments must be computed by
|
||||
floating point operations where this flag is also set. Affects
|
||||
sljit_emit_fop1, sljit_emit_fop2 and sljit_emit_fcmp. */
|
||||
#define SLJIT_F32_OP 0x100
|
||||
/* Set F32 (single) precision mode for floating-point computation. This
|
||||
option is similar to SLJIT_I32_OP, it just applies to floating point
|
||||
registers. When this option is passed, the CPU performs 32 bit floating
|
||||
point operations, rather than 64 bit one. Similar to SLJIT_I32_OP, all
|
||||
register arguments must be the result of those operations where this
|
||||
option was also set.
|
||||
|
||||
/* Common CPU status flags for all architectures (x86, ARM, PPC)
|
||||
- carry flag
|
||||
- overflow flag
|
||||
- zero flag
|
||||
- negative/positive flag (depends on arc)
|
||||
On mips, these flags are emulated by software. */
|
||||
This option is part of the instruction name, so there is no need to
|
||||
manually set it. E.g:
|
||||
|
||||
/* By default, the instructions may, or may not set the CPU status flags.
|
||||
Forcing to set or keep status flags can be done with the following flags: */
|
||||
SLJIT_MOV_F32 = (SLJIT_MOV_F64 | SLJIT_F32_OP)
|
||||
*/
|
||||
#define SLJIT_F32_OP SLJIT_I32_OP
|
||||
|
||||
/* Note: sljit tries to emit the minimum number of instructions. Using these
|
||||
flags can increase them, so use them wisely to avoid unnecessary code generation. */
|
||||
/* Many CPUs (x86, ARM, PPC) has status flags which can be set according
|
||||
to the result of an operation. Other CPUs (MIPS) does not have status
|
||||
flags, and results must be stored in registers. To cover both architecture
|
||||
types efficiently only two flags are defined by SLJIT:
|
||||
|
||||
/* Set Equal (Zero) status flag (E). */
|
||||
#define SLJIT_SET_E 0x0200
|
||||
/* Set unsigned status flag (U). */
|
||||
#define SLJIT_SET_U 0x0400
|
||||
/* Set signed status flag (S). */
|
||||
#define SLJIT_SET_S 0x0800
|
||||
/* Set signed overflow flag (O). */
|
||||
#define SLJIT_SET_O 0x1000
|
||||
/* Set carry flag (C).
|
||||
Note: Kinda unsigned overflow, but behaves differently on various cpus. */
|
||||
#define SLJIT_SET_C 0x2000
|
||||
/* Do not modify the flags (K).
|
||||
Note: This flag cannot be combined with any other SLJIT_SET_* flag. */
|
||||
#define SLJIT_KEEP_FLAGS 0x4000
|
||||
* Zero (equal) flag: it is set if the result is zero
|
||||
* Variable flag: its value is defined by the last arithmetic operation
|
||||
|
||||
SLJIT instructions can set any or both of these flags. The value of
|
||||
these flags is undefined if the instruction does not specify their value.
|
||||
The description of each instruction contains the list of allowed flag
|
||||
types.
|
||||
|
||||
Example: SLJIT_ADD can set the Z, OVERFLOW, CARRY flags hence
|
||||
|
||||
sljit_op2(..., SLJIT_ADD, ...)
|
||||
Both the zero and variable flags are undefined so they can
|
||||
have any value after the operation is completed.
|
||||
|
||||
sljit_op2(..., SLJIT_ADD | SLJIT_SET_Z, ...)
|
||||
Sets the zero flag if the result is zero, clears it otherwise.
|
||||
The variable flag is undefined.
|
||||
|
||||
sljit_op2(..., SLJIT_ADD | SLJIT_SET_OVERFLOW, ...)
|
||||
Sets the variable flag if an integer overflow occurs, clears
|
||||
it otherwise. The zero flag is undefined.
|
||||
|
||||
sljit_op2(..., SLJIT_ADD | SLJIT_SET_Z | SLJIT_SET_CARRY, ...)
|
||||
Sets the zero flag if the result is zero, clears it otherwise.
|
||||
Sets the variable flag if unsigned overflow (carry) occurs,
|
||||
clears it otherwise.
|
||||
|
||||
If an instruction (e.g. SLJIT_MOV) does not modify flags the flags are
|
||||
unchanged.
|
||||
|
||||
Using these flags can reduce the number of emitted instructions. E.g. a
|
||||
fast loop can be implemented by decreasing a counter register and set the
|
||||
zero flag to jump back if the counter register is not reached zero.
|
||||
|
||||
Motivation: although CPUs can set a large number of flags, usually their
|
||||
values are ignored or only one of them is used. Emulating a large number
|
||||
of flags on systems without flag register is complicated so SLJIT
|
||||
instructions must specify the flag they want to use and only that flag
|
||||
will be emulated. The last arithmetic instruction can be repeated if
|
||||
multiple flags needs to be checked.
|
||||
*/
|
||||
|
||||
/* Set Zero status flag. */
|
||||
#define SLJIT_SET_Z 0x0200
|
||||
/* Set the variable status flag if condition is true.
|
||||
See comparison types. */
|
||||
#define SLJIT_SET(condition) ((condition) << 10)
|
||||
|
||||
/* Notes:
|
||||
- you cannot postpone conditional jump instructions except if noted that
|
||||
@ -698,11 +771,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler
|
||||
/* Starting index of opcodes for sljit_emit_op0. */
|
||||
#define SLJIT_OP0_BASE 0
|
||||
|
||||
/* Flags: - (never set any flags)
|
||||
/* Flags: - (does not modify flags)
|
||||
Note: breakpoint instruction is not supported by all architectures (e.g. ppc)
|
||||
It falls back to SLJIT_NOP in those cases. */
|
||||
#define SLJIT_BREAKPOINT (SLJIT_OP0_BASE + 0)
|
||||
/* Flags: - (never set any flags)
|
||||
/* Flags: - (does not modify flags)
|
||||
Note: may or may not cause an extra cycle wait
|
||||
it can even decrease the runtime in a few cases. */
|
||||
#define SLJIT_NOP (SLJIT_OP0_BASE + 1)
|
||||
@ -714,13 +787,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler
|
||||
Signed multiplication of SLJIT_R0 and SLJIT_R1.
|
||||
Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
|
||||
#define SLJIT_LMUL_SW (SLJIT_OP0_BASE + 3)
|
||||
/* Flags: I - (may destroy flags)
|
||||
/* Flags: - (may destroy flags)
|
||||
Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1.
|
||||
The result is placed into SLJIT_R0 and the remainder into SLJIT_R1.
|
||||
Note: if SLJIT_R1 is 0, the behaviour is undefined. */
|
||||
#define SLJIT_DIVMOD_UW (SLJIT_OP0_BASE + 4)
|
||||
#define SLJIT_DIVMOD_U32 (SLJIT_DIVMOD_UW | SLJIT_I32_OP)
|
||||
/* Flags: I - (may destroy flags)
|
||||
/* Flags: - (may destroy flags)
|
||||
Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1.
|
||||
The result is placed into SLJIT_R0 and the remainder into SLJIT_R1.
|
||||
Note: if SLJIT_R1 is 0, the behaviour is undefined.
|
||||
@ -728,13 +801,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler
|
||||
the behaviour is undefined. */
|
||||
#define SLJIT_DIVMOD_SW (SLJIT_OP0_BASE + 5)
|
||||
#define SLJIT_DIVMOD_S32 (SLJIT_DIVMOD_SW | SLJIT_I32_OP)
|
||||
/* Flags: I - (may destroy flags)
|
||||
/* Flags: - (may destroy flags)
|
||||
Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1.
|
||||
The result is placed into SLJIT_R0. SLJIT_R1 preserves its value.
|
||||
Note: if SLJIT_R1 is 0, the behaviour is undefined. */
|
||||
#define SLJIT_DIV_UW (SLJIT_OP0_BASE + 6)
|
||||
#define SLJIT_DIV_U32 (SLJIT_DIV_UW | SLJIT_I32_OP)
|
||||
/* Flags: I - (may destroy flags)
|
||||
/* Flags: - (may destroy flags)
|
||||
Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1.
|
||||
The result is placed into SLJIT_R0. SLJIT_R1 preserves its value.
|
||||
Note: if SLJIT_R1 is 0, the behaviour is undefined.
|
||||
@ -748,75 +821,113 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
|
||||
/* Starting index of opcodes for sljit_emit_op1. */
|
||||
#define SLJIT_OP1_BASE 32
|
||||
|
||||
/* Notes for MOV instructions:
|
||||
U = Mov with update (pre form). If source or destination defined as SLJIT_MEM1(r1)
|
||||
or SLJIT_MEM2(r1, r2), r1 is increased by the sum of r2 and the constant argument
|
||||
UB = unsigned byte (8 bit)
|
||||
SB = signed byte (8 bit)
|
||||
UH = unsigned half (16 bit)
|
||||
SH = signed half (16 bit)
|
||||
UI = unsigned int (32 bit)
|
||||
SI = signed int (32 bit)
|
||||
P = pointer (sljit_p) size */
|
||||
/* The MOV instruction transfer data from source to destination.
|
||||
|
||||
/* Flags: - (never set any flags) */
|
||||
MOV instruction suffixes:
|
||||
|
||||
U8 - unsigned 8 bit data transfer
|
||||
S8 - signed 8 bit data transfer
|
||||
U16 - unsigned 16 bit data transfer
|
||||
S16 - signed 16 bit data transfer
|
||||
U32 - unsigned int (32 bit) data transfer
|
||||
S32 - signed int (32 bit) data transfer
|
||||
P - pointer (sljit_p) data transfer
|
||||
|
||||
U = move with update (pre form). If source or destination defined as
|
||||
SLJIT_MEM1(r1) or SLJIT_MEM2(r1, r2), r1 is increased by the
|
||||
offset part of the address.
|
||||
|
||||
Register arguments and base registers can only be used once for move
|
||||
with update instructions. The shift value of SLJIT_MEM2 addressing
|
||||
mode must also be 0. Reason: SLJIT_MOVU instructions are expected to
|
||||
be in high-performance loops where complex instruction emulation
|
||||
would be too costly.
|
||||
|
||||
Examples for invalid move with update instructions:
|
||||
|
||||
sljit_emit_op1(..., SLJIT_MOVU_U8,
|
||||
SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), 8);
|
||||
sljit_emit_op1(..., SLJIT_MOVU_U8,
|
||||
SLJIT_MEM2(SLJIT_R1, SLJIT_R0), 0, SLJIT_R0, 0);
|
||||
sljit_emit_op1(..., SLJIT_MOVU_U8,
|
||||
SLJIT_MEM2(SLJIT_R0, SLJIT_R1), 0, SLJIT_MEM1(SLJIT_R0), 8);
|
||||
sljit_emit_op1(..., SLJIT_MOVU_U8,
|
||||
SLJIT_MEM2(SLJIT_R0, SLJIT_R1), 0, SLJIT_MEM2(SLJIT_R1, SLJIT_R0), 0);
|
||||
sljit_emit_op1(..., SLJIT_MOVU_U8,
|
||||
SLJIT_R2, 0, SLJIT_MEM2(SLJIT_R0, SLJIT_R1), 1);
|
||||
|
||||
The following example is valid, since only the offset register is
|
||||
used multiple times:
|
||||
|
||||
sljit_emit_op1(..., SLJIT_MOVU_U8,
|
||||
SLJIT_MEM2(SLJIT_R0, SLJIT_R2), 0, SLJIT_MEM2(SLJIT_R1, SLJIT_R2), 0);
|
||||
|
||||
If the destination of a MOV without update instruction is SLJIT_UNUSED
|
||||
and the source operand is a memory address the compiler emits a prefetch
|
||||
instruction if this instruction is supported by the current CPU.
|
||||
Higher data sizes bring the data closer to the core: a MOV with word
|
||||
size loads the data into a higher level cache than a byte size. Otherwise
|
||||
the type does not affect the prefetch instruction. Furthermore a prefetch
|
||||
instruction never fails, so it can be used to prefetch a data from an
|
||||
address and check whether that address is NULL afterwards.
|
||||
*/
|
||||
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV (SLJIT_OP1_BASE + 0)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV_U8 (SLJIT_OP1_BASE + 1)
|
||||
#define SLJIT_MOV32_U8 (SLJIT_MOV_U8 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV_S8 (SLJIT_OP1_BASE + 2)
|
||||
#define SLJIT_MOV32_S8 (SLJIT_MOV_S8 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV_U16 (SLJIT_OP1_BASE + 3)
|
||||
#define SLJIT_MOV32_U16 (SLJIT_MOV_U16 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV_S16 (SLJIT_OP1_BASE + 4)
|
||||
#define SLJIT_MOV32_S16 (SLJIT_MOV_S16 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags)
|
||||
/* Flags: - (does not modify flags)
|
||||
Note: no SLJIT_MOV32_U32 form, since it is the same as SLJIT_MOV32 */
|
||||
#define SLJIT_MOV_U32 (SLJIT_OP1_BASE + 5)
|
||||
/* Flags: I - (never set any flags)
|
||||
/* Flags: - (does not modify flags)
|
||||
Note: no SLJIT_MOV32_S32 form, since it is the same as SLJIT_MOV32 */
|
||||
#define SLJIT_MOV_S32 (SLJIT_OP1_BASE + 6)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV32 (SLJIT_MOV_S32 | SLJIT_I32_OP)
|
||||
/* Flags: - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV_P (SLJIT_OP1_BASE + 7)
|
||||
/* Flags: - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU (SLJIT_OP1_BASE + 8)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU_U8 (SLJIT_OP1_BASE + 9)
|
||||
#define SLJIT_MOVU32_U8 (SLJIT_MOVU_U8 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU_S8 (SLJIT_OP1_BASE + 10)
|
||||
#define SLJIT_MOVU32_S8 (SLJIT_MOVU_S8 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU_U16 (SLJIT_OP1_BASE + 11)
|
||||
#define SLJIT_MOVU32_U16 (SLJIT_MOVU_U16 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU_S16 (SLJIT_OP1_BASE + 12)
|
||||
#define SLJIT_MOVU32_S16 (SLJIT_MOVU_S16 | SLJIT_I32_OP)
|
||||
/* Flags: I - (never set any flags)
|
||||
/* Flags: - (may destroy flags)
|
||||
Note: no SLJIT_MOVU32_U32 form, since it is the same as SLJIT_MOVU32 */
|
||||
#define SLJIT_MOVU_U32 (SLJIT_OP1_BASE + 13)
|
||||
/* Flags: I - (never set any flags)
|
||||
/* Flags: - (may destroy flags)
|
||||
Note: no SLJIT_MOVU32_S32 form, since it is the same as SLJIT_MOVU32 */
|
||||
#define SLJIT_MOVU_S32 (SLJIT_OP1_BASE + 14)
|
||||
/* Flags: I - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU32 (SLJIT_MOVU_S32 | SLJIT_I32_OP)
|
||||
/* Flags: - (never set any flags) */
|
||||
/* Flags: - (may destroy flags) */
|
||||
#define SLJIT_MOVU_P (SLJIT_OP1_BASE + 15)
|
||||
/* Flags: I | E | K */
|
||||
/* Flags: Z */
|
||||
#define SLJIT_NOT (SLJIT_OP1_BASE + 16)
|
||||
#define SLJIT_NOT32 (SLJIT_NOT | SLJIT_I32_OP)
|
||||
/* Flags: I | E | O | K */
|
||||
/* Flags: Z | OVERFLOW */
|
||||
#define SLJIT_NEG (SLJIT_OP1_BASE + 17)
|
||||
#define SLJIT_NEG32 (SLJIT_NEG | SLJIT_I32_OP)
|
||||
/* Count leading zeroes
|
||||
Flags: I | E | K
|
||||
Important note! Sparc 32 does not support K flag, since
|
||||
the required popc instruction is introduced only in sparc 64. */
|
||||
Flags: - (may destroy flags) */
|
||||
#define SLJIT_CLZ (SLJIT_OP1_BASE + 18)
|
||||
#define SLJIT_CLZ32 (SLJIT_CLZ | SLJIT_I32_OP)
|
||||
|
||||
@ -827,46 +938,48 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
/* Starting index of opcodes for sljit_emit_op2. */
|
||||
#define SLJIT_OP2_BASE 96
|
||||
|
||||
/* Flags: I | E | O | C | K */
|
||||
/* Flags: Z | OVERFLOW | CARRY */
|
||||
#define SLJIT_ADD (SLJIT_OP2_BASE + 0)
|
||||
#define SLJIT_ADD32 (SLJIT_ADD | SLJIT_I32_OP)
|
||||
/* Flags: I | C | K */
|
||||
/* Flags: CARRY */
|
||||
#define SLJIT_ADDC (SLJIT_OP2_BASE + 1)
|
||||
#define SLJIT_ADDC32 (SLJIT_ADDC | SLJIT_I32_OP)
|
||||
/* Flags: I | E | U | S | O | C | K */
|
||||
/* Flags: Z | LESS | GREATER_EQUAL | GREATER | LESS_EQUAL
|
||||
SIG_LESS | SIG_GREATER_EQUAL | SIG_GREATER
|
||||
SIG_LESS_EQUAL | CARRY */
|
||||
#define SLJIT_SUB (SLJIT_OP2_BASE + 2)
|
||||
#define SLJIT_SUB32 (SLJIT_SUB | SLJIT_I32_OP)
|
||||
/* Flags: I | C | K */
|
||||
/* Flags: CARRY */
|
||||
#define SLJIT_SUBC (SLJIT_OP2_BASE + 3)
|
||||
#define SLJIT_SUBC32 (SLJIT_SUBC | SLJIT_I32_OP)
|
||||
/* Note: integer mul
|
||||
Flags: I | O (see SLJIT_C_MUL_*) | K */
|
||||
Flags: MUL_OVERFLOW */
|
||||
#define SLJIT_MUL (SLJIT_OP2_BASE + 4)
|
||||
#define SLJIT_MUL32 (SLJIT_MUL | SLJIT_I32_OP)
|
||||
/* Flags: I | E | K */
|
||||
/* Flags: Z */
|
||||
#define SLJIT_AND (SLJIT_OP2_BASE + 5)
|
||||
#define SLJIT_AND32 (SLJIT_AND | SLJIT_I32_OP)
|
||||
/* Flags: I | E | K */
|
||||
/* Flags: Z */
|
||||
#define SLJIT_OR (SLJIT_OP2_BASE + 6)
|
||||
#define SLJIT_OR32 (SLJIT_OR | SLJIT_I32_OP)
|
||||
/* Flags: I | E | K */
|
||||
/* Flags: Z */
|
||||
#define SLJIT_XOR (SLJIT_OP2_BASE + 7)
|
||||
#define SLJIT_XOR32 (SLJIT_XOR | SLJIT_I32_OP)
|
||||
/* Flags: I | E | K
|
||||
/* Flags: Z
|
||||
Let bit_length be the length of the shift operation: 32 or 64.
|
||||
If src2 is immediate, src2w is masked by (bit_length - 1).
|
||||
Otherwise, if the content of src2 is outside the range from 0
|
||||
to bit_length - 1, the result is undefined. */
|
||||
#define SLJIT_SHL (SLJIT_OP2_BASE + 8)
|
||||
#define SLJIT_SHL32 (SLJIT_SHL | SLJIT_I32_OP)
|
||||
/* Flags: I | E | K
|
||||
/* Flags: Z
|
||||
Let bit_length be the length of the shift operation: 32 or 64.
|
||||
If src2 is immediate, src2w is masked by (bit_length - 1).
|
||||
Otherwise, if the content of src2 is outside the range from 0
|
||||
to bit_length - 1, the result is undefined. */
|
||||
#define SLJIT_LSHR (SLJIT_OP2_BASE + 9)
|
||||
#define SLJIT_LSHR32 (SLJIT_LSHR | SLJIT_I32_OP)
|
||||
/* Flags: I | E | K
|
||||
/* Flags: Z
|
||||
Let bit_length be the length of the shift operation: 32 or 64.
|
||||
If src2 is immediate, src2w is masked by (bit_length - 1).
|
||||
Otherwise, if the content of src2 is outside the range from 0
|
||||
@ -879,44 +992,38 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2, sljit_sw src2w);
|
||||
|
||||
/* Returns with non-zero if fpu is available. */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void);
|
||||
|
||||
/* Starting index of opcodes for sljit_emit_fop1. */
|
||||
#define SLJIT_FOP1_BASE 128
|
||||
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MOV_F64 (SLJIT_FOP1_BASE + 0)
|
||||
#define SLJIT_MOV_F32 (SLJIT_MOV_F64 | SLJIT_F32_OP)
|
||||
/* Convert opcodes: CONV[DST_TYPE].FROM[SRC_TYPE]
|
||||
SRC/DST TYPE can be: D - double, S - single, W - signed word, I - signed int
|
||||
Rounding mode when the destination is W or I: round towards zero. */
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_CONV_F64_FROM_F32 (SLJIT_FOP1_BASE + 1)
|
||||
#define SLJIT_CONV_F32_FROM_F64 (SLJIT_CONV_F64_FROM_F32 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_CONV_SW_FROM_F64 (SLJIT_FOP1_BASE + 2)
|
||||
#define SLJIT_CONV_SW_FROM_F32 (SLJIT_CONV_SW_FROM_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_CONV_S32_FROM_F64 (SLJIT_FOP1_BASE + 3)
|
||||
#define SLJIT_CONV_S32_FROM_F32 (SLJIT_CONV_S32_FROM_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_CONV_F64_FROM_SW (SLJIT_FOP1_BASE + 4)
|
||||
#define SLJIT_CONV_F32_FROM_SW (SLJIT_CONV_F64_FROM_SW | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_CONV_F64_FROM_S32 (SLJIT_FOP1_BASE + 5)
|
||||
#define SLJIT_CONV_F32_FROM_S32 (SLJIT_CONV_F64_FROM_S32 | SLJIT_F32_OP)
|
||||
/* Note: dst is the left and src is the right operand for SLJIT_CMPD.
|
||||
Note: NaN check is always performed. If SLJIT_C_FLOAT_UNORDERED flag
|
||||
is set, the comparison result is unpredictable.
|
||||
Flags: SP | E | S (see SLJIT_C_FLOAT_*) */
|
||||
Flags: EQUAL_F | LESS_F | GREATER_EQUAL_F | GREATER_F | LESS_EQUAL_F */
|
||||
#define SLJIT_CMP_F64 (SLJIT_FOP1_BASE + 6)
|
||||
#define SLJIT_CMP_F32 (SLJIT_CMP_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_NEG_F64 (SLJIT_FOP1_BASE + 7)
|
||||
#define SLJIT_NEG_F32 (SLJIT_NEG_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_ABS_F64 (SLJIT_FOP1_BASE + 8)
|
||||
#define SLJIT_ABS_F32 (SLJIT_ABS_F64 | SLJIT_F32_OP)
|
||||
|
||||
@ -927,16 +1034,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
|
||||
/* Starting index of opcodes for sljit_emit_fop2. */
|
||||
#define SLJIT_FOP2_BASE 160
|
||||
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_ADD_F64 (SLJIT_FOP2_BASE + 0)
|
||||
#define SLJIT_ADD_F32 (SLJIT_ADD_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_SUB_F64 (SLJIT_FOP2_BASE + 1)
|
||||
#define SLJIT_SUB_F32 (SLJIT_SUB_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_MUL_F64 (SLJIT_FOP2_BASE + 2)
|
||||
#define SLJIT_MUL_F32 (SLJIT_MUL_F64 | SLJIT_F32_OP)
|
||||
/* Flags: SP - (never set any flags) */
|
||||
/* Flags: - (does not modify flags) */
|
||||
#define SLJIT_DIV_F64 (SLJIT_FOP2_BASE + 3)
|
||||
#define SLJIT_DIV_F32 (SLJIT_DIV_F64 | SLJIT_F32_OP)
|
||||
|
||||
@ -963,56 +1070,77 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
||||
|
||||
#define SLJIT_LESS 2
|
||||
#define SLJIT_LESS32 (SLJIT_LESS | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS)
|
||||
#define SLJIT_GREATER_EQUAL 3
|
||||
#define SLJIT_GREATER_EQUAL32 (SLJIT_GREATER_EQUAL | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_GREATER_EQUAL)
|
||||
#define SLJIT_GREATER 4
|
||||
#define SLJIT_GREATER32 (SLJIT_GREATER | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER)
|
||||
#define SLJIT_LESS_EQUAL 5
|
||||
#define SLJIT_LESS_EQUAL32 (SLJIT_LESS_EQUAL | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_LESS_EQUAL)
|
||||
#define SLJIT_SIG_LESS 6
|
||||
#define SLJIT_SIG_LESS32 (SLJIT_SIG_LESS | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_SIG_LESS SLJIT_SET(SLJIT_SIG_LESS)
|
||||
#define SLJIT_SIG_GREATER_EQUAL 7
|
||||
#define SLJIT_SIG_GREATER_EQUAL32 (SLJIT_SIG_GREATER_EQUAL | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_GREATER_EQUAL)
|
||||
#define SLJIT_SIG_GREATER 8
|
||||
#define SLJIT_SIG_GREATER32 (SLJIT_SIG_GREATER | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_SIG_GREATER SLJIT_SET(SLJIT_SIG_GREATER)
|
||||
#define SLJIT_SIG_LESS_EQUAL 9
|
||||
#define SLJIT_SIG_LESS_EQUAL32 (SLJIT_SIG_LESS_EQUAL | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_LESS_EQUAL)
|
||||
|
||||
#define SLJIT_OVERFLOW 10
|
||||
#define SLJIT_OVERFLOW32 (SLJIT_OVERFLOW | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW)
|
||||
#define SLJIT_NOT_OVERFLOW 11
|
||||
#define SLJIT_NOT_OVERFLOW32 (SLJIT_NOT_OVERFLOW | SLJIT_I32_OP)
|
||||
|
||||
#define SLJIT_MUL_OVERFLOW 12
|
||||
#define SLJIT_MUL_OVERFLOW32 (SLJIT_MUL_OVERFLOW | SLJIT_I32_OP)
|
||||
#define SLJIT_SET_MUL_OVERFLOW SLJIT_SET(SLJIT_MUL_OVERFLOW)
|
||||
#define SLJIT_MUL_NOT_OVERFLOW 13
|
||||
#define SLJIT_MUL_NOT_OVERFLOW32 (SLJIT_MUL_NOT_OVERFLOW | SLJIT_I32_OP)
|
||||
|
||||
/* There is no SLJIT_CARRY or SLJIT_NOT_CARRY. */
|
||||
#define SLJIT_SET_CARRY SLJIT_SET(14)
|
||||
|
||||
/* Floating point comparison types. */
|
||||
#define SLJIT_EQUAL_F64 14
|
||||
#define SLJIT_EQUAL_F64 16
|
||||
#define SLJIT_EQUAL_F32 (SLJIT_EQUAL_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_NOT_EQUAL_F64 15
|
||||
#define SLJIT_SET_EQUAL_F SLJIT_SET(SLJIT_EQUAL_F64)
|
||||
#define SLJIT_NOT_EQUAL_F64 17
|
||||
#define SLJIT_NOT_EQUAL_F32 (SLJIT_NOT_EQUAL_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_LESS_F64 16
|
||||
#define SLJIT_SET_NOT_EQUAL_F SLJIT_SET(SLJIT_NOT_EQUAL_F64)
|
||||
#define SLJIT_LESS_F64 18
|
||||
#define SLJIT_LESS_F32 (SLJIT_LESS_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_GREATER_EQUAL_F64 17
|
||||
#define SLJIT_SET_LESS_F SLJIT_SET(SLJIT_LESS_F64)
|
||||
#define SLJIT_GREATER_EQUAL_F64 19
|
||||
#define SLJIT_GREATER_EQUAL_F32 (SLJIT_GREATER_EQUAL_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_GREATER_F64 18
|
||||
#define SLJIT_SET_GREATER_EQUAL_F SLJIT_SET(SLJIT_GREATER_EQUAL_F64)
|
||||
#define SLJIT_GREATER_F64 20
|
||||
#define SLJIT_GREATER_F32 (SLJIT_GREATER_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_LESS_EQUAL_F64 19
|
||||
#define SLJIT_SET_GREATER_F SLJIT_SET(SLJIT_GREATER_F64)
|
||||
#define SLJIT_LESS_EQUAL_F64 21
|
||||
#define SLJIT_LESS_EQUAL_F32 (SLJIT_LESS_EQUAL_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_UNORDERED_F64 20
|
||||
#define SLJIT_SET_LESS_EQUAL_F SLJIT_SET(SLJIT_LESS_EQUAL_F64)
|
||||
#define SLJIT_UNORDERED_F64 22
|
||||
#define SLJIT_UNORDERED_F32 (SLJIT_UNORDERED_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_ORDERED_F64 21
|
||||
#define SLJIT_SET_UNORDERED_F SLJIT_SET(SLJIT_UNORDERED_F64)
|
||||
#define SLJIT_ORDERED_F64 23
|
||||
#define SLJIT_ORDERED_F32 (SLJIT_ORDERED_F64 | SLJIT_F32_OP)
|
||||
#define SLJIT_SET_ORDERED_F SLJIT_SET(SLJIT_ORDERED_F64)
|
||||
|
||||
/* Unconditional jump types. */
|
||||
#define SLJIT_JUMP 22
|
||||
#define SLJIT_FAST_CALL 23
|
||||
#define SLJIT_CALL0 24
|
||||
#define SLJIT_CALL1 25
|
||||
#define SLJIT_CALL2 26
|
||||
#define SLJIT_CALL3 27
|
||||
#define SLJIT_JUMP 24
|
||||
#define SLJIT_FAST_CALL 25
|
||||
#define SLJIT_CALL0 26
|
||||
#define SLJIT_CALL1 27
|
||||
#define SLJIT_CALL2 28
|
||||
#define SLJIT_CALL3 29
|
||||
|
||||
/* Fast calling method. See sljit_emit_fast_enter / sljit_emit_fast_return. */
|
||||
|
||||
@ -1022,8 +1150,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
||||
/* Emit a jump instruction. The destination is not set, only the type of the jump.
|
||||
type must be between SLJIT_EQUAL and SLJIT_CALL3
|
||||
type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
|
||||
Flags: - (never set any flags) for both conditional and unconditional jumps.
|
||||
Flags: destroy all flags for calls. */
|
||||
|
||||
Flags: does not modify flags for conditional and unconditional
|
||||
jumps but destroy all flags for calls. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type);
|
||||
|
||||
/* Basic arithmetic comparison. In most architectures it is implemented as
|
||||
@ -1033,7 +1162,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
||||
It is suggested to use this comparison form when appropriate.
|
||||
type must be between SLJIT_EQUAL and SLJIT_I_SIG_LESS_EQUAL
|
||||
type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
|
||||
Flags: destroy flags. */
|
||||
Flags: may destroy flags. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2, sljit_sw src2w);
|
||||
@ -1061,36 +1190,47 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw
|
||||
type must be between SLJIT_JUMP and SLJIT_CALL3
|
||||
Direct form: set src to SLJIT_IMM() and srcw to the address
|
||||
Indirect form: any other valid addressing mode
|
||||
Flags: - (never set any flags) for unconditional jumps.
|
||||
Flags: destroy all flags for calls. */
|
||||
|
||||
Flags: does not modify flags for unconditional jumps but
|
||||
destroy all flags for calls. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw);
|
||||
|
||||
/* Perform the operation using the conditional flags as the second argument.
|
||||
Type must always be between SLJIT_EQUAL and SLJIT_S_ORDERED. The value
|
||||
Type must always be between SLJIT_EQUAL and SLJIT_ORDERED_F64. The value
|
||||
represented by the type is 1, if the condition represented by the type
|
||||
is fulfilled, and 0 otherwise.
|
||||
|
||||
If op == SLJIT_MOV, SLJIT_MOV_S32, SLJIT_MOV_U32:
|
||||
If op == SLJIT_MOV, SLJIT_MOV32:
|
||||
Set dst to the value represented by the type (0 or 1).
|
||||
Src must be SLJIT_UNUSED, and srcw must be 0
|
||||
Flags: - (never set any flags)
|
||||
Flags: - (does not modify flags)
|
||||
If op == SLJIT_OR, op == SLJIT_AND, op == SLJIT_XOR
|
||||
Performs the binary operation using src as the first, and the value
|
||||
represented by type as the second argument.
|
||||
Important note: only dst=src and dstw=srcw is supported at the moment!
|
||||
Flags: I | E | K
|
||||
Note: sljit_emit_op_flags does nothing, if dst is SLJIT_UNUSED (regardless of op). */
|
||||
Performs the binary operation using dst as the first, and the value
|
||||
represented by type as the second argument. Result is written into dst.
|
||||
Flags: Z (may destroy flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw,
|
||||
sljit_s32 type);
|
||||
|
||||
/* Emit a conditional mov instruction which moves source to destination,
|
||||
if the condition is satisfied. Unlike other arithmetic operations this
|
||||
instruction does not support memory accesses.
|
||||
|
||||
type must be between SLJIT_EQUAL and SLJIT_ORDERED_F64
|
||||
dst_reg must be a valid register and it can be combined
|
||||
with SLJIT_I32_OP to perform a 32 bit arithmetic operation
|
||||
src must be register or immediate (SLJIT_IMM)
|
||||
|
||||
Flags: - (does not modify flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src, sljit_sw srcw);
|
||||
|
||||
/* Copies the base address of SLJIT_SP + offset to dst.
|
||||
Flags: - (never set any flags) */
|
||||
Flags: - (may destroy flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset);
|
||||
|
||||
/* The constant can be changed runtime (see: sljit_set_const)
|
||||
Flags: - (never set any flags) */
|
||||
Flags: - (does not modify flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value);
|
||||
|
||||
/* After the code generation the address for label, jump and const instructions
|
||||
@ -1100,16 +1240,17 @@ static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { r
|
||||
static SLJIT_INLINE sljit_uw sljit_get_jump_addr(struct sljit_jump *jump) { return jump->addr; }
|
||||
static SLJIT_INLINE sljit_uw sljit_get_const_addr(struct sljit_const *const_) { return const_->addr; }
|
||||
|
||||
/* Only the address is required to rewrite the code. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant);
|
||||
/* Only the address and executable offset are required to perform dynamic
|
||||
code modifications. See sljit_get_executable_offset function. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Miscellaneous utility functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define SLJIT_MAJOR_VERSION 0
|
||||
#define SLJIT_MINOR_VERSION 93
|
||||
#define SLJIT_MINOR_VERSION 94
|
||||
|
||||
/* Get the human readable name of the platform. Can be useful on platforms
|
||||
like ARM, where ARM and Thumb2 functions can be mixed, and
|
||||
@ -1127,19 +1268,23 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void);
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
|
||||
|
||||
/* The sljit_stack is a utiliy feature of sljit, which allocates a
|
||||
writable memory region between base (inclusive) and limit (exclusive).
|
||||
Both base and limit is a pointer, and base is always <= than limit.
|
||||
This feature uses the "address space reserve" feature
|
||||
of modern operating systems. Basically we don't need to allocate a
|
||||
huge memory block in one step for the worst case, we can start with
|
||||
a smaller chunk and extend it later. Since the address space is
|
||||
reserved, the data never copied to other regions, thus it is safe
|
||||
to store pointers here. */
|
||||
/* The sljit_stack is a utility extension of sljit, which provides
|
||||
a top-down stack. The stack starts at base and goes down to
|
||||
max_limit, so the memory region for this stack is between
|
||||
max_limit (inclusive) and base (exclusive). However the
|
||||
application can only use the region between limit (inclusive)
|
||||
and base (exclusive). The sljit_stack_resize can be used to
|
||||
extend this region up to max_limit.
|
||||
|
||||
/* Note: The base field is aligned to PAGE_SIZE bytes (usually 4k or more).
|
||||
Note: stack growing should not happen in small steps: 4k, 16k or even
|
||||
bigger growth is better.
|
||||
This feature uses the "address space reserve" feature of modern
|
||||
operating systems, so instead of allocating a huge memory block
|
||||
applications can allocate a small region and extend it later
|
||||
without moving the memory area. Hence pointers can be stored
|
||||
in this area. */
|
||||
|
||||
/* Note: base and max_limit fields are aligned to PAGE_SIZE bytes
|
||||
(usually 4 Kbyte or more).
|
||||
Note: stack should grow in larger steps, e.g. 4Kbyte, 16Kbyte or more.
|
||||
Note: this structure may not be supported by all operating systems.
|
||||
Some kind of fallback mechanism is suggested when SLJIT_UTIL_STACK
|
||||
is not defined. */
|
||||
@ -1147,15 +1292,16 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void);
|
||||
struct sljit_stack {
|
||||
/* User data, anything can be stored here.
|
||||
Starting with the same value as base. */
|
||||
sljit_uw top;
|
||||
sljit_u8 *top;
|
||||
/* These members are read only. */
|
||||
sljit_uw base;
|
||||
sljit_uw limit;
|
||||
sljit_uw max_limit;
|
||||
sljit_u8 *base;
|
||||
sljit_u8 *limit;
|
||||
sljit_u8 *max_limit;
|
||||
};
|
||||
|
||||
/* Returns NULL if unsuccessful.
|
||||
Note: limit and max_limit contains the size for stack allocation.
|
||||
Note: max_limit contains the maximum stack size in bytes.
|
||||
Note: limit contains the starting stack size in bytes.
|
||||
Note: the top field is initialized to base.
|
||||
Note: see sljit_create_compiler for the explanation of allocator_data. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data);
|
||||
@ -1167,7 +1313,7 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack *st
|
||||
since the growth ratio can be added to the current limit, and sljit_stack_resize
|
||||
will do all the necessary checks. The fields of the stack are not changed if
|
||||
sljit_stack_resize fails. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack *stack, sljit_uw new_limit);
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_limit);
|
||||
|
||||
#endif /* (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) */
|
||||
|
||||
@ -1196,6 +1342,15 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct
|
||||
|
||||
#endif /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
/* Free unused executable memory. The allocator keeps some free memory
|
||||
around to reduce the number of OS executable memory allocations.
|
||||
This improves performance since these calls are costly. However
|
||||
it is sometimes desired to free all unused memory regions, e.g.
|
||||
before the application terminates. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* CPU specific functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -1228,32 +1383,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
|
||||
void *instruction, sljit_s32 size);
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
/* Define the currently available CPU status flags. It is usually used after an
|
||||
sljit_emit_op_custom call to define which flags are set. */
|
||||
|
||||
/* Returns with non-zero if sse2 is available. */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_x86_is_sse2_available(void);
|
||||
|
||||
/* Returns with non-zero if cmov instruction is available. */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_x86_is_cmov_available(void);
|
||||
|
||||
/* Emit a conditional mov instruction on x86 CPUs. This instruction
|
||||
moves src to destination, if the condition is satisfied. Unlike
|
||||
other arithmetic instructions, destination must be a register.
|
||||
Before such instructions are emitted, cmov support should be
|
||||
checked by sljit_x86_is_cmov_available function.
|
||||
type must be between SLJIT_EQUAL and SLJIT_S_ORDERED
|
||||
dst_reg must be a valid register and it can be combined
|
||||
with SLJIT_I32_OP to perform 32 bit arithmetic
|
||||
Flags: I - (never set any flags)
|
||||
*/
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_x86_emit_cmov(struct sljit_compiler *compiler,
|
||||
sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src, sljit_sw srcw);
|
||||
|
||||
#endif
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler,
|
||||
sljit_s32 current_flags);
|
||||
|
||||
#endif /* _SLJIT_LIR_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -76,6 +76,7 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 8] = {
|
||||
#define BRK 0xd4200000
|
||||
#define CBZ 0xb4000000
|
||||
#define CLZ 0xdac01000
|
||||
#define CSEL 0x9a800000
|
||||
#define CSINC 0x9a800400
|
||||
#define EOR 0xca000000
|
||||
#define EORI 0xd2000000
|
||||
@ -151,7 +152,7 @@ static SLJIT_INLINE void modify_imm64_const(sljit_ins* inst, sljit_uw new_imm)
|
||||
inst[3] = MOVK | dst | ((new_imm >> 48) << 5) | (3 << 21);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
|
||||
static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_sw diff;
|
||||
sljit_uw target_addr;
|
||||
@ -165,9 +166,10 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_in
|
||||
target_addr = jump->u.target;
|
||||
else {
|
||||
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
|
||||
}
|
||||
diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr + 4);
|
||||
|
||||
diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr + 4) - executable_offset;
|
||||
|
||||
if (jump->flags & IS_COND) {
|
||||
diff += sizeof(sljit_ins);
|
||||
@ -211,6 +213,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
sljit_ins *buf_ptr;
|
||||
sljit_ins *buf_end;
|
||||
sljit_uw word_count;
|
||||
sljit_sw executable_offset;
|
||||
sljit_uw addr;
|
||||
sljit_s32 dst;
|
||||
|
||||
@ -228,6 +231,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
|
||||
code_ptr = code;
|
||||
word_count = 0;
|
||||
executable_offset = SLJIT_EXEC_OFFSET(code);
|
||||
|
||||
label = compiler->labels;
|
||||
jump = compiler->jumps;
|
||||
const_ = compiler->consts;
|
||||
@ -242,13 +247,13 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
SLJIT_ASSERT(!jump || jump->addr >= word_count);
|
||||
SLJIT_ASSERT(!const_ || const_->addr >= word_count);
|
||||
if (label && label->size == word_count) {
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
if (jump && jump->addr == word_count) {
|
||||
jump->addr = (sljit_uw)(code_ptr - 4);
|
||||
code_ptr -= detect_jump_type(jump, code_ptr, code);
|
||||
code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset);
|
||||
jump = jump->next;
|
||||
}
|
||||
if (const_ && const_->addr == word_count) {
|
||||
@ -263,7 +268,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
@ -278,8 +283,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
do {
|
||||
addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
|
||||
buf_ptr = (sljit_ins *)jump->addr;
|
||||
|
||||
if (jump->flags & PATCH_B) {
|
||||
addr = (sljit_sw)(addr - jump->addr) >> 2;
|
||||
addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
|
||||
SLJIT_ASSERT((sljit_sw)addr <= 0x1ffffff && (sljit_sw)addr >= -0x2000000);
|
||||
buf_ptr[0] = ((jump->flags & IS_BL) ? BL : B) | (addr & 0x3ffffff);
|
||||
if (jump->flags & IS_COND)
|
||||
@ -287,7 +293,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
break;
|
||||
}
|
||||
if (jump->flags & PATCH_COND) {
|
||||
addr = (sljit_sw)(addr - jump->addr) >> 2;
|
||||
addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
|
||||
SLJIT_ASSERT((sljit_sw)addr <= 0x3ffff && (sljit_sw)addr >= -0x40000);
|
||||
buf_ptr[0] = (buf_ptr[0] & ~0xffffe0) | ((addr & 0x7ffff) << 5);
|
||||
break;
|
||||
@ -308,12 +314,37 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
}
|
||||
|
||||
compiler->error = SLJIT_ERR_COMPILED;
|
||||
compiler->executable_offset = executable_offset;
|
||||
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
|
||||
SLJIT_ENABLE_EXEC(code, code_ptr);
|
||||
|
||||
code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
|
||||
code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
SLJIT_CACHE_FLUSH(code, code_ptr);
|
||||
return code;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
|
||||
{
|
||||
switch (feature_type) {
|
||||
case SLJIT_HAS_FPU:
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#else
|
||||
/* Available by default. */
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
case SLJIT_HAS_PRE_UPDATE:
|
||||
case SLJIT_HAS_CLZ:
|
||||
case SLJIT_HAS_CMOV:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Core code generator functions. */
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -366,7 +397,7 @@ static sljit_ins logical_imm(sljit_sw imm, sljit_s32 len)
|
||||
uimm = (sljit_uw)imm;
|
||||
while (1) {
|
||||
if (len <= 0) {
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
mask = ((sljit_uw)1 << len) - 1;
|
||||
@ -636,7 +667,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
||||
}
|
||||
goto set_flags;
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -703,7 +734,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(arg1 == TMP_REG1);
|
||||
FAIL_IF(push_inst(compiler, (ORN ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2)));
|
||||
goto set_flags;
|
||||
break; /* Set flags. */
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(arg1 == TMP_REG1);
|
||||
if (flags & SET_FLAGS)
|
||||
@ -711,8 +742,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
||||
return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(arg1 == TMP_REG1);
|
||||
FAIL_IF(push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2)));
|
||||
goto set_flags;
|
||||
return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2));
|
||||
case SLJIT_ADD:
|
||||
CHECK_FLAGS(1 << 29);
|
||||
return push_inst(compiler, (ADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
|
||||
@ -741,23 +771,23 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
||||
return push_inst(compiler, (AND ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
|
||||
case SLJIT_OR:
|
||||
FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
|
||||
goto set_flags;
|
||||
break; /* Set flags. */
|
||||
case SLJIT_XOR:
|
||||
FAIL_IF(push_inst(compiler, (EOR ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
|
||||
goto set_flags;
|
||||
break; /* Set flags. */
|
||||
case SLJIT_SHL:
|
||||
FAIL_IF(push_inst(compiler, (LSLV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
|
||||
goto set_flags;
|
||||
break; /* Set flags. */
|
||||
case SLJIT_LSHR:
|
||||
FAIL_IF(push_inst(compiler, (LSRV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
|
||||
goto set_flags;
|
||||
break; /* Set flags. */
|
||||
case SLJIT_ASHR:
|
||||
FAIL_IF(push_inst(compiler, (ASRV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
|
||||
goto set_flags;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
break; /* Set flags. */
|
||||
default:
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
set_flags:
|
||||
if (flags & SET_FLAGS)
|
||||
@ -860,6 +890,10 @@ static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flag
|
||||
}
|
||||
|
||||
arg &= REG_MASK;
|
||||
|
||||
if (arg == SLJIT_UNUSED)
|
||||
return 0;
|
||||
|
||||
if (argw >= 0 && (argw >> shift) <= 0xfff && (argw & ((1 << shift) - 1)) == 0) {
|
||||
if (SLJIT_UNLIKELY(flags & ARG_TEST))
|
||||
return 1;
|
||||
@ -920,21 +954,23 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
next_argw = 0;
|
||||
}
|
||||
|
||||
tmp_r = (flags & STORE) ? TMP_REG3 : reg;
|
||||
tmp_r = ((flags & STORE) || (flags == (WORD_SIZE | SIGNED))) ? TMP_REG3 : reg;
|
||||
|
||||
if (SLJIT_UNLIKELY((flags & UPDATE) && (arg & REG_MASK))) {
|
||||
/* Update only applies if a base register exists. */
|
||||
other_r = OFFS_REG(arg);
|
||||
if (!other_r) {
|
||||
other_r = arg & REG_MASK;
|
||||
if (other_r != reg && argw >= 0 && argw <= 0xffffff) {
|
||||
SLJIT_ASSERT(other_r != reg);
|
||||
|
||||
if (argw >= 0 && argw <= 0xffffff) {
|
||||
if ((argw & 0xfff) != 0)
|
||||
FAIL_IF(push_inst(compiler, ADDI | RD(other_r) | RN(other_r) | ((argw & 0xfff) << 10)));
|
||||
if (argw >> 12)
|
||||
FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(other_r) | RN(other_r) | ((argw >> 12) << 10)));
|
||||
return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(other_r));
|
||||
}
|
||||
else if (other_r != reg && argw < 0 && argw >= -0xffffff) {
|
||||
else if (argw < 0 && argw >= -0xffffff) {
|
||||
argw = -argw;
|
||||
if ((argw & 0xfff) != 0)
|
||||
FAIL_IF(push_inst(compiler, SUBI | RD(other_r) | RN(other_r) | ((argw & 0xfff) << 10)));
|
||||
@ -967,18 +1003,8 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
|
||||
/* No caching here. */
|
||||
arg &= REG_MASK;
|
||||
argw &= 0x3;
|
||||
if (!argw || argw == shift) {
|
||||
FAIL_IF(push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(other_r) | (argw ? (1 << 12) : 0)));
|
||||
return push_inst(compiler, ADD | RD(arg) | RN(arg) | RM(other_r) | (argw << 10));
|
||||
}
|
||||
if (arg != reg) {
|
||||
FAIL_IF(push_inst(compiler, ADD | RD(arg) | RN(arg) | RM(other_r) | (argw << 10)));
|
||||
return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg));
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADD | RD(TMP_LR) | RN(arg) | RM(other_r) | (argw << 10)));
|
||||
FAIL_IF(push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(TMP_LR)));
|
||||
return push_inst(compiler, ORR | RD(arg) | RN(TMP_ZERO) | RM(TMP_LR));
|
||||
FAIL_IF(push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(other_r)));
|
||||
return push_inst(compiler, ADD | RD(arg) | RN(arg) | RM(other_r));
|
||||
}
|
||||
|
||||
if (arg & OFFS_REG_MASK) {
|
||||
@ -999,16 +1025,16 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
}
|
||||
}
|
||||
|
||||
if (argw >= 0 && argw <= 0xffffff && (argw & ((1 << shift) - 1)) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_r) | RN(arg & REG_MASK) | ((argw >> 12) << 10)));
|
||||
return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30)
|
||||
| RT(reg) | RN(tmp_r) | ((argw & 0xfff) << (10 - shift)));
|
||||
}
|
||||
|
||||
diff = argw - next_argw;
|
||||
next_arg = (arg & REG_MASK) && (arg == next_arg) && diff <= 0xfff && diff >= -0xfff && diff != 0;
|
||||
arg &= REG_MASK;
|
||||
|
||||
if (arg != SLJIT_UNUSED && argw >= 0 && argw <= 0xffffff && (argw & ((1 << shift) - 1)) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_r) | RN(arg) | ((argw >> 12) << 10)));
|
||||
return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30)
|
||||
| RT(reg) | RN(tmp_r) | ((argw & 0xfff) << (10 - shift)));
|
||||
}
|
||||
|
||||
if (arg && compiler->cache_arg == SLJIT_MEM) {
|
||||
if (compiler->cache_argw == argw)
|
||||
return push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(TMP_REG3));
|
||||
@ -1291,6 +1317,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op)) {
|
||||
if (op <= SLJIT_MOV_P && (src & SLJIT_MEM)) {
|
||||
SLJIT_ASSERT(reg_map[1] == 0 && reg_map[3] == 2 && reg_map[5] == 4);
|
||||
|
||||
if (op >= SLJIT_MOV_U8 && op <= SLJIT_MOV_S8)
|
||||
dst = 5;
|
||||
else if (op >= SLJIT_MOV_U16 && op <= SLJIT_MOV_S16)
|
||||
dst = 3;
|
||||
else
|
||||
dst = 1;
|
||||
|
||||
/* Signed word sized load is the prefetch instruction. */
|
||||
return emit_op_mem(compiler, WORD_SIZE | SIGNED, dst, src, srcw);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
@ -1365,7 +1408,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
srcw = (sljit_s32)srcw;
|
||||
break;
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
flags = 0;
|
||||
break;
|
||||
}
|
||||
@ -1392,7 +1435,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
flags = GET_FLAGS(op_flags) ? SET_FLAGS : 0;
|
||||
flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
|
||||
mem_flags = WORD_SIZE;
|
||||
if (op_flags & SLJIT_I32_OP) {
|
||||
flags |= INT_OP;
|
||||
@ -1444,8 +1487,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
|
||||
flags = GET_FLAGS(op) ? SET_FLAGS : 0;
|
||||
flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
|
||||
mem_flags = WORD_SIZE;
|
||||
if (op & SLJIT_I32_OP) {
|
||||
flags |= INT_OP;
|
||||
@ -1538,16 +1584,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
|
||||
/* Floating point operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void)
|
||||
{
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#else
|
||||
/* Available by default. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
|
||||
{
|
||||
sljit_u32 shift = MEM_SIZE_SHIFT(flags);
|
||||
@ -1605,7 +1641,7 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
|
||||
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
|
||||
|
||||
if (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64)
|
||||
@ -1618,7 +1654,7 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
|
||||
|
||||
FAIL_IF(push_inst(compiler, (FCVTZS ^ inv_bits) | RD(dst_r) | VN(src)));
|
||||
|
||||
if (dst_r == TMP_REG1 && dst != SLJIT_UNUSED)
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? INT_SIZE : WORD_SIZE) | STORE, TMP_REG1, dst, dstw);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
@ -1776,10 +1812,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(TMP_LR));
|
||||
|
||||
@ -1857,7 +1889,7 @@ static sljit_uw get_cc(sljit_s32 type)
|
||||
return 0x6;
|
||||
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return 0xe;
|
||||
}
|
||||
}
|
||||
@ -1883,7 +1915,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
||||
struct sljit_jump *jump;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_jump(compiler, type));
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
@ -1968,19 +1999,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw,
|
||||
sljit_s32 type)
|
||||
{
|
||||
sljit_s32 dst_r, flags, mem_flags;
|
||||
sljit_s32 dst_r, src_r, flags, mem_flags;
|
||||
sljit_ins cc;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
cc = get_cc(type & 0xff);
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
@ -1994,26 +2020,50 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
||||
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
flags = GET_FLAGS(op) ? SET_FLAGS : 0;
|
||||
flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
|
||||
mem_flags = WORD_SIZE;
|
||||
if (op & SLJIT_I32_OP) {
|
||||
flags |= INT_OP;
|
||||
mem_flags = INT_SIZE;
|
||||
}
|
||||
|
||||
if (src & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, mem_flags, TMP_REG1, src, srcw, dst, dstw));
|
||||
src = TMP_REG1;
|
||||
srcw = 0;
|
||||
} else if (src & SLJIT_IMM)
|
||||
flags |= ARG1_IMM;
|
||||
src_r = dst;
|
||||
|
||||
if (dst & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, mem_flags, TMP_REG1, dst, dstw, dst, dstw));
|
||||
src_r = TMP_REG1;
|
||||
}
|
||||
|
||||
FAIL_IF(push_inst(compiler, CSINC | (cc << 12) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(TMP_ZERO)));
|
||||
emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src, TMP_REG2);
|
||||
emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src_r, TMP_REG2);
|
||||
|
||||
if (dst_r != TMP_REG1)
|
||||
return SLJIT_SUCCESS;
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem2(compiler, mem_flags | STORE, TMP_REG1, dst, dstw, 0, 0);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_ins inv_bits = (dst_reg & SLJIT_I32_OP) ? (1 << 31) : 0;
|
||||
sljit_ins cc;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
|
||||
|
||||
if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
|
||||
if (dst_reg & SLJIT_I32_OP)
|
||||
srcw = (sljit_s32)srcw;
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
|
||||
src = TMP_REG1;
|
||||
srcw = 0;
|
||||
}
|
||||
|
||||
cc = get_cc(type & 0xff);
|
||||
dst_reg &= ~SLJIT_I32_OP;
|
||||
|
||||
return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
|
||||
@ -2022,7 +2072,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
sljit_s32 dst_r;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(1);
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
@ -2030,7 +2079,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
PTR_FAIL_IF(!const_);
|
||||
set_const(const_, compiler);
|
||||
|
||||
dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, init_value));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
@ -2038,16 +2087,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins* inst = (sljit_ins*)addr;
|
||||
modify_imm64_const(inst, new_addr);
|
||||
modify_imm64_const(inst, new_target);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 4);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins* inst = (sljit_ins*)addr;
|
||||
modify_imm64_const(inst, new_constant);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 4);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -40,35 +40,37 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_a
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_imm, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
@ -93,8 +95,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_ASSERT_STOP();
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
@ -111,24 +114,25 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_ASSERT_STOP();
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_E)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_E)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
@ -145,130 +149,192 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
if (op & SLJIT_SET_E)
|
||||
return push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_O) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
if (op & SLJIT_SET_E)
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O)) {
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_O)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (op & SLJIT_SET_E)
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
if (!(op & SLJIT_SET_O))
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
return push_inst(compiler, SLL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_C) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
|
||||
if (!(op & SLJIT_SET_C))
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (ULESS_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(ULESS_FLAG) | TA(OVERFLOW_FLAG) | DA(ULESS_FLAG), ULESS_FLAG);
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_MIN)) {
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_O) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
if (op & SLJIT_SET_E)
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_O)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (op & SLJIT_SET_E)
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_U | SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
if (op & SLJIT_SET_U)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(UGREATER_FLAG), UGREATER_FLAG));
|
||||
if (op & SLJIT_SET_S) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(LESS_FLAG), LESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(GREATER_FLAG), GREATER_FLAG));
|
||||
}
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!(op & SLJIT_SET_O))
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
@ -277,28 +343,31 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(LESS_FLAG), LESS_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
|
||||
return (op & SLJIT_SET_C) ? push_inst(compiler, OR | SA(OVERFLOW_FLAG) | TA(LESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG) : SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
if (!(op & SLJIT_SET_O)) {
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
@ -307,10 +376,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
#endif
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(UGREATER_FLAG) | SH_IMM(31), UGREATER_FLAG));
|
||||
return push_inst(compiler, SUBU | SA(ULESS_FLAG) | TA(UGREATER_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
|
||||
FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
@ -337,7 +406,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -347,20 +416,22 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_addr & 0xffff);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -123,15 +123,15 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_a
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
@ -144,16 +144,16 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_a
|
||||
} \
|
||||
else \
|
||||
ins = (op & SLJIT_I32_OP) ? op_imm : op_dimm; \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
ins = (op & SLJIT_I32_OP) ? op_v : op_dv; \
|
||||
if (op & SLJIT_SET_E) \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (CHECK_FLAGS(SLJIT_SET_E)) \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
@ -161,6 +161,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_ins ins;
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
@ -180,8 +181,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_ASSERT_STOP();
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
@ -194,8 +196,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_ASSERT_STOP();
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
@ -209,18 +212,18 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_E)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_E)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
@ -237,130 +240,192 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
if (op & SLJIT_SET_E)
|
||||
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_O) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
if (op & SLJIT_SET_E)
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O)) {
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_O)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (op & SLJIT_SET_E)
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
if (!(op & SLJIT_SET_O))
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SLL) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_C) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
|
||||
if (!(op & SLJIT_SET_C))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (ULESS_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(ULESS_FLAG) | TA(OVERFLOW_FLAG) | DA(ULESS_FLAG), ULESS_FLAG);
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_MIN)) {
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_O) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
if (op & SLJIT_SET_E)
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_O)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (op & SLJIT_SET_E)
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (op & (SLJIT_SET_U | SLJIT_SET_C | SLJIT_SET_O))
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
if (op & SLJIT_SET_U)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(UGREATER_FLAG), UGREATER_FLAG));
|
||||
if (op & SLJIT_SET_S) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(LESS_FLAG), LESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(GREATER_FLAG), GREATER_FLAG));
|
||||
}
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!(op & SLJIT_SET_O))
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
@ -369,28 +434,31 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (op & SLJIT_SET_C)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(LESS_FLAG), LESS_FLAG));
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
|
||||
return (op & SLJIT_SET_C) ? push_inst(compiler, OR | SA(OVERFLOW_FLAG) | TA(LESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG) : SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
if (!(op & SLJIT_SET_O)) {
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_I32_OP)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
@ -402,10 +470,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
#endif
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(ULESS_FLAG), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(UGREATER_FLAG) | SH_IMM(31), UGREATER_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(ULESS_FLAG) | TA(UGREATER_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
@ -432,7 +500,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -446,18 +514,19 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_addr >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_addr & 0xffff);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
@ -465,5 +534,6 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -57,19 +57,14 @@ typedef sljit_u32 sljit_ins;
|
||||
#define RETURN_ADDR_REG 31
|
||||
|
||||
/* Flags are kept in volatile registers. */
|
||||
#define EQUAL_FLAG 12
|
||||
/* And carry flag as well. */
|
||||
#define ULESS_FLAG 13
|
||||
#define UGREATER_FLAG 14
|
||||
#define LESS_FLAG 15
|
||||
#define GREATER_FLAG 31
|
||||
#define OVERFLOW_FLAG 1
|
||||
#define EQUAL_FLAG 31
|
||||
#define OTHER_FLAG 1
|
||||
|
||||
#define TMP_FREG1 (0)
|
||||
#define TMP_FREG2 ((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) << 1)
|
||||
|
||||
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
|
||||
0, 2, 5, 6, 7, 8, 9, 10, 11, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 3, 25, 4
|
||||
0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 3, 25, 4
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -178,7 +173,13 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
#define CLZ (HI(28) | LO(32))
|
||||
#define DCLZ (HI(28) | LO(36))
|
||||
#define MOVF (HI(0) | (0 << 16) | LO(1))
|
||||
#define MOVN (HI(0) | LO(11))
|
||||
#define MOVT (HI(0) | (1 << 16) | LO(1))
|
||||
#define MOVZ (HI(0) | LO(10))
|
||||
#define MUL (HI(28) | LO(2))
|
||||
#define PREF (HI(51))
|
||||
#define PREFX (HI(19) | LO(15))
|
||||
#define SEB (HI(31) | (16 << 6) | LO(32))
|
||||
#define SEH (HI(31) | (24 << 6) | LO(32))
|
||||
#endif
|
||||
@ -218,7 +219,7 @@ static SLJIT_INLINE sljit_ins invert_branch(sljit_s32 flags)
|
||||
return (flags & IS_BIT26_COND) ? (1 << 26) : (1 << 16);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
|
||||
static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_sw diff;
|
||||
sljit_uw target_addr;
|
||||
@ -237,8 +238,9 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
|
||||
target_addr = jump->u.target;
|
||||
else {
|
||||
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
|
||||
}
|
||||
|
||||
inst = (sljit_ins *)jump->addr;
|
||||
if (jump->flags & IS_COND)
|
||||
inst--;
|
||||
@ -250,7 +252,7 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
|
||||
|
||||
/* B instructions. */
|
||||
if (jump->flags & IS_MOVABLE) {
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(inst)) >> 2;
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)inst - executable_offset) >> 2;
|
||||
if (diff <= SIMM_MAX && diff >= SIMM_MIN) {
|
||||
jump->flags |= PATCH_B;
|
||||
|
||||
@ -268,7 +270,7 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
|
||||
}
|
||||
}
|
||||
else {
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(inst + 1)) >> 2;
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(inst + 1) - executable_offset) >> 2;
|
||||
if (diff <= SIMM_MAX && diff >= SIMM_MIN) {
|
||||
jump->flags |= PATCH_B;
|
||||
|
||||
@ -364,6 +366,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
sljit_ins *buf_ptr;
|
||||
sljit_ins *buf_end;
|
||||
sljit_uw word_count;
|
||||
sljit_sw executable_offset;
|
||||
sljit_uw addr;
|
||||
|
||||
struct sljit_label *label;
|
||||
@ -380,9 +383,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
|
||||
code_ptr = code;
|
||||
word_count = 0;
|
||||
executable_offset = SLJIT_EXEC_OFFSET(code);
|
||||
|
||||
label = compiler->labels;
|
||||
jump = compiler->jumps;
|
||||
const_ = compiler->consts;
|
||||
|
||||
do {
|
||||
buf_ptr = (sljit_ins*)buf->memory;
|
||||
buf_end = buf_ptr + (buf->used_size >> 2);
|
||||
@ -393,8 +399,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
SLJIT_ASSERT(!const_ || const_->addr >= word_count);
|
||||
/* These structures are ordered by their address. */
|
||||
if (label && label->size == word_count) {
|
||||
/* Just recording the address. */
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
@ -404,7 +409,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
#else
|
||||
jump->addr = (sljit_uw)(code_ptr - 7);
|
||||
#endif
|
||||
code_ptr = detect_jump_type(jump, code_ptr, code);
|
||||
code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
|
||||
jump = jump->next;
|
||||
}
|
||||
if (const_ && const_->addr == word_count) {
|
||||
@ -437,13 +442,13 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
buf_ptr = (sljit_ins *)jump->addr;
|
||||
|
||||
if (jump->flags & PATCH_B) {
|
||||
addr = (sljit_sw)(addr - (jump->addr + sizeof(sljit_ins))) >> 2;
|
||||
addr = (sljit_sw)(addr - ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) + sizeof(sljit_ins))) >> 2;
|
||||
SLJIT_ASSERT((sljit_sw)addr <= SIMM_MAX && (sljit_sw)addr >= SIMM_MIN);
|
||||
buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | (addr & 0xffff);
|
||||
break;
|
||||
}
|
||||
if (jump->flags & PATCH_J) {
|
||||
SLJIT_ASSERT((addr & ~0xfffffff) == ((jump->addr + sizeof(sljit_ins)) & ~0xfffffff));
|
||||
SLJIT_ASSERT((addr & ~0xfffffff) == (((sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) + sizeof(sljit_ins)) & ~0xfffffff));
|
||||
buf_ptr[0] |= (addr >> 2) & 0x03ffffff;
|
||||
break;
|
||||
}
|
||||
@ -476,8 +481,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
}
|
||||
|
||||
compiler->error = SLJIT_ERR_COMPILED;
|
||||
compiler->executable_offset = executable_offset;
|
||||
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
|
||||
SLJIT_ENABLE_EXEC(code, code_ptr);
|
||||
|
||||
code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
|
||||
code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
#ifndef __GNUC__
|
||||
SLJIT_CACHE_FLUSH(code, code_ptr);
|
||||
#else
|
||||
@ -487,6 +496,31 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
return code;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
|
||||
{
|
||||
switch (feature_type) {
|
||||
case SLJIT_HAS_FPU:
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#elif defined(__GNUC__)
|
||||
sljit_sw fir;
|
||||
asm ("cfc1 %0, $0" : "=r"(fir));
|
||||
return (fir >> 22) & 0x1;
|
||||
#else
|
||||
#error "FIR check is not implemented for this architecture"
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
case SLJIT_HAS_CLZ:
|
||||
case SLJIT_HAS_CMOV:
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Entry, exit */
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -521,10 +555,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
#define SLOW_SRC2 0x20000
|
||||
#define SLOW_DEST 0x40000
|
||||
|
||||
/* Only these flags are set. UNUSED_DEST is not set when no flags should be set. */
|
||||
#define CHECK_FLAGS(list) \
|
||||
(!(flags & UNUSED_DEST) || (op & GET_FLAGS(~(list))))
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
#define STACK_STORE SW
|
||||
#define STACK_LOAD LW
|
||||
@ -760,18 +790,19 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
base = arg & REG_MASK;
|
||||
|
||||
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
|
||||
argw &= 0x3;
|
||||
if ((flags & WRITE_BACK) && reg_ar == DR(base)) {
|
||||
SLJIT_ASSERT(!(flags & LOAD_DATA) && DR(TMP_REG1) != reg_ar);
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | SA(reg_ar) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
reg_ar = DR(TMP_REG1);
|
||||
if (SLJIT_UNLIKELY(flags & WRITE_BACK)) {
|
||||
SLJIT_ASSERT(argw == 0);
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(OFFS_REG(arg)) | D(base), DR(base)));
|
||||
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), delay_slot);
|
||||
}
|
||||
|
||||
argw &= 0x3;
|
||||
|
||||
/* Using the cache. */
|
||||
if (argw == compiler->cache_argw) {
|
||||
if (!(flags & WRITE_BACK)) {
|
||||
if (arg == compiler->cache_arg)
|
||||
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
|
||||
|
||||
if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) {
|
||||
if (arg == next_arg && argw == (next_argw & 0x3)) {
|
||||
compiler->cache_arg = arg;
|
||||
@ -783,13 +814,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) {
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(base), DR(base)));
|
||||
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), delay_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SLJIT_UNLIKELY(argw)) {
|
||||
compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
|
||||
@ -797,7 +821,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(arg)) | D(TMP_REG3) | SH_IMM(argw), DR(TMP_REG3)));
|
||||
}
|
||||
|
||||
if (!(flags & WRITE_BACK)) {
|
||||
if (arg == next_arg && argw == (next_argw & 0x3)) {
|
||||
compiler->cache_arg = arg;
|
||||
compiler->cache_argw = argw;
|
||||
@ -808,24 +831,8 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | DA(tmp_ar), tmp_ar));
|
||||
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | D(base), DR(base)));
|
||||
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), delay_slot);
|
||||
}
|
||||
|
||||
if (SLJIT_UNLIKELY(flags & WRITE_BACK) && base) {
|
||||
/* Update only applies if a base register exists. */
|
||||
if (reg_ar == DR(base)) {
|
||||
SLJIT_ASSERT(!(flags & LOAD_DATA) && DR(TMP_REG1) != reg_ar);
|
||||
if (argw <= SIMM_MAX && argw >= SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar) | IMM(argw), MOVABLE_INS));
|
||||
if (argw)
|
||||
return push_inst(compiler, ADDIU_W | S(base) | T(base) | IMM(argw), DR(base));
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | SA(reg_ar) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
reg_ar = DR(TMP_REG1);
|
||||
}
|
||||
|
||||
if (argw <= SIMM_MAX && argw >= SIMM_MIN) {
|
||||
if (argw)
|
||||
FAIL_IF(push_inst(compiler, ADDIU_W | S(base) | T(base) | IMM(argw), DR(base)));
|
||||
@ -915,9 +922,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
||||
}
|
||||
|
||||
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
|
||||
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS;
|
||||
if (GET_FLAGS(op))
|
||||
SLJIT_ASSERT(HAS_FLAGS(op));
|
||||
flags |= UNUSED_DEST;
|
||||
}
|
||||
else if (FAST_IS_REG(dst)) {
|
||||
@ -1080,6 +1085,29 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
if (!(src & OFFS_REG_MASK)) {
|
||||
if (srcw <= SIMM_MAX && srcw >= SIMM_MIN)
|
||||
return push_inst(compiler, PREF | S(src & REG_MASK) | IMM(srcw), MOVABLE_INS);
|
||||
|
||||
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
|
||||
return push_inst(compiler, PREFX | S(src & REG_MASK) | T(TMP_REG1), MOVABLE_INS);
|
||||
}
|
||||
|
||||
srcw &= 0x3;
|
||||
|
||||
if (SLJIT_UNLIKELY(srcw != 0)) {
|
||||
FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(src)) | D(TMP_REG1) | SH_IMM(srcw), DR(TMP_REG1)));
|
||||
return push_inst(compiler, PREFX | S(src & REG_MASK) | T(TMP_REG1), MOVABLE_INS);
|
||||
}
|
||||
|
||||
return push_inst(compiler, PREFX | S(src & REG_MASK) | T(OFFS_REG(src)), MOVABLE_INS);
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
@ -1095,6 +1123,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op)) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op <= SLJIT_MOV_P && (src & SLJIT_MEM))
|
||||
return emit_prefetch(compiler, src, srcw);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if ((op & SLJIT_I32_OP) && GET_OPCODE(op) >= SLJIT_NOT) {
|
||||
flags |= INT_DATA | SIGNED_DATA;
|
||||
@ -1198,6 +1234,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if (op & SLJIT_I32_OP) {
|
||||
flags |= INT_DATA | SIGNED_DATA;
|
||||
@ -1274,19 +1313,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
|
||||
/* Floating point operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void)
|
||||
{
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#elif defined(__GNUC__)
|
||||
sljit_sw fir;
|
||||
asm ("cfc1 %0, $0" : "=r"(fir));
|
||||
return (fir >> 22) & 0x1;
|
||||
#else
|
||||
#error "FIR check is not implemented for this architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 7))
|
||||
#define FMT(op) (((op & SLJIT_F32_OP) ^ SLJIT_F32_OP) << (21 - 8))
|
||||
|
||||
@ -1309,9 +1335,6 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
|
||||
|
||||
FAIL_IF(push_inst(compiler, (TRUNC_W_S ^ (flags >> 19)) | FMT(op) | FS(src) | FD(TMP_FREG1), MOVABLE_INS));
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
return push_inst(compiler, MFC1 | flags | T(dst) | FS(TMP_FREG1), MOVABLE_INS);
|
||||
|
||||
@ -1365,6 +1388,8 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2, sljit_sw src2w)
|
||||
{
|
||||
sljit_ins inst;
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
|
||||
src1 = TMP_FREG1;
|
||||
@ -1379,25 +1404,26 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
|
||||
else
|
||||
src2 <<= 1;
|
||||
|
||||
/* src2 and src1 are swapped. */
|
||||
if (op & SLJIT_SET_E) {
|
||||
FAIL_IF(push_inst(compiler, C_UEQ_S | FMT(op) | FT(src2) | FS(src1), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, CFC1 | TA(EQUAL_FLAG) | DA(FCSR_REG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, SRL | TA(EQUAL_FLAG) | DA(EQUAL_FLAG) | SH_IMM(23), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ANDI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG));
|
||||
switch (GET_FLAG_TYPE(op)) {
|
||||
case SLJIT_EQUAL_F64:
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
inst = C_UEQ_S;
|
||||
break;
|
||||
case SLJIT_LESS_F64:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
inst = C_ULT_S;
|
||||
break;
|
||||
case SLJIT_GREATER_F64:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
inst = C_ULE_S;
|
||||
break;
|
||||
default:
|
||||
SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_UNORDERED_F64 || GET_FLAG_TYPE(op) == SLJIT_ORDERED_F64);
|
||||
inst = C_UN_S;
|
||||
break;
|
||||
}
|
||||
if (op & SLJIT_SET_S) {
|
||||
/* Mixing the instructions for the two checks. */
|
||||
FAIL_IF(push_inst(compiler, C_ULT_S | FMT(op) | FT(src2) | FS(src1), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, CFC1 | TA(ULESS_FLAG) | DA(FCSR_REG), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, C_ULT_S | FMT(op) | FT(src1) | FS(src2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SRL | TA(ULESS_FLAG) | DA(ULESS_FLAG) | SH_IMM(23), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ANDI | SA(ULESS_FLAG) | TA(ULESS_FLAG) | IMM(1), ULESS_FLAG));
|
||||
FAIL_IF(push_inst(compiler, CFC1 | TA(UGREATER_FLAG) | DA(FCSR_REG), UGREATER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, SRL | TA(UGREATER_FLAG) | DA(UGREATER_FLAG) | SH_IMM(23), UGREATER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, ANDI | SA(UGREATER_FLAG) | TA(UGREATER_FLAG) | IMM(1), UGREATER_FLAG));
|
||||
}
|
||||
return push_inst(compiler, C_UN_S | FMT(op) | FT(src2) | FS(src1), FCSR_FCC);
|
||||
|
||||
return push_inst(compiler, inst | FMT(op) | FT(src2) | FS(src1), UNMOVABLE_INS);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
@ -1543,10 +1569,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), DR(dst));
|
||||
|
||||
@ -1626,7 +1648,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
||||
sljit_s32 delay_check = UNMOVABLE_INS;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_jump(compiler, type));
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
@ -1636,55 +1657,39 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
||||
|
||||
switch (type) {
|
||||
case SLJIT_EQUAL:
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
BR_NZ(EQUAL_FLAG);
|
||||
break;
|
||||
case SLJIT_NOT_EQUAL:
|
||||
case SLJIT_EQUAL_F64:
|
||||
BR_Z(EQUAL_FLAG);
|
||||
break;
|
||||
case SLJIT_LESS:
|
||||
case SLJIT_LESS_F64:
|
||||
BR_Z(ULESS_FLAG);
|
||||
break;
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
BR_NZ(ULESS_FLAG);
|
||||
break;
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_GREATER_F64:
|
||||
BR_Z(UGREATER_FLAG);
|
||||
break;
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
BR_NZ(UGREATER_FLAG);
|
||||
break;
|
||||
case SLJIT_SIG_LESS:
|
||||
BR_Z(LESS_FLAG);
|
||||
break;
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
BR_NZ(LESS_FLAG);
|
||||
break;
|
||||
case SLJIT_SIG_GREATER:
|
||||
BR_Z(GREATER_FLAG);
|
||||
break;
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
BR_NZ(GREATER_FLAG);
|
||||
break;
|
||||
case SLJIT_OVERFLOW:
|
||||
case SLJIT_MUL_OVERFLOW:
|
||||
BR_Z(OVERFLOW_FLAG);
|
||||
BR_Z(OTHER_FLAG);
|
||||
break;
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
case SLJIT_NOT_OVERFLOW:
|
||||
case SLJIT_MUL_NOT_OVERFLOW:
|
||||
BR_NZ(OVERFLOW_FLAG);
|
||||
break;
|
||||
case SLJIT_UNORDERED_F64:
|
||||
BR_F();
|
||||
BR_NZ(OTHER_FLAG);
|
||||
break;
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
case SLJIT_GREATER_F64:
|
||||
case SLJIT_ORDERED_F64:
|
||||
BR_T();
|
||||
break;
|
||||
case SLJIT_EQUAL_F64:
|
||||
case SLJIT_LESS_F64:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
case SLJIT_UNORDERED_F64:
|
||||
BR_F();
|
||||
break;
|
||||
default:
|
||||
/* Not conditional branch. */
|
||||
inst = 0;
|
||||
@ -1744,7 +1749,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
|
||||
sljit_ins inst;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
@ -1857,87 +1861,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
|
||||
#undef RESOLVE_IMM1
|
||||
#undef RESOLVE_IMM2
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2, sljit_sw src2w)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_ins inst;
|
||||
sljit_s32 if_true;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w));
|
||||
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
PTR_FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(type) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
|
||||
src1 = TMP_FREG1;
|
||||
}
|
||||
else
|
||||
src1 <<= 1;
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
PTR_FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(type) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0));
|
||||
src2 = TMP_FREG2;
|
||||
}
|
||||
else
|
||||
src2 <<= 1;
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
|
||||
jump->flags |= IS_BIT16_COND;
|
||||
|
||||
switch (type & 0xff) {
|
||||
case SLJIT_EQUAL_F64:
|
||||
inst = C_UEQ_S;
|
||||
if_true = 1;
|
||||
break;
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
inst = C_UEQ_S;
|
||||
if_true = 0;
|
||||
break;
|
||||
case SLJIT_LESS_F64:
|
||||
inst = C_ULT_S;
|
||||
if_true = 1;
|
||||
break;
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
inst = C_ULT_S;
|
||||
if_true = 0;
|
||||
break;
|
||||
case SLJIT_GREATER_F64:
|
||||
inst = C_ULE_S;
|
||||
if_true = 0;
|
||||
break;
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
inst = C_ULE_S;
|
||||
if_true = 1;
|
||||
break;
|
||||
case SLJIT_UNORDERED_F64:
|
||||
inst = C_UN_S;
|
||||
if_true = 1;
|
||||
break;
|
||||
default: /* Make compilers happy. */
|
||||
SLJIT_ASSERT_STOP();
|
||||
case SLJIT_ORDERED_F64:
|
||||
inst = C_UN_S;
|
||||
if_true = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, inst | FMT(type) | FT(src2) | FS(src1), UNMOVABLE_INS));
|
||||
/* Intentionally the other opcode. */
|
||||
PTR_FAIL_IF(push_inst(compiler, (if_true ? BC1F : BC1T) | JUMP_LENGTH, UNMOVABLE_INS));
|
||||
PTR_FAIL_IF(emit_const(compiler, TMP_REG2, 0));
|
||||
PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS));
|
||||
jump->addr = compiler->size;
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
|
||||
return jump;
|
||||
}
|
||||
|
||||
#undef JUMP_LENGTH
|
||||
#undef BR_Z
|
||||
#undef BR_NZ
|
||||
@ -2007,115 +1930,160 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw,
|
||||
sljit_s32 type)
|
||||
{
|
||||
sljit_s32 sugg_dst_ar, dst_ar;
|
||||
sljit_s32 flags = GET_ALL_FLAGS(op);
|
||||
sljit_s32 src_ar, dst_ar;
|
||||
sljit_s32 saved_op = op;
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
# define mem_type WORD_DATA
|
||||
sljit_s32 mem_type = WORD_DATA;
|
||||
#else
|
||||
sljit_s32 mem_type = (op & SLJIT_I32_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
|
||||
#endif
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if (op == SLJIT_MOV_S32 || op == SLJIT_MOV_U32)
|
||||
if (op == SLJIT_MOV_S32)
|
||||
mem_type = INT_DATA | SIGNED_DATA;
|
||||
#endif
|
||||
sugg_dst_ar = DR((op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2);
|
||||
dst_ar = DR((op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2);
|
||||
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, DR(TMP_REG1), src, srcw, dst, dstw));
|
||||
src = TMP_REG1;
|
||||
srcw = 0;
|
||||
}
|
||||
|
||||
if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
|
||||
FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, DR(TMP_REG1), dst, dstw, dst, dstw));
|
||||
|
||||
switch (type & 0xff) {
|
||||
case SLJIT_EQUAL:
|
||||
case SLJIT_NOT_EQUAL:
|
||||
FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(sugg_dst_ar) | IMM(1), sugg_dst_ar));
|
||||
dst_ar = sugg_dst_ar;
|
||||
break;
|
||||
case SLJIT_LESS:
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_LESS_F64:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
dst_ar = ULESS_FLAG;
|
||||
break;
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_GREATER_F64:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
dst_ar = UGREATER_FLAG;
|
||||
break;
|
||||
case SLJIT_SIG_LESS:
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
dst_ar = LESS_FLAG;
|
||||
break;
|
||||
case SLJIT_SIG_GREATER:
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
dst_ar = GREATER_FLAG;
|
||||
break;
|
||||
case SLJIT_OVERFLOW:
|
||||
case SLJIT_NOT_OVERFLOW:
|
||||
dst_ar = OVERFLOW_FLAG;
|
||||
FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
|
||||
src_ar = dst_ar;
|
||||
break;
|
||||
case SLJIT_MUL_OVERFLOW:
|
||||
case SLJIT_MUL_NOT_OVERFLOW:
|
||||
FAIL_IF(push_inst(compiler, SLTIU | SA(OVERFLOW_FLAG) | TA(sugg_dst_ar) | IMM(1), sugg_dst_ar));
|
||||
dst_ar = sugg_dst_ar;
|
||||
FAIL_IF(push_inst(compiler, SLTIU | SA(OTHER_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
|
||||
src_ar = dst_ar;
|
||||
type ^= 0x1; /* Flip type bit for the XORI below. */
|
||||
break;
|
||||
case SLJIT_GREATER_F64:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
type ^= 0x1; /* Flip type bit for the XORI below. */
|
||||
case SLJIT_EQUAL_F64:
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
dst_ar = EQUAL_FLAG;
|
||||
break;
|
||||
|
||||
case SLJIT_LESS_F64:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
case SLJIT_UNORDERED_F64:
|
||||
case SLJIT_ORDERED_F64:
|
||||
FAIL_IF(push_inst(compiler, CFC1 | TA(sugg_dst_ar) | DA(FCSR_REG), sugg_dst_ar));
|
||||
FAIL_IF(push_inst(compiler, SRL | TA(sugg_dst_ar) | DA(sugg_dst_ar) | SH_IMM(23), sugg_dst_ar));
|
||||
FAIL_IF(push_inst(compiler, ANDI | SA(sugg_dst_ar) | TA(sugg_dst_ar) | IMM(1), sugg_dst_ar));
|
||||
dst_ar = sugg_dst_ar;
|
||||
FAIL_IF(push_inst(compiler, CFC1 | TA(dst_ar) | DA(FCSR_REG), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, SRL | TA(dst_ar) | DA(dst_ar) | SH_IMM(23), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, ANDI | SA(dst_ar) | TA(dst_ar) | IMM(1), dst_ar));
|
||||
src_ar = dst_ar;
|
||||
break;
|
||||
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
dst_ar = sugg_dst_ar;
|
||||
src_ar = OTHER_FLAG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (type & 0x1) {
|
||||
FAIL_IF(push_inst(compiler, XORI | SA(dst_ar) | TA(sugg_dst_ar) | IMM(1), sugg_dst_ar));
|
||||
dst_ar = sugg_dst_ar;
|
||||
FAIL_IF(push_inst(compiler, XORI | SA(src_ar) | TA(dst_ar) | IMM(1), dst_ar));
|
||||
src_ar = dst_ar;
|
||||
}
|
||||
|
||||
if (op >= SLJIT_ADD) {
|
||||
if (DR(TMP_REG2) != dst_ar)
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | SA(dst_ar) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
|
||||
return emit_op(compiler, op | flags, mem_type | CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0);
|
||||
if (op < SLJIT_ADD) {
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, mem_type, src_ar, dst, dstw);
|
||||
|
||||
if (src_ar != dst_ar)
|
||||
return push_inst(compiler, ADDU_W | SA(src_ar) | TA(0) | DA(dst_ar), dst_ar);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* OTHER_FLAG cannot be specified as src2 argument at the moment. */
|
||||
if (DR(TMP_REG2) != src_ar)
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | SA(src_ar) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
|
||||
|
||||
mem_type |= CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, mem_type, dst_ar, dst, dstw);
|
||||
return emit_op(compiler, saved_op, mem_type, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
|
||||
return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, TMP_REG2, 0);
|
||||
}
|
||||
|
||||
if (sugg_dst_ar != dst_ar)
|
||||
return push_inst(compiler, ADDU_W | SA(dst_ar) | TA(0) | DA(sugg_dst_ar), sugg_dst_ar);
|
||||
return SLJIT_SUCCESS;
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
sljit_ins ins;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
# undef mem_type
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
|
||||
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
|
||||
if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if (dst_reg & SLJIT_I32_OP)
|
||||
srcw = (sljit_s32)srcw;
|
||||
#endif
|
||||
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
|
||||
src = TMP_REG1;
|
||||
srcw = 0;
|
||||
}
|
||||
|
||||
dst_reg &= ~SLJIT_I32_OP;
|
||||
|
||||
switch (type & 0xff) {
|
||||
case SLJIT_EQUAL:
|
||||
ins = MOVZ | TA(EQUAL_FLAG);
|
||||
break;
|
||||
case SLJIT_NOT_EQUAL:
|
||||
ins = MOVN | TA(EQUAL_FLAG);
|
||||
break;
|
||||
case SLJIT_LESS:
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_SIG_LESS:
|
||||
case SLJIT_SIG_GREATER:
|
||||
case SLJIT_OVERFLOW:
|
||||
case SLJIT_MUL_OVERFLOW:
|
||||
ins = MOVN | TA(OTHER_FLAG);
|
||||
break;
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
case SLJIT_NOT_OVERFLOW:
|
||||
case SLJIT_MUL_NOT_OVERFLOW:
|
||||
ins = MOVZ | TA(OTHER_FLAG);
|
||||
break;
|
||||
case SLJIT_EQUAL_F64:
|
||||
case SLJIT_LESS_F64:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
case SLJIT_UNORDERED_F64:
|
||||
ins = MOVT;
|
||||
break;
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
case SLJIT_GREATER_F64:
|
||||
case SLJIT_ORDERED_F64:
|
||||
ins = MOVF;
|
||||
break;
|
||||
default:
|
||||
ins = MOVZ | TA(OTHER_FLAG);
|
||||
SLJIT_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
return push_inst(compiler, ins | S(src) | D(dst_reg), DR(dst_reg));
|
||||
|
||||
#else
|
||||
return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2125,7 +2093,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
sljit_s32 reg;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(1);
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
@ -2133,7 +2100,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
PTR_FAIL_IF(!const_);
|
||||
set_const(const_, compiler);
|
||||
|
||||
reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
PTR_FAIL_IF(emit_const(compiler, reg, init_value));
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -88,77 +88,86 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, NEG | OE((flags & ALT_FORM1) ? ALT_SET_FLAGS : 0) | RC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZW | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
|
||||
if (flags & ALT_FORM3)
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1))));
|
||||
src1 = dst;
|
||||
}
|
||||
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM4) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
if (flags & ALT_FORM4)
|
||||
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
if (flags & ALT_FORM1) {
|
||||
FAIL_IF(push_inst(compiler, MFXER | D(0)));
|
||||
FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, MTXER | S(0));
|
||||
}
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
if (flags & ALT_FORM2) {
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2)));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM3) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM2 | ALT_FORM3)) {
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
if (flags & ALT_FORM5) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2)
|
||||
FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm));
|
||||
if (flags & ALT_FORM3)
|
||||
return push_inst(compiler, CMPLI | CRD(4) | A(src1) | compiler->imm);
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM4 | ALT_FORM5)) {
|
||||
if (flags & ALT_FORM4)
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(4) | A(src1) | B(src2)));
|
||||
if (flags & ALT_FORM5)
|
||||
FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2)));
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2));
|
||||
}
|
||||
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
if (flags & ALT_FORM6)
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(4) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
if (flags & ALT_FORM5)
|
||||
return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, SUBF | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if (flags & ALT_FORM1) {
|
||||
FAIL_IF(push_inst(compiler, MFXER | D(0)));
|
||||
FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
|
||||
return push_inst(compiler, MTXER | S(0));
|
||||
}
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
@ -166,7 +175,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
@ -228,19 +237,15 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM3)
|
||||
FAIL_IF(push_inst(compiler, MFXER | D(0)));
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)));
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2)));
|
||||
return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS;
|
||||
return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -250,20 +255,22 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_addr & 0xffff);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -204,84 +204,118 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
|
||||
if ((flags & (ALT_FORM1 | ALT_SIGN_EXT)) == (ALT_FORM1 | ALT_SIGN_EXT)) {
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
|
||||
FAIL_IF(push_inst(compiler, NEG | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(TMP_REG2)));
|
||||
return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
|
||||
}
|
||||
|
||||
UN_EXTS();
|
||||
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, NEG | OE((flags & ALT_FORM1) ? ALT_SET_FLAGS : 0) | RC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (flags & ALT_FORM1)
|
||||
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZD | RC(flags) | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZW | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZD | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
|
||||
if (flags & ALT_SIGN_EXT) {
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
|
||||
src1 = TMP_REG1;
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
FAIL_IF(push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)));
|
||||
if (flags & ALT_SIGN_EXT)
|
||||
return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
|
||||
if (flags & ALT_FORM3)
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1))));
|
||||
src1 = dst;
|
||||
}
|
||||
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
BIN_IMM_EXTS();
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM4) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
if (flags & ALT_FORM4)
|
||||
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
if (flags & ALT_FORM1) {
|
||||
FAIL_IF(push_inst(compiler, MFXER | D(0)));
|
||||
FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, MTXER | S(0));
|
||||
}
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
if (flags & ALT_FORM2) {
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
if (flags & ALT_SIGN_EXT) {
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
|
||||
src1 = TMP_REG1;
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
FAIL_IF(push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)));
|
||||
if (flags & ALT_SIGN_EXT)
|
||||
return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM3) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM2 | ALT_FORM3)) {
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
if (flags & ALT_FORM5) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2)
|
||||
FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
|
||||
if (flags & ALT_FORM3)
|
||||
return push_inst(compiler, CMPLI | CRD(4 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM4 | ALT_FORM5)) {
|
||||
if (flags & ALT_FORM4)
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(4 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
|
||||
if (flags & ALT_FORM5)
|
||||
return push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM6)
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(4 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
if (flags & ALT_FORM5)
|
||||
return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, SUBF | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if (flags & ALT_FORM1) {
|
||||
FAIL_IF(push_inst(compiler, MFXER | D(0)));
|
||||
FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
|
||||
return push_inst(compiler, MTXER | S(0));
|
||||
}
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
@ -292,8 +326,8 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
}
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM2)
|
||||
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLD | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLD | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
@ -345,11 +379,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
else {
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
|
||||
}
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
@ -359,33 +391,25 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
else {
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
|
||||
}
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM3)
|
||||
FAIL_IF(push_inst(compiler, MFXER | D(0)));
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)));
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
else {
|
||||
compiler->imm &= 0x3f;
|
||||
FAIL_IF(push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4)));
|
||||
return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4));
|
||||
}
|
||||
}
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2)));
|
||||
return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -398,18 +422,19 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_addr >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_addr & 0xffff);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
@ -417,5 +442,6 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -127,9 +127,9 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
|
||||
|
||||
/* Instruction bit sections.
|
||||
OE and Rc flag (see ALT_SET_FLAGS). */
|
||||
#define OERC(flags) (((flags & ALT_SET_FLAGS) >> 10) | (flags & ALT_SET_FLAGS))
|
||||
#define OE(flags) ((flags) & ALT_SET_FLAGS)
|
||||
/* Rc flag (see ALT_SET_FLAGS). */
|
||||
#define RC(flags) ((flags & ALT_SET_FLAGS) >> 10)
|
||||
#define RC(flags) (((flags) & ALT_SET_FLAGS) >> 10)
|
||||
#define HI(opcode) ((opcode) << 26)
|
||||
#define LO(opcode) ((opcode) << 1)
|
||||
|
||||
@ -154,6 +154,7 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
|
||||
#define CMPL (HI(31) | LO(32))
|
||||
#define CMPLI (HI(10))
|
||||
#define CROR (HI(19) | LO(449))
|
||||
#define DCBT (HI(31) | LO(278))
|
||||
#define DIVD (HI(31) | LO(489))
|
||||
#define DIVDU (HI(31) | LO(457))
|
||||
#define DIVW (HI(31) | LO(491))
|
||||
@ -249,7 +250,7 @@ static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
|
||||
static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_sw diff;
|
||||
sljit_uw target_addr;
|
||||
@ -267,7 +268,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_in
|
||||
target_addr = jump->u.target;
|
||||
else {
|
||||
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
|
||||
}
|
||||
|
||||
#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
@ -275,7 +276,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_in
|
||||
goto keep_address;
|
||||
#endif
|
||||
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr)) & ~0x3l;
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l;
|
||||
|
||||
extra_jump_flags = 0;
|
||||
if (jump->flags & IS_COND) {
|
||||
@ -296,6 +297,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_in
|
||||
jump->flags |= PATCH_B | extra_jump_flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (target_addr <= 0x03ffffff) {
|
||||
jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags;
|
||||
return 1;
|
||||
@ -309,6 +311,7 @@ keep_address:
|
||||
jump->flags |= PATCH_ABS32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (target_addr <= 0x7fffffffffffl) {
|
||||
jump->flags |= PATCH_ABS48;
|
||||
return 1;
|
||||
@ -326,6 +329,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
sljit_ins *buf_ptr;
|
||||
sljit_ins *buf_end;
|
||||
sljit_uw word_count;
|
||||
sljit_sw executable_offset;
|
||||
sljit_uw addr;
|
||||
|
||||
struct sljit_label *label;
|
||||
@ -349,9 +353,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
|
||||
code_ptr = code;
|
||||
word_count = 0;
|
||||
executable_offset = SLJIT_EXEC_OFFSET(code);
|
||||
|
||||
label = compiler->labels;
|
||||
jump = compiler->jumps;
|
||||
const_ = compiler->consts;
|
||||
|
||||
do {
|
||||
buf_ptr = (sljit_ins*)buf->memory;
|
||||
buf_end = buf_ptr + (buf->used_size >> 2);
|
||||
@ -363,7 +370,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
/* These structures are ordered by their address. */
|
||||
if (label && label->size == word_count) {
|
||||
/* Just recording the address. */
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
@ -373,7 +380,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
#else
|
||||
jump->addr = (sljit_uw)(code_ptr - 6);
|
||||
#endif
|
||||
if (detect_jump_type(jump, code_ptr, code)) {
|
||||
if (detect_jump_type(jump, code_ptr, code, executable_offset)) {
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
code_ptr[-3] = code_ptr[0];
|
||||
code_ptr -= 3;
|
||||
@ -420,7 +427,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
@ -439,10 +446,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
do {
|
||||
addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
|
||||
buf_ptr = (sljit_ins *)jump->addr;
|
||||
|
||||
if (jump->flags & PATCH_B) {
|
||||
if (jump->flags & IS_COND) {
|
||||
if (!(jump->flags & PATCH_ABS_B)) {
|
||||
addr = addr - jump->addr;
|
||||
addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
|
||||
SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);
|
||||
*buf_ptr = BCx | (addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001);
|
||||
}
|
||||
@ -453,7 +461,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
}
|
||||
else {
|
||||
if (!(jump->flags & PATCH_ABS_B)) {
|
||||
addr = addr - jump->addr;
|
||||
addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
|
||||
SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);
|
||||
*buf_ptr = Bx | (addr & 0x03fffffc) | ((*buf_ptr) & 0x1);
|
||||
}
|
||||
@ -464,6 +472,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the fields of immediate loads. */
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
|
||||
@ -492,25 +501,50 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
}
|
||||
|
||||
compiler->error = SLJIT_ERR_COMPILED;
|
||||
compiler->executable_offset = executable_offset;
|
||||
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
|
||||
SLJIT_ENABLE_EXEC(code, code_ptr);
|
||||
SLJIT_CACHE_FLUSH(code, code_ptr);
|
||||
|
||||
code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
|
||||
|
||||
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
if (((sljit_sw)code_ptr) & 0x4)
|
||||
code_ptr++;
|
||||
sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code);
|
||||
return code_ptr;
|
||||
#else
|
||||
sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code);
|
||||
return code_ptr;
|
||||
#endif
|
||||
sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code);
|
||||
#endif
|
||||
|
||||
code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
SLJIT_CACHE_FLUSH(code, code_ptr);
|
||||
|
||||
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
|
||||
return code_ptr;
|
||||
#else
|
||||
return code;
|
||||
#endif
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
|
||||
{
|
||||
switch (feature_type) {
|
||||
case SLJIT_HAS_FPU:
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#else
|
||||
/* Available by default. */
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
case SLJIT_HAS_PRE_UPDATE:
|
||||
case SLJIT_HAS_CLZ:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Entry, exit */
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -545,7 +579,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
#define ALT_FORM3 0x040000
|
||||
#define ALT_FORM4 0x080000
|
||||
#define ALT_FORM5 0x100000
|
||||
#define ALT_FORM6 0x200000
|
||||
|
||||
/* Source and destination is register. */
|
||||
#define REG_DEST 0x000001
|
||||
@ -560,7 +593,7 @@ ALT_SIGN_EXT 0x000200
|
||||
ALT_SET_FLAGS 0x000400
|
||||
ALT_FORM1 0x010000
|
||||
...
|
||||
ALT_FORM6 0x200000 */
|
||||
ALT_FORM5 0x100000 */
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
#include "sljitNativePPC_32.c"
|
||||
@ -851,7 +884,7 @@ static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 inp_
|
||||
sljit_ins inst;
|
||||
|
||||
/* Should work when (arg & REG_MASK) == 0. */
|
||||
SLJIT_COMPILE_ASSERT(A(0) == 0, a0_must_be_0);
|
||||
SLJIT_ASSERT(A(0) == 0);
|
||||
SLJIT_ASSERT(arg & SLJIT_MEM);
|
||||
|
||||
if (arg & OFFS_REG_MASK) {
|
||||
@ -1006,10 +1039,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 inp_flags
|
||||
#endif
|
||||
|
||||
if (inp_flags & WRITE_BACK) {
|
||||
if (arg == reg) {
|
||||
FAIL_IF(push_inst(compiler, OR | S(reg) | A(tmp_r) | B(reg)));
|
||||
reg = tmp_r;
|
||||
}
|
||||
tmp_r = arg;
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(arg) | A(arg) | IMM(high_short >> 16)));
|
||||
}
|
||||
@ -1132,7 +1161,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
||||
sljit_s32 src1_r;
|
||||
sljit_s32 src2_r;
|
||||
sljit_s32 sugg_src2_r = TMP_REG2;
|
||||
sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_FORM6 | ALT_SIGN_EXT | ALT_SET_FLAGS);
|
||||
sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_SIGN_EXT | ALT_SET_FLAGS);
|
||||
|
||||
if (!(input_flags & ALT_KEEP_CACHE)) {
|
||||
compiler->cache_arg = 0;
|
||||
@ -1141,8 +1170,6 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
||||
|
||||
/* Destination check. */
|
||||
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
|
||||
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS;
|
||||
dst_r = TMP_REG2;
|
||||
}
|
||||
else if (FAST_IS_REG(dst)) {
|
||||
@ -1295,6 +1322,31 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
if (!(src & OFFS_REG_MASK)) {
|
||||
if (srcw == 0 && (src & REG_MASK) != SLJIT_UNUSED)
|
||||
return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK));
|
||||
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
|
||||
/* Works with SLJIT_MEM0() case as well. */
|
||||
return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
|
||||
}
|
||||
|
||||
srcw &= 0x3;
|
||||
|
||||
if (srcw == 0)
|
||||
return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src)));
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(src)) | A(TMP_REG1) | (srcw << 11) | ((31 - srcw) << 1)));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, OFFS_REG(src), srcw, 63 - srcw, 1)));
|
||||
#endif
|
||||
return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
|
||||
}
|
||||
|
||||
#define EMIT_MOV(type, type_flags, type_cast) \
|
||||
emit_op(compiler, (src & SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? type_cast srcw : srcw)
|
||||
|
||||
@ -1302,7 +1354,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0;
|
||||
sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
|
||||
sljit_s32 op_flags = GET_ALL_FLAGS(op);
|
||||
|
||||
CHECK_ERROR();
|
||||
@ -1310,11 +1362,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op)) {
|
||||
if (op <= SLJIT_MOV_P && (src & SLJIT_MEM))
|
||||
return emit_prefetch(compiler, src, srcw);
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
if ((src & SLJIT_IMM) && srcw == 0)
|
||||
src = TMP_ZERO;
|
||||
|
||||
if (op_flags & SLJIT_SET_O)
|
||||
if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW)
|
||||
FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
|
||||
|
||||
if (op_flags & SLJIT_I32_OP) {
|
||||
@ -1340,6 +1399,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
flags |= INT_DATA | SIGNED_DATA;
|
||||
if (src & SLJIT_IMM)
|
||||
srcw = (sljit_s32)srcw;
|
||||
if (HAS_FLAGS(op_flags))
|
||||
flags |= ALT_SIGN_EXT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -1405,7 +1466,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw);
|
||||
|
||||
case SLJIT_NEG:
|
||||
return emit_op(compiler, SLJIT_NEG, flags, dst, dstw, TMP_REG1, 0, src, srcw);
|
||||
return emit_op(compiler, SLJIT_NEG, flags | (GET_FLAG_TYPE(op_flags) ? ALT_FORM1 : 0), dst, dstw, TMP_REG1, 0, src, srcw);
|
||||
|
||||
case SLJIT_CLZ:
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
@ -1458,7 +1519,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2, sljit_sw src2w)
|
||||
{
|
||||
sljit_s32 flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0;
|
||||
sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
|
||||
@ -1466,6 +1527,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if ((src1 & SLJIT_IMM) && src1w == 0)
|
||||
src1 = TMP_ZERO;
|
||||
if ((src2 & SLJIT_IMM) && src2w == 0)
|
||||
@ -1479,45 +1543,48 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
src1w = (sljit_s32)(src1w);
|
||||
if (src2 & SLJIT_IMM)
|
||||
src2w = (sljit_s32)(src2w);
|
||||
if (GET_FLAGS(op))
|
||||
if (HAS_FLAGS(op))
|
||||
flags |= ALT_SIGN_EXT;
|
||||
}
|
||||
#endif
|
||||
if (op & SLJIT_SET_O)
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
|
||||
FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
|
||||
if (src2 == TMP_REG2)
|
||||
flags |= ALT_KEEP_CACHE;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_ADD:
|
||||
if (!GET_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
|
||||
if (TEST_SL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
if (TEST_SL_IMM(src1, src1w)) {
|
||||
compiler->imm = src1w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
if (TEST_SH_IMM(src2, src2w)) {
|
||||
compiler->imm = (src2w >> 16) & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
if (TEST_SH_IMM(src1, src1w)) {
|
||||
compiler->imm = (src1w >> 16) & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
/* Range between -1 and -32768 is covered above. */
|
||||
if (TEST_ADD_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffffffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
if (TEST_ADD_IMM(src1, src1w)) {
|
||||
compiler->imm = src1w & 0xffffffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
if (!(GET_FLAGS(op) & (SLJIT_SET_E | SLJIT_SET_O))) {
|
||||
if (HAS_FLAGS(op)) {
|
||||
if (TEST_SL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
@ -1527,75 +1594,75 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
return emit_op(compiler, SLJIT_ADD, flags, dst, dstw, src1, src1w, src2, src2w);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM4 : 0), dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return emit_op(compiler, SLJIT_ADDC, flags | (!(op & SLJIT_KEEP_FLAGS) ? 0 : ALT_FORM1), dst, dstw, src1, src1w, src2, src2w);
|
||||
return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (!GET_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
|
||||
if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL) {
|
||||
if (dst == SLJIT_UNUSED) {
|
||||
if (TEST_UL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= (SIMM_MAX + 1)) {
|
||||
compiler->imm = src2w;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
|
||||
if (TEST_SL_IMM(src2, -src2w)) {
|
||||
compiler->imm = (-src2w) & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
if (TEST_SL_IMM(src1, src1w)) {
|
||||
compiler->imm = src1w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
if (TEST_SH_IMM(src2, -src2w)) {
|
||||
compiler->imm = ((-src2w) >> 16) & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
/* Range between -1 and -32768 is covered above. */
|
||||
if (TEST_ADD_IMM(src2, -src2w)) {
|
||||
compiler->imm = -src2w & 0xffffffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
if (dst == SLJIT_UNUSED && (op & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S)) && !(op & (SLJIT_SET_O | SLJIT_SET_C))) {
|
||||
if (!(op & SLJIT_SET_U)) {
|
||||
/* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP on 64 bit systems. */
|
||||
|
||||
if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) != GET_FLAG_TYPE(SLJIT_SET_CARRY)) {
|
||||
if (TEST_SL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
if (GET_FLAGS(op) == SLJIT_SET_E && TEST_SL_IMM(src1, src1w)) {
|
||||
compiler->imm = src1w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
if (!(op & (SLJIT_SET_E | SLJIT_SET_S))) {
|
||||
/* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP on 64 bit systems. */
|
||||
if (TEST_UL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= 0x7fff) {
|
||||
compiler->imm = src2w;
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ((op & SLJIT_SET_U) ? ALT_FORM4 : 0) | ((op & (SLJIT_SET_E | SLJIT_SET_S)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
if (!(op & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O))) {
|
||||
|
||||
if (TEST_SL_IMM(src2, -src2w)) {
|
||||
compiler->imm = (-src2w) & 0xffff;
|
||||
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
/* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP on 64 bit systems. */
|
||||
return emit_op(compiler, SLJIT_SUB, flags | (!(op & SLJIT_SET_U) ? 0 : ALT_FORM6), dst, dstw, src1, src1w, src2, src2w);
|
||||
return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return emit_op(compiler, SLJIT_SUBC, flags | (!(op & SLJIT_KEEP_FLAGS) ? 0 : ALT_FORM1), dst, dstw, src1, src1w, src2, src2w);
|
||||
return emit_op(compiler, SLJIT_SUBC, flags, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
case SLJIT_MUL:
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
if (op & SLJIT_I32_OP)
|
||||
flags |= ALT_FORM2;
|
||||
#endif
|
||||
if (!GET_FLAGS(op)) {
|
||||
if (!HAS_FLAGS(op)) {
|
||||
if (TEST_SL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w & 0xffff;
|
||||
return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
@ -1605,13 +1672,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
|
||||
return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
case SLJIT_AND:
|
||||
case SLJIT_OR:
|
||||
case SLJIT_XOR:
|
||||
/* Commutative unsigned operations. */
|
||||
if (!GET_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {
|
||||
if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {
|
||||
if (TEST_UL_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w;
|
||||
return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
@ -1629,7 +1698,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
|
||||
}
|
||||
}
|
||||
if (!GET_FLAGS(op) && GET_OPCODE(op) != SLJIT_AND) {
|
||||
if (GET_OPCODE(op) != SLJIT_AND && GET_OPCODE(op) != SLJIT_AND) {
|
||||
/* Unlike or and xor, and resets unwanted bits as well. */
|
||||
if (TEST_UI_IMM(src2, src2w)) {
|
||||
compiler->imm = src2w;
|
||||
return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
|
||||
@ -1641,12 +1711,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
}
|
||||
return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (op & SLJIT_KEEP_FLAGS)
|
||||
flags |= ALT_FORM3;
|
||||
/* Fall through. */
|
||||
case SLJIT_SHL:
|
||||
case SLJIT_LSHR:
|
||||
case SLJIT_ASHR:
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
if (op & SLJIT_I32_OP)
|
||||
flags |= ALT_FORM2;
|
||||
@ -1686,16 +1753,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
|
||||
/* Floating point operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void)
|
||||
{
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#else
|
||||
/* Available by default. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 6))
|
||||
#define SELECT_FOP(op, single, double) ((op & SLJIT_F32_OP) ? single : double)
|
||||
|
||||
@ -1728,9 +1785,6 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
|
||||
op = GET_OPCODE(op);
|
||||
FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (op == SLJIT_CONV_SW_FROM_F64) {
|
||||
if (FAST_IS_REG(dst)) {
|
||||
FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, 0, 0));
|
||||
@ -1738,12 +1792,8 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
|
||||
}
|
||||
return emit_op_mem2(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, 0, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src)));
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
@ -2020,10 +2070,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
return push_inst(compiler, MFLR | D(dst));
|
||||
|
||||
@ -2080,33 +2126,33 @@ static sljit_ins get_bo_bi_flags(sljit_s32 type)
|
||||
return (4 << 21) | (2 << 16);
|
||||
|
||||
case SLJIT_LESS:
|
||||
case SLJIT_LESS_F64:
|
||||
return (12 << 21) | ((4 + 0) << 16);
|
||||
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
return (4 << 21) | ((4 + 0) << 16);
|
||||
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_GREATER_F64:
|
||||
return (12 << 21) | ((4 + 1) << 16);
|
||||
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
return (4 << 21) | ((4 + 1) << 16);
|
||||
|
||||
case SLJIT_SIG_LESS:
|
||||
return (12 << 21) | (0 << 16);
|
||||
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
return (4 << 21) | (0 << 16);
|
||||
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_SIG_GREATER:
|
||||
return (12 << 21) | (1 << 16);
|
||||
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
return (4 << 21) | (1 << 16);
|
||||
|
||||
case SLJIT_LESS_F64:
|
||||
return (12 << 21) | ((4 + 0) << 16);
|
||||
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
return (4 << 21) | ((4 + 0) << 16);
|
||||
|
||||
case SLJIT_GREATER_F64:
|
||||
return (12 << 21) | ((4 + 1) << 16);
|
||||
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
return (4 << 21) | ((4 + 1) << 16);
|
||||
|
||||
case SLJIT_OVERFLOW:
|
||||
case SLJIT_MUL_OVERFLOW:
|
||||
return (12 << 21) | (3 << 16);
|
||||
@ -2139,7 +2185,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
||||
sljit_ins bo_bi_flags;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_jump(compiler, type));
|
||||
|
||||
bo_bi_flags = get_bo_bi_flags(type & 0xff);
|
||||
@ -2209,153 +2254,148 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
|
||||
return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0));
|
||||
}
|
||||
|
||||
/* Get a bit from CR, all other bits are zeroed. */
|
||||
#define GET_CR_BIT(bit, dst) \
|
||||
FAIL_IF(push_inst(compiler, MFCR | D(dst))); \
|
||||
FAIL_IF(push_inst(compiler, RLWINM | S(dst) | A(dst) | ((1 + (bit)) << 11) | (31 << 6) | (31 << 1)));
|
||||
|
||||
#define INVERT_BIT(dst) \
|
||||
FAIL_IF(push_inst(compiler, XORI | S(dst) | A(dst) | 0x1));
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw,
|
||||
sljit_s32 type)
|
||||
{
|
||||
sljit_s32 reg, input_flags;
|
||||
sljit_s32 flags = GET_ALL_FLAGS(op);
|
||||
sljit_sw original_dstw = dstw;
|
||||
sljit_s32 reg, input_flags, cr_bit, invert;
|
||||
sljit_s32 saved_op = op;
|
||||
sljit_sw saved_dstw = dstw;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
input_flags = (op & SLJIT_I32_OP) ? INT_DATA : WORD_DATA;
|
||||
#else
|
||||
input_flags = WORD_DATA;
|
||||
#endif
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
|
||||
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
input_flags = (flags & SLJIT_I32_OP) ? INT_DATA : WORD_DATA;
|
||||
#else
|
||||
input_flags = WORD_DATA;
|
||||
#endif
|
||||
FAIL_IF(emit_op_mem2(compiler, input_flags | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
|
||||
src = TMP_REG1;
|
||||
srcw = 0;
|
||||
}
|
||||
|
||||
if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
|
||||
FAIL_IF(emit_op_mem2(compiler, input_flags | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
|
||||
|
||||
invert = 0;
|
||||
|
||||
switch (type & 0xff) {
|
||||
case SLJIT_EQUAL:
|
||||
GET_CR_BIT(2, reg);
|
||||
break;
|
||||
|
||||
case SLJIT_NOT_EQUAL:
|
||||
GET_CR_BIT(2, reg);
|
||||
INVERT_BIT(reg);
|
||||
break;
|
||||
|
||||
case SLJIT_LESS:
|
||||
case SLJIT_LESS_F64:
|
||||
GET_CR_BIT(4 + 0, reg);
|
||||
case SLJIT_SIG_LESS:
|
||||
cr_bit = 0;
|
||||
break;
|
||||
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
GET_CR_BIT(4 + 0, reg);
|
||||
INVERT_BIT(reg);
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
cr_bit = 0;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_GREATER_F64:
|
||||
GET_CR_BIT(4 + 1, reg);
|
||||
case SLJIT_SIG_GREATER:
|
||||
cr_bit = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_LESS_EQUAL:
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
GET_CR_BIT(4 + 1, reg);
|
||||
INVERT_BIT(reg);
|
||||
break;
|
||||
|
||||
case SLJIT_SIG_LESS:
|
||||
GET_CR_BIT(0, reg);
|
||||
break;
|
||||
|
||||
case SLJIT_SIG_GREATER_EQUAL:
|
||||
GET_CR_BIT(0, reg);
|
||||
INVERT_BIT(reg);
|
||||
break;
|
||||
|
||||
case SLJIT_SIG_GREATER:
|
||||
GET_CR_BIT(1, reg);
|
||||
break;
|
||||
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
GET_CR_BIT(1, reg);
|
||||
INVERT_BIT(reg);
|
||||
cr_bit = 1;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_EQUAL:
|
||||
cr_bit = 2;
|
||||
break;
|
||||
|
||||
case SLJIT_NOT_EQUAL:
|
||||
cr_bit = 2;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_OVERFLOW:
|
||||
case SLJIT_MUL_OVERFLOW:
|
||||
GET_CR_BIT(3, reg);
|
||||
cr_bit = 3;
|
||||
break;
|
||||
|
||||
case SLJIT_NOT_OVERFLOW:
|
||||
case SLJIT_MUL_NOT_OVERFLOW:
|
||||
GET_CR_BIT(3, reg);
|
||||
INVERT_BIT(reg);
|
||||
cr_bit = 3;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_LESS_F64:
|
||||
cr_bit = 4 + 0;
|
||||
break;
|
||||
|
||||
case SLJIT_GREATER_EQUAL_F64:
|
||||
cr_bit = 4 + 0;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_GREATER_F64:
|
||||
cr_bit = 4 + 1;
|
||||
break;
|
||||
|
||||
case SLJIT_LESS_EQUAL_F64:
|
||||
cr_bit = 4 + 1;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_EQUAL_F64:
|
||||
GET_CR_BIT(4 + 2, reg);
|
||||
cr_bit = 4 + 2;
|
||||
break;
|
||||
|
||||
case SLJIT_NOT_EQUAL_F64:
|
||||
GET_CR_BIT(4 + 2, reg);
|
||||
INVERT_BIT(reg);
|
||||
cr_bit = 4 + 2;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
case SLJIT_UNORDERED_F64:
|
||||
GET_CR_BIT(4 + 3, reg);
|
||||
cr_bit = 4 + 3;
|
||||
break;
|
||||
|
||||
case SLJIT_ORDERED_F64:
|
||||
GET_CR_BIT(4 + 3, reg);
|
||||
INVERT_BIT(reg);
|
||||
cr_bit = 4 + 3;
|
||||
invert = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
FAIL_IF(push_inst(compiler, MFCR | D(reg)));
|
||||
FAIL_IF(push_inst(compiler, RLWINM | S(reg) | A(reg) | ((1 + (cr_bit)) << 11) | (31 << 6) | (31 << 1)));
|
||||
|
||||
if (invert)
|
||||
FAIL_IF(push_inst(compiler, XORI | S(reg) | A(reg) | 0x1));
|
||||
|
||||
if (op < SLJIT_ADD) {
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
if (op == SLJIT_MOV)
|
||||
input_flags = WORD_DATA;
|
||||
else {
|
||||
op = SLJIT_MOV_U32;
|
||||
input_flags = INT_DATA;
|
||||
}
|
||||
#else
|
||||
op = SLJIT_MOV;
|
||||
input_flags = WORD_DATA;
|
||||
#endif
|
||||
if (reg != TMP_REG2)
|
||||
if (!(dst & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS;
|
||||
return emit_op(compiler, op, input_flags, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
|
||||
return emit_op_mem2(compiler, input_flags, reg, dst, dstw, reg, 0);
|
||||
}
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
return sljit_emit_op2(compiler, op | flags, dst, original_dstw, src, srcw, TMP_REG2, 0);
|
||||
if (dst & SLJIT_MEM)
|
||||
return sljit_emit_op2(compiler, saved_op, dst, saved_dstw, TMP_REG1, 0, TMP_REG2, 0);
|
||||
return sljit_emit_op2(compiler, saved_op, dst, 0, dst, 0, TMP_REG2, 0);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
|
||||
|
||||
return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
|
||||
@ -2364,7 +2404,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
sljit_s32 reg;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(1);
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
@ -2372,7 +2411,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
PTR_FAIL_IF(!const_);
|
||||
set_const(const_, compiler);
|
||||
|
||||
reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
PTR_FAIL_IF(emit_const(compiler, reg, init_value));
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -60,7 +60,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
@ -71,7 +71,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return push_inst(compiler, (op == SLJIT_MOV_S16 ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
@ -80,18 +80,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
/* sparc 32 does not support SLJIT_KEEP_FLAGS. Not sure I can fix this. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS | (flags & SET_FLAGS)));
|
||||
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
|
||||
|
||||
/* Loop. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0xe) | (-2 & DISP_MASK), UNMOVABLE_INS));
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS | (flags & SET_FLAGS));
|
||||
return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS);
|
||||
|
||||
case SLJIT_ADD:
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
@ -135,7 +134,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -145,20 +144,22 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
||||
return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_addr >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_addr & 0x3ff);
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_target >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_target & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_constant >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_constant & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -199,7 +199,7 @@ static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
|
||||
static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_sw diff;
|
||||
sljit_uw target_addr;
|
||||
@ -213,7 +213,7 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
|
||||
target_addr = jump->u.target;
|
||||
else {
|
||||
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size);
|
||||
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
|
||||
}
|
||||
inst = (sljit_ins*)jump->addr;
|
||||
|
||||
@ -239,8 +239,9 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
|
||||
if (jump->flags & IS_COND)
|
||||
inst--;
|
||||
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(inst - 1) - executable_offset) >> 2;
|
||||
|
||||
if (jump->flags & IS_MOVABLE) {
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(inst - 1)) >> 2;
|
||||
if (diff <= MAX_DISP && diff >= MIN_DISP) {
|
||||
jump->flags |= PATCH_B;
|
||||
inst--;
|
||||
@ -257,7 +258,8 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
|
||||
}
|
||||
}
|
||||
|
||||
diff = ((sljit_sw)target_addr - (sljit_sw)(inst)) >> 2;
|
||||
diff += sizeof(sljit_ins);
|
||||
|
||||
if (diff <= MAX_DISP && diff >= MIN_DISP) {
|
||||
jump->flags |= PATCH_B;
|
||||
if (jump->flags & IS_COND)
|
||||
@ -280,6 +282,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
sljit_ins *buf_ptr;
|
||||
sljit_ins *buf_end;
|
||||
sljit_uw word_count;
|
||||
sljit_sw executable_offset;
|
||||
sljit_uw addr;
|
||||
|
||||
struct sljit_label *label;
|
||||
@ -296,9 +299,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
|
||||
code_ptr = code;
|
||||
word_count = 0;
|
||||
executable_offset = SLJIT_EXEC_OFFSET(code);
|
||||
|
||||
label = compiler->labels;
|
||||
jump = compiler->jumps;
|
||||
const_ = compiler->consts;
|
||||
|
||||
do {
|
||||
buf_ptr = (sljit_ins*)buf->memory;
|
||||
buf_end = buf_ptr + (buf->used_size >> 2);
|
||||
@ -310,7 +316,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
/* These structures are ordered by their address. */
|
||||
if (label && label->size == word_count) {
|
||||
/* Just recording the address. */
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
@ -320,7 +326,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
#else
|
||||
jump->addr = (sljit_uw)(code_ptr - 6);
|
||||
#endif
|
||||
code_ptr = detect_jump_type(jump, code_ptr, code);
|
||||
code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
|
||||
jump = jump->next;
|
||||
}
|
||||
if (const_ && const_->addr == word_count) {
|
||||
@ -336,7 +342,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
label->addr = (sljit_uw)code_ptr;
|
||||
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = code_ptr - code;
|
||||
label = label->next;
|
||||
}
|
||||
@ -353,13 +359,13 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
buf_ptr = (sljit_ins *)jump->addr;
|
||||
|
||||
if (jump->flags & PATCH_CALL) {
|
||||
addr = (sljit_sw)(addr - jump->addr) >> 2;
|
||||
addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
|
||||
SLJIT_ASSERT((sljit_sw)addr <= 0x1fffffff && (sljit_sw)addr >= -0x20000000);
|
||||
buf_ptr[0] = CALL | (addr & 0x3fffffff);
|
||||
break;
|
||||
}
|
||||
if (jump->flags & PATCH_B) {
|
||||
addr = (sljit_sw)(addr - jump->addr) >> 2;
|
||||
addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
|
||||
SLJIT_ASSERT((sljit_sw)addr <= MAX_DISP && (sljit_sw)addr >= MIN_DISP);
|
||||
buf_ptr[0] = (buf_ptr[0] & ~DISP_MASK) | (addr & DISP_MASK);
|
||||
break;
|
||||
@ -378,12 +384,37 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
||||
|
||||
|
||||
compiler->error = SLJIT_ERR_COMPILED;
|
||||
compiler->executable_offset = executable_offset;
|
||||
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
|
||||
SLJIT_ENABLE_EXEC(code, code_ptr);
|
||||
|
||||
code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
|
||||
code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
SLJIT_CACHE_FLUSH(code, code_ptr);
|
||||
return code;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
|
||||
{
|
||||
switch (feature_type) {
|
||||
case SLJIT_HAS_FPU:
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#else
|
||||
/* Available by default. */
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
|
||||
case SLJIT_HAS_CMOV:
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Entry, exit */
|
||||
/* --------------------------------------------------------------------- */
|
||||
@ -568,7 +599,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
|
||||
base = arg & REG_MASK;
|
||||
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
|
||||
argw &= 0x3;
|
||||
SLJIT_ASSERT(argw != 0);
|
||||
|
||||
/* Using the cache. */
|
||||
if (((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) && (argw == compiler->cache_argw))
|
||||
@ -653,11 +683,8 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
||||
compiler->cache_argw = 0;
|
||||
}
|
||||
|
||||
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
|
||||
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
else if (FAST_IS_REG(dst)) {
|
||||
if (dst != SLJIT_UNUSED) {
|
||||
if (FAST_IS_REG(dst)) {
|
||||
dst_r = dst;
|
||||
flags |= REG_DEST;
|
||||
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
|
||||
@ -665,6 +692,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
||||
}
|
||||
else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
|
||||
flags |= SLOW_DEST;
|
||||
}
|
||||
|
||||
if (flags & IMM_OP) {
|
||||
if ((src2 & SLJIT_IMM) && src2w) {
|
||||
@ -813,13 +841,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 flags = GET_FLAGS(op) ? SET_FLAGS : 0;
|
||||
sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
@ -882,7 +913,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2, sljit_sw src2w)
|
||||
{
|
||||
sljit_s32 flags = GET_FLAGS(op) ? SET_FLAGS : 0;
|
||||
sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
|
||||
@ -890,6 +921,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
switch (op) {
|
||||
case SLJIT_ADD:
|
||||
@ -911,7 +945,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
||||
if (src2 & SLJIT_IMM)
|
||||
src2w &= 0x1f;
|
||||
#else
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
#endif
|
||||
return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
@ -944,16 +978,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
|
||||
/* Floating point operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void)
|
||||
{
|
||||
#ifdef SLJIT_IS_FPU_AVAILABLE
|
||||
return SLJIT_IS_FPU_AVAILABLE;
|
||||
#else
|
||||
/* Available by default. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 7))
|
||||
#define SELECT_FOP(op, single, double) ((op & SLJIT_F32_OP) ? single : double)
|
||||
#define FLOAT_TMP_MEM_OFFSET (22 * sizeof(sljit_sw))
|
||||
@ -971,9 +995,6 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSTOI, FDTOI) | DA(TMP_FREG1) | S2A(src), MOVABLE_INS));
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
FAIL_IF(emit_op_mem2(compiler, SINGLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
|
||||
return emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET);
|
||||
@ -1187,10 +1208,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | S2(TMP_LINK), DR(dst));
|
||||
|
||||
@ -1286,7 +1303,7 @@ static sljit_ins get_cc(sljit_s32 type)
|
||||
return DA(0xf);
|
||||
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return DA(0x8);
|
||||
}
|
||||
}
|
||||
@ -1296,7 +1313,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
||||
struct sljit_jump *jump;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_jump(compiler, type));
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
@ -1375,30 +1391,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw,
|
||||
sljit_s32 type)
|
||||
{
|
||||
sljit_s32 reg, flags = (GET_FLAGS(op) ? SET_FLAGS : 0);
|
||||
sljit_s32 reg, flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
op = GET_OPCODE(op);
|
||||
reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
|
||||
|
||||
compiler->cache_arg = 0;
|
||||
compiler->cache_argw = 0;
|
||||
if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
|
||||
src = TMP_REG1;
|
||||
srcw = 0;
|
||||
}
|
||||
|
||||
if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
|
||||
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
|
||||
|
||||
type &= 0xff;
|
||||
if (type < SLJIT_EQUAL_F64)
|
||||
@ -1409,10 +1418,31 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
||||
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(1), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS));
|
||||
|
||||
if (op >= SLJIT_ADD)
|
||||
return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0);
|
||||
if (op >= SLJIT_ADD) {
|
||||
flags |= CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE;
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
|
||||
return emit_op(compiler, op, flags, dst, 0, dst, 0, TMP_REG2, 0);
|
||||
}
|
||||
|
||||
return (reg == TMP_REG2) ? emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw) : SLJIT_SUCCESS;
|
||||
if (!(dst & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
|
||||
#else
|
||||
#error "Implementation required"
|
||||
#endif
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
|
||||
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
|
||||
#else
|
||||
#error "Implementation required"
|
||||
#endif
|
||||
@ -1424,7 +1454,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(1);
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
@ -1432,7 +1461,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
||||
PTR_FAIL_IF(!const_);
|
||||
set_const(const_, compiler);
|
||||
|
||||
reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
PTR_FAIL_IF(emit_const(compiler, reg, init_value));
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2013-2013 Tilera Corporation(jiwang@tilera.com). All rights reserved.
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2013-2013 Tilera Corporation(jiwang@tilera.com). All rights reserved.
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -687,7 +687,7 @@ static sljit_s32 update_buffer(struct sljit_compiler *compiler)
|
||||
inst_buf[0] = inst1;
|
||||
inst_buf_index = 1;
|
||||
} else
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
|
||||
#ifdef TILEGX_JIT_DEBUG
|
||||
return push_inst_nodebug(compiler, bits);
|
||||
@ -727,10 +727,10 @@ static sljit_s32 update_buffer(struct sljit_compiler *compiler)
|
||||
return push_inst(compiler, bits);
|
||||
#endif
|
||||
} else
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
static sljit_s32 flush_buffer(struct sljit_compiler *compiler)
|
||||
@ -814,7 +814,7 @@ static sljit_s32 push_3_buffer(struct sljit_compiler *compiler, tilegx_mnemonic
|
||||
break;
|
||||
default:
|
||||
printf("unrecoginzed opc: %s\n", opcode->name);
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
inst_buf_index++;
|
||||
@ -859,7 +859,7 @@ static sljit_s32 push_2_buffer(struct sljit_compiler *compiler, tilegx_mnemonic
|
||||
break;
|
||||
default:
|
||||
printf("unrecoginzed opc: %s\n", opcode->name);
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
inst_buf_index++;
|
||||
@ -1113,7 +1113,6 @@ SLJIT_API_FUNC_ATTRIBUTE void * sljit_generate_code(struct sljit_compiler *compi
|
||||
|
||||
compiler->error = SLJIT_ERR_COMPILED;
|
||||
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
|
||||
SLJIT_ENABLE_EXEC(code, code_ptr);
|
||||
SLJIT_CACHE_FLUSH(code, code_ptr);
|
||||
return code;
|
||||
}
|
||||
@ -1953,7 +1952,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2093,9 +2092,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
||||
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
if (dst == SLJIT_UNUSED)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
op = GET_OPCODE(op);
|
||||
if (op == SLJIT_MOV_S32 || op == SLJIT_MOV_U32)
|
||||
mem_type = INT_DATA | SIGNED_DATA;
|
||||
@ -2144,7 +2140,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
||||
break;
|
||||
|
||||
default:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
dst_ar = sugg_dst_ar;
|
||||
break;
|
||||
}
|
||||
@ -2187,7 +2183,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
|
||||
case SLJIT_DIVMOD_SW:
|
||||
case SLJIT_DIV_UW:
|
||||
case SLJIT_DIV_SW:
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
@ -2413,7 +2409,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compil
|
||||
flush_buffer(compiler);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(type & SLJIT_REWRITABLE_JUMP);
|
||||
CHECK_PTR(check_sljit_emit_jump(compiler, type));
|
||||
|
||||
jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
@ -2489,19 +2484,14 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compil
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w)
|
||||
{
|
||||
SLJIT_ASSERT_STOP();
|
||||
SLJIT_UNREACHABLE();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
|
||||
@ -2512,7 +2502,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_comp
|
||||
flush_buffer(compiler);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_DYN_CODE_MOD(1);
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
@ -2529,13 +2518,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_comp
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & ~(0xFFFFL << 43)) | (((new_addr >> 32) & 0xffff) << 43);
|
||||
inst[1] = (inst[1] & ~(0xFFFFL << 43)) | (((new_addr >> 16) & 0xffff) << 43);
|
||||
inst[2] = (inst[2] & ~(0xFFFFL << 43)) | ((new_addr & 0xffff) << 43);
|
||||
inst[0] = (inst[0] & ~(0xFFFFL << 43)) | (((new_target >> 32) & 0xffff) << 43);
|
||||
inst[1] = (inst[1] & ~(0xFFFFL << 43)) | (((new_target >> 16) & 0xffff) << 43);
|
||||
inst[2] = (inst[2] & ~(0xFFFFL << 43)) | ((new_target & 0xffff) << 43);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 3);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -38,7 +38,7 @@ static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, s
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type)
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type, sljit_sw executable_offset)
|
||||
{
|
||||
if (type == SLJIT_JUMP) {
|
||||
*code_ptr++ = JMP_i32;
|
||||
@ -57,7 +57,7 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MW;
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4));
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset);
|
||||
code_ptr += 4;
|
||||
|
||||
return code_ptr;
|
||||
@ -75,9 +75,30 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->args = args;
|
||||
compiler->flags_saved = 0;
|
||||
|
||||
size = 1 + (scratches > 7 ? (scratches - 7) : 0) + (saveds <= 3 ? saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
/* [esp+0] for saving temporaries and third argument for calls. */
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
#else
|
||||
/* [esp+0] for saving temporaries and space for maximum three arguments. */
|
||||
if (scratches <= 1)
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->saveds_offset = ((scratches == 2) ? 2 : 3) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
size = 1 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
size += (args > 0 ? (args * 2) : 0) + (args > 2 ? 2 : 0);
|
||||
#else
|
||||
@ -94,11 +115,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
*inst++ = MOD_REG | (reg_map[TMP_REG1] << 3) | 0x4 /* esp */;
|
||||
}
|
||||
#endif
|
||||
if (saveds > 2 || scratches > 7)
|
||||
if (saveds > 2 || scratches > 9)
|
||||
PUSH_REG(reg_map[SLJIT_S2]);
|
||||
if (saveds > 1 || scratches > 8)
|
||||
if (saveds > 1 || scratches > 10)
|
||||
PUSH_REG(reg_map[SLJIT_S1]);
|
||||
if (saveds > 0 || scratches > 9)
|
||||
if (saveds > 0 || scratches > 11)
|
||||
PUSH_REG(reg_map[SLJIT_S0]);
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
@ -134,51 +155,64 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_COMPILE_ASSERT(SLJIT_LOCALS_OFFSET >= (2 + 4) * sizeof(sljit_uw), require_at_least_two_words);
|
||||
SLJIT_ASSERT(SLJIT_LOCALS_OFFSET > 0);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Ignore pushed registers and SLJIT_LOCALS_OFFSET when computing the aligned local size. */
|
||||
saveds = (2 + (scratches > 7 ? (scratches - 7) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_DOUBLE_ALIGNMENT) {
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + 7) & ~7);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 17);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(17);
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_REG | (reg_map[TMP_REG1] << 3) | reg_map[SLJIT_SP];
|
||||
inst[2] = GROUP_F7;
|
||||
inst[3] = MOD_REG | (0 << 3) | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_sw(inst + 4, 0x4);
|
||||
inst[8] = JNE_i8;
|
||||
inst[9] = 6;
|
||||
inst[10] = GROUP_BINARY_81;
|
||||
inst[11] = MOD_REG | (5 << 3) | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_sw(inst + 12, 0x4);
|
||||
inst[16] = PUSH_r + reg_map[TMP_REG1];
|
||||
}
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + 3) & ~3);
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (local_size > 1024) {
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
|
||||
#else
|
||||
local_size -= SLJIT_LOCALS_OFFSET;
|
||||
/* Space for a single argument. This amount is excluded when the stack is allocated below. */
|
||||
local_size -= sizeof(sljit_sw);
|
||||
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
|
||||
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, SLJIT_LOCALS_OFFSET));
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (options & SLJIT_F64_ALIGNMENT) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_SP, 0);
|
||||
|
||||
/* Some space might allocated during sljit_grow_stack() above on WIN32. */
|
||||
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size + sizeof(sljit_sw)));
|
||||
|
||||
#if defined _WIN32 && !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->local_size > 1024)
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 6);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(6);
|
||||
inst[0] = GROUP_BINARY_81;
|
||||
inst[1] = MOD_REG | AND | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_sw(inst + 2, ~(sizeof(sljit_f64) - 1));
|
||||
|
||||
/* The real local size must be used. */
|
||||
return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), compiler->local_size, TMP_REG1, 0);
|
||||
}
|
||||
#endif
|
||||
return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size);
|
||||
}
|
||||
@ -193,14 +227,36 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
|
||||
|
||||
compiler->args = args;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
/* [esp+0] for saving temporaries and third argument for calls. */
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
#else
|
||||
/* [esp+0] for saving temporaries and space for maximum three arguments. */
|
||||
if (scratches <= 1)
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->saveds_offset = ((scratches == 2) ? 2 : 3) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
saveds = (2 + (scratches > 7 ? (scratches - 7) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
compiler->local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_DOUBLE_ALIGNMENT)
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + 7) & ~7);
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + 3) & ~3);
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
@ -214,23 +270,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
SLJIT_ASSERT(compiler->args >= 0);
|
||||
|
||||
compiler->flags_saved = 0;
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
SLJIT_ASSERT(compiler->local_size > 0);
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (compiler->options & SLJIT_DOUBLE_ALIGNMENT) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(3);
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = (reg_map[SLJIT_SP] << 3) | 0x4 /* SIB */;
|
||||
inst[2] = (4 << 3) | reg_map[SLJIT_SP];
|
||||
}
|
||||
if (compiler->options & SLJIT_F64_ALIGNMENT)
|
||||
EMIT_MOV(compiler, SLJIT_SP, 0, SLJIT_MEM1(SLJIT_SP), compiler->local_size)
|
||||
else
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#else
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#endif
|
||||
|
||||
size = 2 + (compiler->scratches > 7 ? (compiler->scratches - 7) : 0) +
|
||||
@ -247,11 +299,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
if (compiler->saveds > 0 || compiler->scratches > 9)
|
||||
if (compiler->saveds > 0 || compiler->scratches > 11)
|
||||
POP_REG(reg_map[SLJIT_S0]);
|
||||
if (compiler->saveds > 1 || compiler->scratches > 8)
|
||||
if (compiler->saveds > 1 || compiler->scratches > 10)
|
||||
POP_REG(reg_map[SLJIT_S1]);
|
||||
if (compiler->saveds > 2 || compiler->scratches > 7)
|
||||
if (compiler->saveds > 2 || compiler->scratches > 9)
|
||||
POP_REG(reg_map[SLJIT_S2]);
|
||||
POP_REG(reg_map[TMP_REG1]);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -47,9 +47,8 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_
|
||||
*code_ptr++ = 10 + 3;
|
||||
}
|
||||
|
||||
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_first);
|
||||
*code_ptr++ = REX_W | REX_B;
|
||||
*code_ptr++ = MOV_r_i32 + 1;
|
||||
*code_ptr++ = REX_W | ((reg_map[TMP_REG2] <= 7) ? 0 : REX_B);
|
||||
*code_ptr++ = MOV_r_i32 | reg_lmap[TMP_REG2];
|
||||
jump->addr = (sljit_uw)code_ptr;
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
@ -58,31 +57,10 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target);
|
||||
|
||||
code_ptr += sizeof(sljit_sw);
|
||||
if (reg_map[TMP_REG2] >= 8)
|
||||
*code_ptr++ = REX_B;
|
||||
*code_ptr++ = GROUP_FF;
|
||||
*code_ptr++ = (type >= SLJIT_FAST_CALL) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_fixed_jump(sljit_u8 *code_ptr, sljit_sw addr, sljit_s32 type)
|
||||
{
|
||||
sljit_sw delta = addr - ((sljit_sw)code_ptr + 1 + sizeof(sljit_s32));
|
||||
|
||||
if (delta <= HALFWORD_MAX && delta >= HALFWORD_MIN) {
|
||||
*code_ptr++ = (type == 2) ? CALL_i32 : JMP_i32;
|
||||
sljit_unaligned_store_sw(code_ptr, delta);
|
||||
}
|
||||
else {
|
||||
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_second);
|
||||
*code_ptr++ = REX_W | REX_B;
|
||||
*code_ptr++ = MOV_r_i32 + 1;
|
||||
sljit_unaligned_store_sw(code_ptr, addr);
|
||||
code_ptr += sizeof(sljit_sw);
|
||||
*code_ptr++ = REX_B;
|
||||
*code_ptr++ = GROUP_FF;
|
||||
*code_ptr++ = (type == 2) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
|
||||
}
|
||||
*code_ptr++ = MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2];
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
@ -98,7 +76,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->flags_saved = 0;
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
@ -177,7 +161,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
INC_SIZE(4 + (3 + sizeof(sljit_s32)));
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | SUB | 4;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
/* Allocated size for registers must be divisible by 8. */
|
||||
SLJIT_ASSERT(!(saved_register_size & 0x7));
|
||||
/* Aligned to 16 byte. */
|
||||
@ -189,7 +173,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
local_size -= 4 * sizeof(sljit_sw);
|
||||
}
|
||||
/* Second instruction */
|
||||
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R0] < 8, temporary_reg1_is_loreg);
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R0] < 8);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_rm_i32;
|
||||
*inst++ = MOD_REG | reg_lmap[SLJIT_R0];
|
||||
@ -202,14 +186,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(local_size > 0);
|
||||
if (local_size > 0) {
|
||||
if (local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | SUB | 4;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
*inst++ = local_size;
|
||||
}
|
||||
else {
|
||||
@ -218,10 +202,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
|
||||
INC_SIZE(7);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_81;
|
||||
*inst++ = MOD_REG | SUB | 4;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_s32(inst, local_size);
|
||||
inst += sizeof(sljit_s32);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Save xmm6 register: movaps [rsp + 0x20], xmm6 */
|
||||
@ -247,6 +232,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
|
||||
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
compiler->local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
@ -261,7 +254,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
|
||||
compiler->flags_saved = 0;
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
#ifdef _WIN64
|
||||
@ -275,7 +267,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(compiler->local_size > 0);
|
||||
if (compiler->local_size > 0) {
|
||||
if (compiler->local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
@ -294,6 +286,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
sljit_unaligned_store_s32(inst, compiler->local_size);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = compiler->scratches;
|
||||
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
|
||||
@ -387,13 +380,12 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
|
||||
if (b & SLJIT_MEM) {
|
||||
if (!(b & OFFS_REG_MASK)) {
|
||||
if (NOT_HALFWORD(immb)) {
|
||||
if (emit_load_imm64(compiler, TMP_REG3, immb))
|
||||
return NULL;
|
||||
PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immb));
|
||||
immb = 0;
|
||||
if (b & REG_MASK)
|
||||
b |= TO_OFFS_REG(TMP_REG3);
|
||||
b |= TO_OFFS_REG(TMP_REG2);
|
||||
else
|
||||
b |= TMP_REG3;
|
||||
b |= TMP_REG2;
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 4)
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
@ -553,17 +545,19 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
/* After any change update IS_REG_CHANGED_BY_CALL as well. */
|
||||
#ifndef _WIN64
|
||||
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8, args_registers);
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8 && reg_map[TMP_REG1] == 2);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
|
||||
if (type >= SLJIT_CALL3) {
|
||||
/* Move third argument to TMP_REG1. */
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x2 /* rdx */ << 3) | reg_lmap[SLJIT_R2];
|
||||
@ -572,12 +566,13 @@ static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sl
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x7 /* rdi */ << 3) | reg_lmap[SLJIT_R0];
|
||||
#else
|
||||
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8, args_registers);
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8 && reg_map[TMP_REG1] == 8);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
|
||||
if (type >= SLJIT_CALL3) {
|
||||
/* Move third argument to TMP_REG1. */
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x0 /* r8 */ << 3) | reg_lmap[SLJIT_R2];
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
@ -206,10 +206,7 @@ static sljit_sw sljit_page_align = 0;
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data)
|
||||
{
|
||||
struct sljit_stack *stack;
|
||||
union {
|
||||
void *ptr;
|
||||
sljit_uw uw;
|
||||
} base;
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO si;
|
||||
#endif
|
||||
@ -233,29 +230,29 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(slj
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Align limit and max_limit. */
|
||||
max_limit = (max_limit + sljit_page_align) & ~sljit_page_align;
|
||||
|
||||
stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
|
||||
if (!stack)
|
||||
return NULL;
|
||||
|
||||
/* Align max_limit. */
|
||||
max_limit = (max_limit + sljit_page_align) & ~sljit_page_align;
|
||||
|
||||
#ifdef _WIN32
|
||||
base.ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!base.ptr) {
|
||||
ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!ptr) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->base = base.uw;
|
||||
stack->max_limit = (sljit_u8 *)ptr;
|
||||
stack->base = stack->max_limit + max_limit;
|
||||
stack->limit = stack->base;
|
||||
stack->max_limit = stack->base + max_limit;
|
||||
if (sljit_stack_resize(stack, stack->base + limit)) {
|
||||
if (sljit_stack_resize(stack, stack->base - limit)) {
|
||||
sljit_free_stack(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#ifdef MAP_ANON
|
||||
base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero()) {
|
||||
@ -263,15 +260,15 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(slj
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
|
||||
ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif
|
||||
if (base.ptr == MAP_FAILED) {
|
||||
if (ptr == MAP_FAILED) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->base = base.uw;
|
||||
stack->limit = stack->base + limit;
|
||||
stack->max_limit = stack->base + max_limit;
|
||||
stack->max_limit = (sljit_u8 *)ptr;
|
||||
stack->base = stack->max_limit + max_limit;
|
||||
stack->limit = stack->base - limit;
|
||||
#endif
|
||||
stack->top = stack->base;
|
||||
return stack;
|
||||
@ -283,49 +280,49 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* st
|
||||
{
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
#ifdef _WIN32
|
||||
VirtualFree((void*)stack->base, 0, MEM_RELEASE);
|
||||
VirtualFree((void*)stack->max_limit, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap((void*)stack->base, stack->max_limit - stack->base);
|
||||
munmap((void*)stack->max_limit, stack->base - stack->max_limit);
|
||||
#endif
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit)
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_limit)
|
||||
{
|
||||
sljit_uw aligned_old_limit;
|
||||
sljit_uw aligned_new_limit;
|
||||
|
||||
if ((new_limit > stack->max_limit) || (new_limit < stack->base))
|
||||
if ((new_limit < stack->max_limit) || (new_limit >= stack->base))
|
||||
return -1;
|
||||
#ifdef _WIN32
|
||||
aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align;
|
||||
aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align;
|
||||
aligned_new_limit = (sljit_uw)new_limit & ~sljit_page_align;
|
||||
aligned_old_limit = ((sljit_uw)stack->limit) & ~sljit_page_align;
|
||||
if (aligned_new_limit != aligned_old_limit) {
|
||||
if (aligned_new_limit > aligned_old_limit) {
|
||||
if (!VirtualAlloc((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_COMMIT, PAGE_READWRITE))
|
||||
if (aligned_new_limit < aligned_old_limit) {
|
||||
if (!VirtualAlloc((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_COMMIT, PAGE_READWRITE))
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (!VirtualFree((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_DECOMMIT))
|
||||
if (!VirtualFree((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_DECOMMIT))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
#else
|
||||
if (new_limit >= stack->limit) {
|
||||
if (new_limit <= stack->limit) {
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
}
|
||||
aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align;
|
||||
aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align;
|
||||
aligned_new_limit = (sljit_uw)new_limit & ~sljit_page_align;
|
||||
aligned_old_limit = ((sljit_uw)stack->limit) & ~sljit_page_align;
|
||||
/* If madvise is available, we release the unnecessary space. */
|
||||
#if defined(MADV_DONTNEED)
|
||||
if (aligned_new_limit < aligned_old_limit)
|
||||
madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MADV_DONTNEED);
|
||||
if (aligned_new_limit > aligned_old_limit)
|
||||
madvise((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MADV_DONTNEED);
|
||||
#elif defined(POSIX_MADV_DONTNEED)
|
||||
if (aligned_new_limit < aligned_old_limit)
|
||||
posix_madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, POSIX_MADV_DONTNEED);
|
||||
if (aligned_new_limit > aligned_old_limit)
|
||||
posix_madvise((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, POSIX_MADV_DONTNEED);
|
||||
#endif
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
|
3
pcre/testdata/testinput1
vendored
3
pcre/testdata/testinput1
vendored
@ -5739,4 +5739,7 @@ AbcdCBefgBhiBqz
|
||||
/(?=.*X)X$/
|
||||
\ X
|
||||
|
||||
/X+(?#comment)?/
|
||||
>XXX<
|
||||
|
||||
/-- End of testinput1 --/
|
||||
|
2
pcre/testdata/testinput12
vendored
2
pcre/testdata/testinput12
vendored
@ -104,4 +104,6 @@ and a couple of things that are different with JIT. --/
|
||||
/(.|.)*?bx/
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabax
|
||||
|
||||
/((?(?!))x)(?'name')(?1)/S++
|
||||
|
||||
/-- End of testinput12 --/
|
||||
|
3
pcre/testdata/testinput15
vendored
3
pcre/testdata/testinput15
vendored
@ -363,4 +363,7 @@ correctly, but that messes up comparisons). --/
|
||||
|
||||
/abc/89
|
||||
|
||||
//8+L
|
||||
\xf1\xad\xae\xae
|
||||
|
||||
/-- End of testinput15 --/
|
||||
|
3
pcre/testdata/testinput8
vendored
3
pcre/testdata/testinput8
vendored
@ -4845,4 +4845,7 @@
|
||||
aaa\D
|
||||
a\D
|
||||
|
||||
/(02-)?[0-9]{3}-[0-9]{3}/
|
||||
02-123-123
|
||||
|
||||
/-- End of testinput8 --/
|
||||
|
4
pcre/testdata/testoutput1
vendored
4
pcre/testdata/testoutput1
vendored
@ -9442,4 +9442,8 @@ No match
|
||||
\ X
|
||||
0: X
|
||||
|
||||
/X+(?#comment)?/
|
||||
>XXX<
|
||||
0: X
|
||||
|
||||
/-- End of testinput1 --/
|
||||
|
2
pcre/testdata/testoutput12
vendored
2
pcre/testdata/testoutput12
vendored
@ -201,4 +201,6 @@ No match, mark = m (JIT)
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabax
|
||||
Error -8 (match limit exceeded)
|
||||
|
||||
/((?(?!))x)(?'name')(?1)/S++
|
||||
|
||||
/-- End of testinput12 --/
|
||||
|
5
pcre/testdata/testoutput15
vendored
5
pcre/testdata/testoutput15
vendored
@ -1136,4 +1136,9 @@ Failed: setting UTF is disabled by the application at offset 0
|
||||
/abc/89
|
||||
Failed: setting UTF is disabled by the application at offset 0
|
||||
|
||||
//8+L
|
||||
\xf1\xad\xae\xae
|
||||
0:
|
||||
0+ \x{6dbae}
|
||||
|
||||
/-- End of testinput15 --/
|
||||
|
4
pcre/testdata/testoutput8
vendored
4
pcre/testdata/testoutput8
vendored
@ -7801,4 +7801,8 @@ No match
|
||||
** Show all captures ignored after DFA matching
|
||||
0: a
|
||||
|
||||
/(02-)?[0-9]{3}-[0-9]{3}/
|
||||
02-123-123
|
||||
0: 02-123-123
|
||||
|
||||
/-- End of testinput8 --/
|
||||
|
Reference in New Issue
Block a user