fi
fi
+PHP_ARG_WITH(pcre-valgrind,,[ --with-pcre-valgrind=DIR
+ Enable PCRE valgrind support. Developers only!], no, no)
+ if test "$PHP_PCRE_REGEX" != "yes" && test "$PHP_PCRE_REGEX" != "no"; then
+ AC_MSG_WARN([PHP is going to be linked with an external PCRE, --with-pcre-valgrind has no effect])
+ else
+ if test "$PHP_PCRE_VALGRIND" != "no"; then
+ PHP_PCRE_VALGRIND_INCDIR=
+ AC_MSG_CHECKING([for Valgrind headers location])
+ for i in $PHP_PCRE_VALGRIND $PHP_PCRE_VALGRIND/include $PHP_PCRE_VALGRIND/local/include /usr/include /usr/local/include; do
+ if test -f $i/valgrind/memcheck.h
+ then
+ PHP_PCRE_VALGRIND_INCDIR=$i
+ break
+ fi
+ done
+ if test -z "$PHP_PCRE_VALGRIND_INCDIR"
+ then
+ AC_MSG_ERROR([Could not find valgrind/memcheck.h])
+ else
+ AC_DEFINE(HAVE_PCRE_VALGRIND_SUPPORT, 1, [ ])
+ PHP_ADD_INCLUDE($PHP_PCRE_VALGRIND_INCDIR)
+ AC_MSG_RESULT([$PHP_PCRE_VALGRIND_INCDIR])
+ fi
+ fi
+ fi
+
University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2015 University of Cambridge
+Copyright (c) 1997-2017 University of Cambridge
All rights reserved
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2010-2015 Zoltan Herczeg
+Copyright(c) 2010-2017 Zoltan Herczeg
All rights reserved.
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2009-2015 Zoltan Herczeg
+Copyright(c) 2009-2017 Zoltan Herczeg
All rights reserved.
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. Using -o with -M in pcregrep could cause unnecessary repeated output when
+ the match extended over a line boundary.
+
+2. Applied Chris Wilson's second patch (Bugzilla #1681) to CMakeLists.txt for
+ MSVC static compilation, putting the first patch under a new option.
+
+3. Fix register overwite in JIT when SSE2 acceleration is enabled.
+
+4. Ignore "show all captures" (/=) for DFA matching.
+
+5. Fix JIT unaligned accesses on x86. Patch by Marc Mutz.
+
+6. In any wide-character mode (8-bit UTF or any 16-bit or 32-bit mode),
+ without PCRE_UCP set, a negative character type such as \D in a positive
+ class should cause all characters greater than 255 to match, whatever else
+ is in the class. There was a bug that caused this not to happen if a
+ Unicode property item was added to such a class, for example [\D\P{Nd}] or
+ [\W\pL].
+
+7. When pcretest was outputing information from a callout, the caret indicator
+ for the current position in the subject line was incorrect if it was after
+ an escape sequence for a character whose code point was greater than
+ \x{ff}.
+
+8. A pattern such as (?<RA>abc)(?(R)xyz) was incorrectly compiled such that
+ the conditional was interpreted as a reference to capturing group 1 instead
+ of a test for recursion. Any group whose name began with R was
+ misinterpreted in this way. (The reference interpretation should only
+ happen if the group's name is precisely "R".)
+
+9. A number of bugs have been mended relating to match start-up optimizations
+ when the first thing in a pattern is a positive lookahead. These all
+ applied only when PCRE_NO_START_OPTIMIZE was *not* set:
+
+ (a) A pattern such as (?=.*X)X$ was incorrectly optimized as if it needed
+ both an initial 'X' and a following 'X'.
+ (b) Some patterns starting with an assertion that started with .* were
+ incorrectly optimized as having to match at the start of the subject or
+ after a newline. There are cases where this is not true, for example,
+ (?=.*[A-Z])(?=.{8,16})(?!.*[\s]) matches after the start in lines that
+ start with spaces. Starting .* in an assertion is no longer taken as an
+ indication of matching at the start (or after a newline).
+
+
+Version 8.39 14-June-2016
+-------------------------
+
+1. If PCRE_AUTO_CALLOUT was set on a pattern that had a (?# comment between
+ an item and its qualifier (for example, A(?#comment)?B) pcre_compile()
+ misbehaved. This bug was found by the LLVM fuzzer.
+
+2. Similar to the above, if an isolated \E was present between an item and its
+ qualifier when PCRE_AUTO_CALLOUT was set, pcre_compile() misbehaved. This
+ bug was found by the LLVM fuzzer.
+
+3. Further to 8.38/46, negated classes such as [^[:^ascii:]\d] were also not
+ working correctly in UCP mode.
+
+4. The POSIX wrapper function regexec() crashed if the option REG_STARTEND
+ was set when the pmatch argument was NULL. It now returns REG_INVARG.
+
+5. Allow for up to 32-bit numbers in the ordin() function in pcregrep.
+
+6. An empty \Q\E sequence between an item and its qualifier caused
+ pcre_compile() to misbehave when auto callouts were enabled. This bug was
+ found by the LLVM fuzzer.
+
+7. If a pattern that was compiled with PCRE_EXTENDED started with white
+ space or a #-type comment that was followed by (?-x), which turns off
+ PCRE_EXTENDED, and there was no subsequent (?x) to turn it on again,
+ pcre_compile() assumed that (?-x) applied to the whole pattern and
+ consequently mis-compiled it. This bug was found by the LLVM fuzzer.
+
+8. A call of pcre_copy_named_substring() for a named substring whose number
+ was greater than the space in the ovector could cause a crash.
+
+9. Yet another buffer overflow bug involved duplicate named groups with a
+ group that reset capture numbers (compare 8.38/7 below). Once again, I have
+ just allowed for more memory, even if not needed. (A proper fix is
+ implemented in PCRE2, but it involves a lot of refactoring.)
+
+10. pcre_get_substring_list() crashed if the use of \K in a match caused the
+ start of the match to be earlier than the end.
+
+11. Migrating appropriate PCRE2 JIT improvements to PCRE.
+
+12. A pattern such as /(?<=((?C)0))/, which has a callout inside a lookbehind
+ assertion, caused pcretest to generate incorrect output, and also to read
+ uninitialized memory (detected by ASAN or valgrind).
+
+13. A pattern that included (*ACCEPT) in the middle of a sufficiently deeply
+ nested set of parentheses of sufficient size caused an overflow of the
+ compiling workspace (which was diagnosed, but of course is not desirable).
+
+14. And yet another buffer overflow bug involving duplicate named groups, this
+ time nested, with a nested back reference. Yet again, I have just allowed
+ for more memory, because anything more needs all the refactoring that has
+ been done for PCRE2. An example pattern that provoked this bug is:
+ /((?J)(?'R'(?'R'(?'R'(?'R'(?'R'(?|(\k'R'))))))))/ and the bug was
+ registered as CVE-2016-1283.
+
+15. pcretest went into a loop if global matching was requested with an ovector
+ size less than 2. It now gives an error message. This bug was found by
+ afl-fuzz.
+
+16. An invalid pattern fragment such as (?(?C)0 was not diagnosing an error
+ ("assertion expected") when (?(?C) was not followed by an opening
+ parenthesis.
+
+17. Fixed typo ("&&" for "&") in pcre_study(). Fortunately, this could not
+ actually affect anything, by sheer luck.
+
+18. Applied Chris Wilson's patch (Bugzilla #1681) to CMakeLists.txt for MSVC
+ static compilation.
+
+19. Modified the RunTest script to incorporate a valgrind suppressions file so
+ that certain errors, provoked by the SSE2 instruction set when JIT is used,
+ are ignored.
+
+20. A racing condition is fixed in JIT reported by Mozilla.
+
+21. Minor code refactor to avoid "array subscript is below array bounds"
+ compiler warning.
+
+22. Minor code refactor to avoid "left shift of negative number" warning.
+
+23. Fix typo causing compile error when 16- or 32-bit JIT is compiled without
+ UCP support.
+
+24. Refactor to avoid compiler warnings in pcrecpp.cc.
+
+25. Refactor to fix a typo in pcre_jit_test.c
+
+26. Patch to support compiling pcrecpp.cc with Intel compiler.
+
+
Version 8.38 23-November-2015
-----------------------------
1. If a group that contained a recursive back reference also contained a
forward reference subroutine call followed by a non-forward-reference
- subroutine call, for example /.((?2)(?R)\1)()/, pcre2_compile() failed to
+ subroutine call, for example /.((?2)(?R)\1)()/, pcre_compile() failed to
compile correct code, leading to undefined behaviour or an internally
detected error. This bug was discovered by the LLVM fuzzer.
University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2015 University of Cambridge
+Copyright (c) 1997-2017 University of Cambridge
All rights reserved.
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2010-2015 Zoltan Herczeg
+Copyright(c) 2010-2017 Zoltan Herczeg
All rights reserved.
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2009-2015 Zoltan Herczeg
+Copyright(c) 2009-2017 Zoltan Herczeg
All rights reserved.
News about PCRE releases
------------------------
+Release 8.41 13-June-2017
+-------------------------
+
+This is a bug-fix release.
+
+
+Release 8.40 11-January-2017
+----------------------------
+
+This is a bug-fix release.
+
+
+Release 8.39 14-June-2016
+-------------------------
+
+Some appropriate PCRE2 JIT improvements have been retro-fitted to PCRE1. Apart
+from that, this is another bug-fix release. Note that this library (now called
+PCRE1) is now being maintained for bug fixes only. New projects are advised to
+use the new PCRE2 libraries.
+
+
Release 8.38 23-November-2015
-----------------------------
script that can be run to recreate the configuration, and config.log, which
contains compiler output from tests that "configure" runs.
-Once "configure" has run, you can run "make". This builds the libraries
+Once "configure" has run, you can run "make". This builds the the libraries
libpcre, libpcre16 and/or libpcre32, and a test program called pcretest. If you
enabled JIT support with --enable-jit, a test program called pcre_jit_test is
built as well.
#define PACKAGE_NAME "PCRE"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "PCRE 8.38"
+#define PACKAGE_STRING "PCRE 8.41"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pcre"
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "8.38"
+#define PACKAGE_VERSION "8.41"
/* to make a symbol visible */
/* #undef PCRECPP_EXP_DECL */
/* #undef SUPPORT_UTF8 */
/* Valgrind support to find invalid memory reads. */
-/* #undef SUPPORT_VALGRIND */
+#if HAVE_PCRE_VALGRIND_SUPPORT
+#define SUPPORT_VALGRIND 1
+#endif
/* Version number of package */
#ifndef VERSION
-#define VERSION "8.38"
+#define VERSION "8.41"
#endif
/* Define to empty if `const' does not conform to ANSI C. */
locale. Now that pcre_maketables is a function visible to the outside world, we
make use of its code from here in order to be consistent. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include <ctype.h>
#include <stdio.h>
ments that have limited stacks. Because of the greater use of memory
management, it runs more slowly. Separate functions are provided so
that special-purpose external code can be used for this case. When
- used, these functions are always called in a stack-like manner (last
- obtained, first freed), and always for memory blocks of the same size.
- There is a discussion about PCRE's stack usage in the pcrestack docu-
+ used, these functions always allocate memory blocks of the same size.
+ There is a discussion about PCRE's stack usage in the pcrestack docu-
mentation.
The global variable pcre_callout initially contains NULL. It can be set
- by the caller to a "callout" function, which PCRE will then call at
- specified points during a matching operation. Details are given in the
+ by the caller to a "callout" function, which PCRE will then call at
+ specified points during a matching operation. Details are given in the
pcrecallout documentation.
The global variable pcre_stack_guard initially contains NULL. It can be
- set by the caller to a function that is called by PCRE whenever it
- starts to compile a parenthesized part of a pattern. When parentheses
+ set by the caller to a function that is called by PCRE whenever it
+ starts to compile a parenthesized part of a pattern. When parentheses
are nested, PCRE uses recursive function calls, which use up the system
- stack. This function is provided so that applications with restricted
- stacks can force a compilation error if the stack runs out. The func-
+ stack. This function is provided so that applications with restricted
+ stacks can force a compilation error if the stack runs out. The func-
tion should return zero if all is well, or non-zero to force an error.
NEWLINES
- PCRE supports five different conventions for indicating line breaks in
- strings: a single CR (carriage return) character, a single LF (line-
+ PCRE supports five different conventions for indicating line breaks in
+ strings: a single CR (carriage return) character, a single LF (line-
feed) character, the two-character sequence CRLF, any of the three pre-
- ceding, or any Unicode newline sequence. The Unicode newline sequences
- are the three just mentioned, plus the single characters VT (vertical
+ ceding, or any Unicode newline sequence. The Unicode newline sequences
+ are the three just mentioned, plus the single characters VT (vertical
tab, U+000B), FF (form feed, U+000C), NEL (next line, U+0085), LS (line
separator, U+2028), and PS (paragraph separator, U+2029).
- Each of the first three conventions is used by at least one operating
- system as its standard newline sequence. When PCRE is built, a default
- can be specified. The default default is LF, which is the Unix stan-
- dard. When PCRE is run, the default can be overridden, either when a
+ Each of the first three conventions is used by at least one operating
+ system as its standard newline sequence. When PCRE is built, a default
+ can be specified. The default default is LF, which is the Unix stan-
+ dard. When PCRE is run, the default can be overridden, either when a
pattern is compiled, or when it is matched.
At compile time, the newline convention can be specified by the options
- argument of pcre_compile(), or it can be specified by special text at
+ argument of pcre_compile(), or it can be specified by special text at
the start of the pattern itself; this overrides any other settings. See
the pcrepattern page for details of the special character sequences.
In the PCRE documentation the word "newline" is used to mean "the char-
- acter or pair of characters that indicate a line break". The choice of
- newline convention affects the handling of the dot, circumflex, and
+ acter or pair of characters that indicate a line break". The choice of
+ newline convention affects the handling of the dot, circumflex, and
dollar metacharacters, the handling of #-comments in /x mode, and, when
- CRLF is a recognized line ending sequence, the match position advance-
+ CRLF is a recognized line ending sequence, the match position advance-
ment for a non-anchored pattern. There is more detail about this in the
section on pcre_exec() options below.
- The choice of newline convention does not affect the interpretation of
- the \n or \r escape sequences, nor does it affect what \R matches,
+ The choice of newline convention does not affect the interpretation of
+ the \n or \r escape sequences, nor does it affect what \R matches,
which is controlled in a similar way, but by separate options.
MULTITHREADING
- The PCRE functions can be used in multi-threading applications, with
+ The PCRE functions can be used in multi-threading applications, with
the proviso that the memory management functions pointed to by
pcre_malloc, pcre_free, pcre_stack_malloc, and pcre_stack_free, and the
- callout and stack-checking functions pointed to by pcre_callout and
+ callout and stack-checking functions pointed to by pcre_callout and
pcre_stack_guard, are shared by all threads.
- The compiled form of a regular expression is not altered during match-
+ The compiled form of a regular expression is not altered during match-
ing, so the same compiled pattern can safely be used by several threads
at once.
- If the just-in-time optimization feature is being used, it needs sepa-
- rate memory stack areas for each thread. See the pcrejit documentation
+ If the just-in-time optimization feature is being used, it needs sepa-
+ rate memory stack areas for each thread. See the pcrejit documentation
for more details.
SAVING PRECOMPILED PATTERNS FOR LATER USE
The compiled form of a regular expression can be saved and re-used at a
- later time, possibly by a different program, and even on a host other
- than the one on which it was compiled. Details are given in the
- pcreprecompile documentation, which includes a description of the
- pcre_pattern_to_host_byte_order() function. However, compiling a regu-
- lar expression with one version of PCRE for use with a different ver-
+ later time, possibly by a different program, and even on a host other
+ than the one on which it was compiled. Details are given in the
+ pcreprecompile documentation, which includes a description of the
+ pcre_pattern_to_host_byte_order() function. However, compiling a regu-
+ lar expression with one version of PCRE for use with a different ver-
sion is not guaranteed to work and may cause crashes.
int pcre_config(int what, void *where);
- The function pcre_config() makes it possible for a PCRE client to dis-
+ The function pcre_config() makes it possible for a PCRE client to dis-
cover which optional features have been compiled into the PCRE library.
- The pcrebuild documentation has more details about these optional fea-
+ The pcrebuild documentation has more details about these optional fea-
tures.
- The first argument for pcre_config() is an integer, specifying which
+ The first argument for pcre_config() is an integer, specifying which
information is required; the second argument is a pointer to a variable
- into which the information is placed. The returned value is zero on
- success, or the negative error code PCRE_ERROR_BADOPTION if the value
- in the first argument is not recognized. The following information is
+ into which the information is placed. The returned value is zero on
+ success, or the negative error code PCRE_ERROR_BADOPTION if the value
+ in the first argument is not recognized. The following information is
available:
PCRE_CONFIG_UTF8
- The output is an integer that is set to one if UTF-8 support is avail-
- able; otherwise it is set to zero. This value should normally be given
+ The output is an integer that is set to one if UTF-8 support is avail-
+ able; otherwise it is set to zero. This value should normally be given
to the 8-bit version of this function, pcre_config(). If it is given to
- the 16-bit or 32-bit version of this function, the result is
+ the 16-bit or 32-bit version of this function, the result is
PCRE_ERROR_BADOPTION.
PCRE_CONFIG_UTF16
The output is an integer that is set to one if UTF-16 support is avail-
- able; otherwise it is set to zero. This value should normally be given
+ able; otherwise it is set to zero. This value should normally be given
to the 16-bit version of this function, pcre16_config(). If it is given
- to the 8-bit or 32-bit version of this function, the result is
+ to the 8-bit or 32-bit version of this function, the result is
PCRE_ERROR_BADOPTION.
PCRE_CONFIG_UTF32
The output is an integer that is set to one if UTF-32 support is avail-
- able; otherwise it is set to zero. This value should normally be given
+ able; otherwise it is set to zero. This value should normally be given
to the 32-bit version of this function, pcre32_config(). If it is given
- to the 8-bit or 16-bit version of this function, the result is
+ to the 8-bit or 16-bit version of this function, the result is
PCRE_ERROR_BADOPTION.
PCRE_CONFIG_UNICODE_PROPERTIES
- The output is an integer that is set to one if support for Unicode
+ The output is an integer that is set to one if support for Unicode
character properties is available; otherwise it is set to zero.
PCRE_CONFIG_JIT
PCRE_CONFIG_JITTARGET
- The output is a pointer to a zero-terminated "const char *" string. If
+ The output is a pointer to a zero-terminated "const char *" string. If
JIT support is available, the string contains the name of the architec-
- ture for which the JIT compiler is configured, for example "x86 32bit
- (little endian + unaligned)". If JIT support is not available, the
+ ture for which the JIT compiler is configured, for example "x86 32bit
+ (little endian + unaligned)". If JIT support is not available, the
result is NULL.
PCRE_CONFIG_NEWLINE
- The output is an integer whose value specifies the default character
- sequence that is recognized as meaning "newline". The values that are
+ The output is an integer whose value specifies the default character
+ sequence that is recognized as meaning "newline". The values that are
supported in ASCII/Unicode environments are: 10 for LF, 13 for CR, 3338
- for CRLF, -2 for ANYCRLF, and -1 for ANY. In EBCDIC environments, CR,
- ANYCRLF, and ANY yield the same values. However, the value for LF is
- normally 21, though some EBCDIC environments use 37. The corresponding
- values for CRLF are 3349 and 3365. The default should normally corre-
+ for CRLF, -2 for ANYCRLF, and -1 for ANY. In EBCDIC environments, CR,
+ ANYCRLF, and ANY yield the same values. However, the value for LF is
+ normally 21, though some EBCDIC environments use 37. The corresponding
+ values for CRLF are 3349 and 3365. The default should normally corre-
spond to the standard sequence for your operating system.
PCRE_CONFIG_BSR
The output is an integer whose value indicates what character sequences
- the \R escape sequence matches by default. A value of 0 means that \R
- matches any Unicode line ending sequence; a value of 1 means that \R
+ the \R escape sequence matches by default. A value of 0 means that \R
+ matches any Unicode line ending sequence; a value of 1 means that \R
matches only CR, LF, or CRLF. The default can be overridden when a pat-
tern is compiled or matched.
PCRE_CONFIG_LINK_SIZE
- The output is an integer that contains the number of bytes used for
+ The output is an integer that contains the number of bytes used for
internal linkage in compiled regular expressions. For the 8-bit
library, the value can be 2, 3, or 4. For the 16-bit library, the value
- is either 2 or 4 and is still a number of bytes. For the 32-bit
+ is either 2 or 4 and is still a number of bytes. For the 32-bit
library, the value is either 2 or 4 and is still a number of bytes. The
default value of 2 is sufficient for all but the most massive patterns,
- since it allows the compiled pattern to be up to 64K in size. Larger
- values allow larger regular expressions to be compiled, at the expense
+ since it allows the compiled pattern to be up to 64K in size. Larger
+ values allow larger regular expressions to be compiled, at the expense
of slower matching.
PCRE_CONFIG_POSIX_MALLOC_THRESHOLD
- The output is an integer that contains the threshold above which the
- POSIX interface uses malloc() for output vectors. Further details are
+ The output is an integer that contains the threshold above which the
+ POSIX interface uses malloc() for output vectors. Further details are
given in the pcreposix documentation.
PCRE_CONFIG_PARENS_LIMIT
The output is a long integer that gives the maximum depth of nesting of
- parentheses (of any kind) in a pattern. This limit is imposed to cap
+ parentheses (of any kind) in a pattern. This limit is imposed to cap
the amount of system stack used when a pattern is compiled. It is spec-
- ified when PCRE is built; the default is 250. This limit does not take
+ ified when PCRE is built; the default is 250. This limit does not take
into account the stack that may already be used by the calling applica-
- tion. For finer control over compilation stack usage, you can set a
+ tion. For finer control over compilation stack usage, you can set a
pointer to an external checking function in pcre_stack_guard.
PCRE_CONFIG_MATCH_LIMIT
- The output is a long integer that gives the default limit for the num-
- ber of internal matching function calls in a pcre_exec() execution.
+ The output is a long integer that gives the default limit for the num-
+ ber of internal matching function calls in a pcre_exec() execution.
Further details are given with pcre_exec() below.
PCRE_CONFIG_MATCH_LIMIT_RECURSION
The output is a long integer that gives the default limit for the depth
- of recursion when calling the internal matching function in a
- pcre_exec() execution. Further details are given with pcre_exec()
+ of recursion when calling the internal matching function in a
+ pcre_exec() execution. Further details are given with pcre_exec()
below.
PCRE_CONFIG_STACKRECURSE
- The output is an integer that is set to one if internal recursion when
+ The output is an integer that is set to one if internal recursion when
running pcre_exec() is implemented by recursive function calls that use
- the stack to remember their state. This is the usual way that PCRE is
+ the stack to remember their state. This is the usual way that PCRE is
compiled. The output is zero if PCRE was compiled to use blocks of data
- on the heap instead of recursive function calls. In this case,
- pcre_stack_malloc and pcre_stack_free are called to manage memory
+ on the heap instead of recursive function calls. In this case,
+ pcre_stack_malloc and pcre_stack_free are called to manage memory
blocks on the heap, thus avoiding the use of the stack.
Either of the functions pcre_compile() or pcre_compile2() can be called
to compile a pattern into an internal form. The only difference between
- the two interfaces is that pcre_compile2() has an additional argument,
- errorcodeptr, via which a numerical error code can be returned. To
- avoid too much repetition, we refer just to pcre_compile() below, but
+ the two interfaces is that pcre_compile2() has an additional argument,
+ errorcodeptr, via which a numerical error code can be returned. To
+ avoid too much repetition, we refer just to pcre_compile() below, but
the information applies equally to pcre_compile2().
The pattern is a C string terminated by a binary zero, and is passed in
- the pattern argument. A pointer to a single block of memory that is
- obtained via pcre_malloc is returned. This contains the compiled code
+ the pattern argument. A pointer to a single block of memory that is
+ obtained via pcre_malloc is returned. This contains the compiled code
and related data. The pcre type is defined for the returned block; this
is a typedef for a structure whose contents are not externally defined.
It is up to the caller to free the memory (via pcre_free) when it is no
longer required.
- Although the compiled code of a PCRE regex is relocatable, that is, it
+ Although the compiled code of a PCRE regex is relocatable, that is, it
does not depend on memory location, the complete pcre data block is not
- fully relocatable, because it may contain a copy of the tableptr argu-
+ fully relocatable, because it may contain a copy of the tableptr argu-
ment, which is an address (see below).
The options argument contains various bit settings that affect the com-
- pilation. It should be zero if no options are required. The available
- options are described below. Some of them (in particular, those that
- are compatible with Perl, but some others as well) can also be set and
- unset from within the pattern (see the detailed description in the
- pcrepattern documentation). For those options that can be different in
- different parts of the pattern, the contents of the options argument
+ pilation. It should be zero if no options are required. The available
+ options are described below. Some of them (in particular, those that
+ are compatible with Perl, but some others as well) can also be set and
+ unset from within the pattern (see the detailed description in the
+ pcrepattern documentation). For those options that can be different in
+ different parts of the pattern, the contents of the options argument
specifies their settings at the start of compilation and execution. The
- PCRE_ANCHORED, PCRE_BSR_xxx, PCRE_NEWLINE_xxx, PCRE_NO_UTF8_CHECK, and
- PCRE_NO_START_OPTIMIZE options can be set at the time of matching as
+ PCRE_ANCHORED, PCRE_BSR_xxx, PCRE_NEWLINE_xxx, PCRE_NO_UTF8_CHECK, and
+ PCRE_NO_START_OPTIMIZE options can be set at the time of matching as
well as at compile time.
If errptr is NULL, pcre_compile() returns NULL immediately. Otherwise,
- if compilation of a pattern fails, pcre_compile() returns NULL, and
+ if compilation of a pattern fails, pcre_compile() returns NULL, and
sets the variable pointed to by errptr to point to a textual error mes-
sage. This is a static string that is part of the library. You must not
- try to free it. Normally, the offset from the start of the pattern to
+ try to free it. Normally, the offset from the start of the pattern to
the data unit that was being processed when the error was discovered is
- placed in the variable pointed to by erroffset, which must not be NULL
- (if it is, an immediate error is given). However, for an invalid UTF-8
- or UTF-16 string, the offset is that of the first data unit of the
+ placed in the variable pointed to by erroffset, which must not be NULL
+ (if it is, an immediate error is given). However, for an invalid UTF-8
+ or UTF-16 string, the offset is that of the first data unit of the
failing character.
- Some errors are not detected until the whole pattern has been scanned;
- in these cases, the offset passed back is the length of the pattern.
- Note that the offset is in data units, not characters, even in a UTF
+ Some errors are not detected until the whole pattern has been scanned;
+ in these cases, the offset passed back is the length of the pattern.
+ Note that the offset is in data units, not characters, even in a UTF
mode. It may sometimes point into the middle of a UTF-8 or UTF-16 char-
acter.
- If pcre_compile2() is used instead of pcre_compile(), and the error-
- codeptr argument is not NULL, a non-zero error code number is returned
- via this argument in the event of an error. This is in addition to the
+ If pcre_compile2() is used instead of pcre_compile(), and the error-
+ codeptr argument is not NULL, a non-zero error code number is returned
+ via this argument in the event of an error. This is in addition to the
textual error message. Error codes and messages are listed below.
- If the final argument, tableptr, is NULL, PCRE uses a default set of
- character tables that are built when PCRE is compiled, using the
- default C locale. Otherwise, tableptr must be an address that is the
- result of a call to pcre_maketables(). This value is stored with the
- compiled pattern, and used again by pcre_exec() and pcre_dfa_exec()
- when the pattern is matched. For more discussion, see the section on
+ If the final argument, tableptr, is NULL, PCRE uses a default set of
+ character tables that are built when PCRE is compiled, using the
+ default C locale. Otherwise, tableptr must be an address that is the
+ result of a call to pcre_maketables(). This value is stored with the
+ compiled pattern, and used again by pcre_exec() and pcre_dfa_exec()
+ when the pattern is matched. For more discussion, see the section on
locale support below.
- This code fragment shows a typical straightforward call to pcre_com-
+ This code fragment shows a typical straightforward call to pcre_com-
pile():
pcre *re;
&erroffset, /* for error offset */
NULL); /* use default character tables */
- The following names for option bits are defined in the pcre.h header
+ The following names for option bits are defined in the pcre.h header
file:
PCRE_ANCHORED
If this bit is set, the pattern is forced to be "anchored", that is, it
- is constrained to match only at the first matching point in the string
- that is being searched (the "subject string"). This effect can also be
- achieved by appropriate constructs in the pattern itself, which is the
+ is constrained to match only at the first matching point in the string
+ that is being searched (the "subject string"). This effect can also be
+ achieved by appropriate constructs in the pattern itself, which is the
only way to do it in Perl.
PCRE_AUTO_CALLOUT
If this bit is set, pcre_compile() automatically inserts callout items,
- all with number 255, before each pattern item. For discussion of the
+ all with number 255, before each pattern item. For discussion of the
callout facility, see the pcrecallout documentation.
PCRE_BSR_ANYCRLF
PCRE_BSR_UNICODE
These options (which are mutually exclusive) control what the \R escape
- sequence matches. The choice is either to match only CR, LF, or CRLF,
+ sequence matches. The choice is either to match only CR, LF, or CRLF,
or to match any Unicode newline sequence. The default is specified when
PCRE is built. It can be overridden from within the pattern, or by set-
ting an option when a compiled pattern is matched.
PCRE_CASELESS
- If this bit is set, letters in the pattern match both upper and lower
- case letters. It is equivalent to Perl's /i option, and it can be
- changed within a pattern by a (?i) option setting. In UTF-8 mode, PCRE
- always understands the concept of case for characters whose values are
- less than 128, so caseless matching is always possible. For characters
- with higher values, the concept of case is supported if PCRE is com-
- piled with Unicode property support, but not otherwise. If you want to
- use caseless matching for characters 128 and above, you must ensure
- that PCRE is compiled with Unicode property support as well as with
+ If this bit is set, letters in the pattern match both upper and lower
+ case letters. It is equivalent to Perl's /i option, and it can be
+ changed within a pattern by a (?i) option setting. In UTF-8 mode, PCRE
+ always understands the concept of case for characters whose values are
+ less than 128, so caseless matching is always possible. For characters
+ with higher values, the concept of case is supported if PCRE is com-
+ piled with Unicode property support, but not otherwise. If you want to
+ use caseless matching for characters 128 and above, you must ensure
+ that PCRE is compiled with Unicode property support as well as with
UTF-8 support.
PCRE_DOLLAR_ENDONLY
- If this bit is set, a dollar metacharacter in the pattern matches only
- at the end of the subject string. Without this option, a dollar also
- matches immediately before a newline at the end of the string (but not
- before any other newlines). The PCRE_DOLLAR_ENDONLY option is ignored
- if PCRE_MULTILINE is set. There is no equivalent to this option in
+ If this bit is set, a dollar metacharacter in the pattern matches only
+ at the end of the subject string. Without this option, a dollar also
+ matches immediately before a newline at the end of the string (but not
+ before any other newlines). The PCRE_DOLLAR_ENDONLY option is ignored
+ if PCRE_MULTILINE is set. There is no equivalent to this option in
Perl, and no way to set it within a pattern.
PCRE_DOTALL
- If this bit is set, a dot metacharacter in the pattern matches a char-
+ If this bit is set, a dot metacharacter in the pattern matches a char-
acter of any value, including one that indicates a newline. However, it
- only ever matches one character, even if newlines are coded as CRLF.
- Without this option, a dot does not match when the current position is
+ only ever matches one character, even if newlines are coded as CRLF.
+ Without this option, a dot does not match when the current position is
at a newline. This option is equivalent to Perl's /s option, and it can
- be changed within a pattern by a (?s) option setting. A negative class
+ be changed within a pattern by a (?s) option setting. A negative class
such as [^a] always matches newline characters, independent of the set-
ting of this option.
PCRE_DUPNAMES
- If this bit is set, names used to identify capturing subpatterns need
+ If this bit is set, names used to identify capturing subpatterns need
not be unique. This can be helpful for certain types of pattern when it
- is known that only one instance of the named subpattern can ever be
- matched. There are more details of named subpatterns below; see also
+ is known that only one instance of the named subpattern can ever be
+ matched. There are more details of named subpatterns below; see also
the pcrepattern documentation.
PCRE_EXTENDED
- If this bit is set, most white space characters in the pattern are
- totally ignored except when escaped or inside a character class. How-
- ever, white space is not allowed within sequences such as (?> that
- introduce various parenthesized subpatterns, nor within a numerical
- quantifier such as {1,3}. However, ignorable white space is permitted
+ If this bit is set, most white space characters in the pattern are
+ totally ignored except when escaped or inside a character class. How-
+ ever, white space is not allowed within sequences such as (?> that
+ introduce various parenthesized subpatterns, nor within a numerical
+ quantifier such as {1,3}. However, ignorable white space is permitted
between an item and a following quantifier and between a quantifier and
a following + that indicates possessiveness.
White space did not used to include the VT character (code 11), because
Perl did not treat this character as white space. However, Perl changed
- at release 5.18, so PCRE followed at release 8.34, and VT is now
+ at release 5.18, so PCRE followed at release 8.34, and VT is now
treated as white space.
- PCRE_EXTENDED also causes characters between an unescaped # outside a
- character class and the next newline, inclusive, to be ignored.
- PCRE_EXTENDED is equivalent to Perl's /x option, and it can be changed
+ PCRE_EXTENDED also causes characters between an unescaped # outside a
+ character class and the next newline, inclusive, to be ignored.
+ PCRE_EXTENDED is equivalent to Perl's /x option, and it can be changed
within a pattern by a (?x) option setting.
- Which characters are interpreted as newlines is controlled by the
- options passed to pcre_compile() or by a special sequence at the start
- of the pattern, as described in the section entitled "Newline conven-
+ Which characters are interpreted as newlines is controlled by the
+ options passed to pcre_compile() or by a special sequence at the start
+ of the pattern, as described in the section entitled "Newline conven-
tions" in the pcrepattern documentation. Note that the end of this type
- of comment is a literal newline sequence in the pattern; escape
+ of comment is a literal newline sequence in the pattern; escape
sequences that happen to represent a newline do not count.
- This option makes it possible to include comments inside complicated
- patterns. Note, however, that this applies only to data characters.
- White space characters may never appear within special character
+ This option makes it possible to include comments inside complicated
+ patterns. Note, however, that this applies only to data characters.
+ White space characters may never appear within special character
sequences in a pattern, for example within the sequence (?( that intro-
duces a conditional subpattern.
PCRE_EXTRA
- This option was invented in order to turn on additional functionality
- of PCRE that is incompatible with Perl, but it is currently of very
- little use. When set, any backslash in a pattern that is followed by a
- letter that has no special meaning causes an error, thus reserving
- these combinations for future expansion. By default, as in Perl, a
- backslash followed by a letter with no special meaning is treated as a
+ This option was invented in order to turn on additional functionality
+ of PCRE that is incompatible with Perl, but it is currently of very
+ little use. When set, any backslash in a pattern that is followed by a
+ letter that has no special meaning causes an error, thus reserving
+ these combinations for future expansion. By default, as in Perl, a
+ backslash followed by a letter with no special meaning is treated as a
literal. (Perl can, however, be persuaded to give an error for this, by
- running it with the -w option.) There are at present no other features
- controlled by this option. It can also be set by a (?X) option setting
+ running it with the -w option.) There are at present no other features
+ controlled by this option. It can also be set by a (?X) option setting
within a pattern.
PCRE_FIRSTLINE
- If this option is set, an unanchored pattern is required to match
- before or at the first newline in the subject string, though the
+ If this option is set, an unanchored pattern is required to match
+ before or at the first newline in the subject string, though the
matched text may continue over the newline.
PCRE_JAVASCRIPT_COMPAT
If this option is set, PCRE's behaviour is changed in some ways so that
- it is compatible with JavaScript rather than Perl. The changes are as
+ it is compatible with JavaScript rather than Perl. The changes are as
follows:
- (1) A lone closing square bracket in a pattern causes a compile-time
- error, because this is illegal in JavaScript (by default it is treated
+ (1) A lone closing square bracket in a pattern causes a compile-time
+ error, because this is illegal in JavaScript (by default it is treated
as a data character). Thus, the pattern AB]CD becomes illegal when this
option is set.
- (2) At run time, a back reference to an unset subpattern group matches
- an empty string (by default this causes the current matching alterna-
- tive to fail). A pattern such as (\1)(a) succeeds when this option is
- set (assuming it can find an "a" in the subject), whereas it fails by
+ (2) At run time, a back reference to an unset subpattern group matches
+ an empty string (by default this causes the current matching alterna-
+ tive to fail). A pattern such as (\1)(a) succeeds when this option is
+ set (assuming it can find an "a" in the subject), whereas it fails by
default, for Perl compatibility.
(3) \U matches an upper case "U" character; by default \U causes a com-
pile time error (Perl uses \U to upper case subsequent characters).
(4) \u matches a lower case "u" character unless it is followed by four
- hexadecimal digits, in which case the hexadecimal number defines the
- code point to match. By default, \u causes a compile time error (Perl
+ hexadecimal digits, in which case the hexadecimal number defines the
+ code point to match. By default, \u causes a compile time error (Perl
uses it to upper case the following character).
- (5) \x matches a lower case "x" character unless it is followed by two
- hexadecimal digits, in which case the hexadecimal number defines the
- code point to match. By default, as in Perl, a hexadecimal number is
+ (5) \x matches a lower case "x" character unless it is followed by two
+ hexadecimal digits, in which case the hexadecimal number defines the
+ code point to match. By default, as in Perl, a hexadecimal number is
always expected after \x, but it may have zero, one, or two digits (so,
for example, \xz matches a binary zero character followed by z).
PCRE_MULTILINE
- By default, for the purposes of matching "start of line" and "end of
+ By default, for the purposes of matching "start of line" and "end of
line", PCRE treats the subject string as consisting of a single line of
- characters, even if it actually contains newlines. The "start of line"
+ characters, even if it actually contains newlines. The "start of line"
metacharacter (^) matches only at the start of the string, and the "end
- of line" metacharacter ($) matches only at the end of the string, or
- before a terminating newline (except when PCRE_DOLLAR_ENDONLY is set).
- Note, however, that unless PCRE_DOTALL is set, the "any character"
- metacharacter (.) does not match at a newline. This behaviour (for ^,
+ of line" metacharacter ($) matches only at the end of the string, or
+ before a terminating newline (except when PCRE_DOLLAR_ENDONLY is set).
+ Note, however, that unless PCRE_DOTALL is set, the "any character"
+ metacharacter (.) does not match at a newline. This behaviour (for ^,
$, and dot) is the same as Perl.
- When PCRE_MULTILINE it is set, the "start of line" and "end of line"
- constructs match immediately following or immediately before internal
- newlines in the subject string, respectively, as well as at the very
- start and end. This is equivalent to Perl's /m option, and it can be
+ When PCRE_MULTILINE it is set, the "start of line" and "end of line"
+ constructs match immediately following or immediately before internal
+ newlines in the subject string, respectively, as well as at the very
+ start and end. This is equivalent to Perl's /m option, and it can be
changed within a pattern by a (?m) option setting. If there are no new-
- lines in a subject string, or no occurrences of ^ or $ in a pattern,
+ lines in a subject string, or no occurrences of ^ or $ in a pattern,
setting PCRE_MULTILINE has no effect.
PCRE_NEVER_UTF
This option locks out interpretation of the pattern as UTF-8 (or UTF-16
- or UTF-32 in the 16-bit and 32-bit libraries). In particular, it pre-
- vents the creator of the pattern from switching to UTF interpretation
+ or UTF-32 in the 16-bit and 32-bit libraries). In particular, it pre-
+ vents the creator of the pattern from switching to UTF interpretation
by starting the pattern with (*UTF). This may be useful in applications
that process patterns from external sources. The combination of
PCRE_UTF8 and PCRE_NEVER_UTF also causes an error.
PCRE_NEWLINE_ANYCRLF
PCRE_NEWLINE_ANY
- These options override the default newline definition that was chosen
- when PCRE was built. Setting the first or the second specifies that a
- newline is indicated by a single character (CR or LF, respectively).
- Setting PCRE_NEWLINE_CRLF specifies that a newline is indicated by the
- two-character CRLF sequence. Setting PCRE_NEWLINE_ANYCRLF specifies
+ These options override the default newline definition that was chosen
+ when PCRE was built. Setting the first or the second specifies that a
+ newline is indicated by a single character (CR or LF, respectively).
+ Setting PCRE_NEWLINE_CRLF specifies that a newline is indicated by the
+ two-character CRLF sequence. Setting PCRE_NEWLINE_ANYCRLF specifies
that any of the three preceding sequences should be recognized. Setting
- PCRE_NEWLINE_ANY specifies that any Unicode newline sequence should be
+ PCRE_NEWLINE_ANY specifies that any Unicode newline sequence should be
recognized.
- In an ASCII/Unicode environment, the Unicode newline sequences are the
- three just mentioned, plus the single characters VT (vertical tab,
+ In an ASCII/Unicode environment, the Unicode newline sequences are the
+ three just mentioned, plus the single characters VT (vertical tab,
U+000B), FF (form feed, U+000C), NEL (next line, U+0085), LS (line sep-
- arator, U+2028), and PS (paragraph separator, U+2029). For the 8-bit
+ arator, U+2028), and PS (paragraph separator, U+2029). For the 8-bit
library, the last two are recognized only in UTF-8 mode.
- When PCRE is compiled to run in an EBCDIC (mainframe) environment, the
+ When PCRE is compiled to run in an EBCDIC (mainframe) environment, the
code for CR is 0x0d, the same as ASCII. However, the character code for
- LF is normally 0x15, though in some EBCDIC environments 0x25 is used.
- Whichever of these is not LF is made to correspond to Unicode's NEL
- character. EBCDIC codes are all less than 256. For more details, see
+ LF is normally 0x15, though in some EBCDIC environments 0x25 is used.
+ Whichever of these is not LF is made to correspond to Unicode's NEL
+ character. EBCDIC codes are all less than 256. For more details, see
the pcrebuild documentation.
- The newline setting in the options word uses three bits that are
+ The newline setting in the options word uses three bits that are
treated as a number, giving eight possibilities. Currently only six are
- used (default plus the five values above). This means that if you set
- more than one newline option, the combination may or may not be sensi-
+ used (default plus the five values above). This means that if you set
+ more than one newline option, the combination may or may not be sensi-
ble. For example, PCRE_NEWLINE_CR with PCRE_NEWLINE_LF is equivalent to
- PCRE_NEWLINE_CRLF, but other combinations may yield unused numbers and
+ PCRE_NEWLINE_CRLF, but other combinations may yield unused numbers and
cause an error.
- The only time that a line break in a pattern is specially recognized
- when compiling is when PCRE_EXTENDED is set. CR and LF are white space
- characters, and so are ignored in this mode. Also, an unescaped # out-
- side a character class indicates a comment that lasts until after the
- next line break sequence. In other circumstances, line break sequences
+ The only time that a line break in a pattern is specially recognized
+ when compiling is when PCRE_EXTENDED is set. CR and LF are white space
+ characters, and so are ignored in this mode. Also, an unescaped # out-
+ side a character class indicates a comment that lasts until after the
+ next line break sequence. In other circumstances, line break sequences
in patterns are treated as literal data.
The newline option that is set at compile time becomes the default that
PCRE_NO_AUTO_CAPTURE
If this option is set, it disables the use of numbered capturing paren-
- theses in the pattern. Any opening parenthesis that is not followed by
- ? behaves as if it were followed by ?: but named parentheses can still
- be used for capturing (and they acquire numbers in the usual way).
+ theses in the pattern. Any opening parenthesis that is not followed by
+ ? behaves as if it were followed by ?: but named parentheses can still
+ be used for capturing (and they acquire numbers in the usual way).
There is no equivalent of this option in Perl.
PCRE_NO_AUTO_POSSESS
- If this option is set, it disables "auto-possessification". This is an
- optimization that, for example, turns a+b into a++b in order to avoid
- backtracks into a+ that can never be successful. However, if callouts
- are in use, auto-possessification means that some of them are never
+ If this option is set, it disables "auto-possessification". This is an
+ optimization that, for example, turns a+b into a++b in order to avoid
+ backtracks into a+ that can never be successful. However, if callouts
+ are in use, auto-possessification means that some of them are never
taken. You can set this option if you want the matching functions to do
- a full unoptimized search and run all the callouts, but it is mainly
+ a full unoptimized search and run all the callouts, but it is mainly
provided for testing purposes.
PCRE_NO_START_OPTIMIZE
- This is an option that acts at matching time; that is, it is really an
- option for pcre_exec() or pcre_dfa_exec(). If it is set at compile
- time, it is remembered with the compiled pattern and assumed at match-
- ing time. This is necessary if you want to use JIT execution, because
- the JIT compiler needs to know whether or not this option is set. For
+ This is an option that acts at matching time; that is, it is really an
+ option for pcre_exec() or pcre_dfa_exec(). If it is set at compile
+ time, it is remembered with the compiled pattern and assumed at match-
+ ing time. This is necessary if you want to use JIT execution, because
+ the JIT compiler needs to know whether or not this option is set. For
details see the discussion of PCRE_NO_START_OPTIMIZE below.
PCRE_UCP
- This option changes the way PCRE processes \B, \b, \D, \d, \S, \s, \W,
- \w, and some of the POSIX character classes. By default, only ASCII
- characters are recognized, but if PCRE_UCP is set, Unicode properties
- are used instead to classify characters. More details are given in the
- section on generic character types in the pcrepattern page. If you set
- PCRE_UCP, matching one of the items it affects takes much longer. The
- option is available only if PCRE has been compiled with Unicode prop-
+ This option changes the way PCRE processes \B, \b, \D, \d, \S, \s, \W,
+ \w, and some of the POSIX character classes. By default, only ASCII
+ characters are recognized, but if PCRE_UCP is set, Unicode properties
+ are used instead to classify characters. More details are given in the
+ section on generic character types in the pcrepattern page. If you set
+ PCRE_UCP, matching one of the items it affects takes much longer. The
+ option is available only if PCRE has been compiled with Unicode prop-
erty support.
PCRE_UNGREEDY
- This option inverts the "greediness" of the quantifiers so that they
- are not greedy by default, but become greedy if followed by "?". It is
- not compatible with Perl. It can also be set by a (?U) option setting
+ This option inverts the "greediness" of the quantifiers so that they
+ are not greedy by default, but become greedy if followed by "?". It is
+ not compatible with Perl. It can also be set by a (?U) option setting
within the pattern.
PCRE_UTF8
- This option causes PCRE to regard both the pattern and the subject as
+ This option causes PCRE to regard both the pattern and the subject as
strings of UTF-8 characters instead of single-byte strings. However, it
- is available only when PCRE is built to include UTF support. If not,
- the use of this option provokes an error. Details of how this option
+ is available only when PCRE is built to include UTF support. If not,
+ the use of this option provokes an error. Details of how this option
changes the behaviour of PCRE are given in the pcreunicode page.
PCRE_NO_UTF8_CHECK
When PCRE_UTF8 is set, the validity of the pattern as a UTF-8 string is
- automatically checked. There is a discussion about the validity of
- UTF-8 strings in the pcreunicode page. If an invalid UTF-8 sequence is
- found, pcre_compile() returns an error. If you already know that your
- pattern is valid, and you want to skip this check for performance rea-
- sons, you can set the PCRE_NO_UTF8_CHECK option. When it is set, the
+ automatically checked. There is a discussion about the validity of
+ UTF-8 strings in the pcreunicode page. If an invalid UTF-8 sequence is
+ found, pcre_compile() returns an error. If you already know that your
+ pattern is valid, and you want to skip this check for performance rea-
+ sons, you can set the PCRE_NO_UTF8_CHECK option. When it is set, the
effect of passing an invalid UTF-8 string as a pattern is undefined. It
may cause your program to crash or loop. Note that this option can also
- be passed to pcre_exec() and pcre_dfa_exec(), to suppress the validity
- checking of subject strings only. If the same string is being matched
- many times, the option can be safely set for the second and subsequent
+ be passed to pcre_exec() and pcre_dfa_exec(), to suppress the validity
+ checking of subject strings only. If the same string is being matched
+ many times, the option can be safely set for the second and subsequent
matchings to improve performance.
COMPILATION ERROR CODES
- The following table lists the error codes than may be returned by
- pcre_compile2(), along with the error messages that may be returned by
- both compiling functions. Note that error messages are always 8-bit
- ASCII strings, even in 16-bit or 32-bit mode. As PCRE has developed,
- some error codes have fallen out of use. To avoid confusion, they have
+ The following table lists the error codes than may be returned by
+ pcre_compile2(), along with the error messages that may be returned by
+ both compiling functions. Note that error messages are always 8-bit
+ ASCII strings, even in 16-bit or 32-bit mode. As PCRE has developed,
+ some error codes have fallen out of use. To avoid confusion, they have
not been re-used.
0 no error
84 group name must start with a non-digit
85 parentheses are too deeply nested (stack check)
- The numbers 32 and 10000 in errors 48 and 49 are defaults; different
+ The numbers 32 and 10000 in errors 48 and 49 are defaults; different
values may be used if the limits were changed when PCRE was built.
pcre_extra *pcre_study(const pcre *code, int options,
const char **errptr);
- If a compiled pattern is going to be used several times, it is worth
+ If a compiled pattern is going to be used several times, it is worth
spending more time analyzing it in order to speed up the time taken for
- matching. The function pcre_study() takes a pointer to a compiled pat-
+ matching. The function pcre_study() takes a pointer to a compiled pat-
tern as its first argument. If studying the pattern produces additional
- information that will help speed up matching, pcre_study() returns a
- pointer to a pcre_extra block, in which the study_data field points to
+ information that will help speed up matching, pcre_study() returns a
+ pointer to a pcre_extra block, in which the study_data field points to
the results of the study.
The returned value from pcre_study() can be passed directly to
- pcre_exec() or pcre_dfa_exec(). However, a pcre_extra block also con-
- tains other fields that can be set by the caller before the block is
+ pcre_exec() or pcre_dfa_exec(). However, a pcre_extra block also con-
+ tains other fields that can be set by the caller before the block is
passed; these are described below in the section on matching a pattern.
- If studying the pattern does not produce any useful information,
- pcre_study() returns NULL by default. In that circumstance, if the
+ If studying the pattern does not produce any useful information,
+ pcre_study() returns NULL by default. In that circumstance, if the
calling program wants to pass any of the other fields to pcre_exec() or
- pcre_dfa_exec(), it must set up its own pcre_extra block. However, if
- pcre_study() is called with the PCRE_STUDY_EXTRA_NEEDED option, it
+ pcre_dfa_exec(), it must set up its own pcre_extra block. However, if
+ pcre_study() is called with the PCRE_STUDY_EXTRA_NEEDED option, it
returns a pcre_extra block even if studying did not find any additional
- information. It may still return NULL, however, if an error occurs in
+ information. It may still return NULL, however, if an error occurs in
pcre_study().
- The second argument of pcre_study() contains option bits. There are
+ The second argument of pcre_study() contains option bits. There are
three further options in addition to PCRE_STUDY_EXTRA_NEEDED:
PCRE_STUDY_JIT_COMPILE
PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE
PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
- If any of these are set, and the just-in-time compiler is available,
- the pattern is further compiled into machine code that executes much
- faster than the pcre_exec() interpretive matching function. If the
- just-in-time compiler is not available, these options are ignored. All
+ If any of these are set, and the just-in-time compiler is available,
+ the pattern is further compiled into machine code that executes much
+ faster than the pcre_exec() interpretive matching function. If the
+ just-in-time compiler is not available, these options are ignored. All
undefined bits in the options argument must be zero.
- JIT compilation is a heavyweight optimization. It can take some time
- for patterns to be analyzed, and for one-off matches and simple pat-
- terns the benefit of faster execution might be offset by a much slower
+ JIT compilation is a heavyweight optimization. It can take some time
+ for patterns to be analyzed, and for one-off matches and simple pat-
+ terns the benefit of faster execution might be offset by a much slower
study time. Not all patterns can be optimized by the JIT compiler. For
- those that cannot be handled, matching automatically falls back to the
- pcre_exec() interpreter. For more details, see the pcrejit documenta-
+ those that cannot be handled, matching automatically falls back to the
+ pcre_exec() interpreter. For more details, see the pcrejit documenta-
tion.
- The third argument for pcre_study() is a pointer for an error message.
- If studying succeeds (even if no data is returned), the variable it
- points to is set to NULL. Otherwise it is set to point to a textual
+ The third argument for pcre_study() is a pointer for an error message.
+ If studying succeeds (even if no data is returned), the variable it
+ points to is set to NULL. Otherwise it is set to point to a textual
error message. This is a static string that is part of the library. You
- must not try to free it. You should test the error pointer for NULL
+ must not try to free it. You should test the error pointer for NULL
after calling pcre_study(), to be sure that it has run successfully.
- When you are finished with a pattern, you can free the memory used for
+ When you are finished with a pattern, you can free the memory used for
the study data by calling pcre_free_study(). This function was added to
- the API for release 8.20. For earlier versions, the memory could be
- freed with pcre_free(), just like the pattern itself. This will still
- work in cases where JIT optimization is not used, but it is advisable
+ the API for release 8.20. For earlier versions, the memory could be
+ freed with pcre_free(), just like the pattern itself. This will still
+ work in cases where JIT optimization is not used, but it is advisable
to change to the new function when convenient.
- This is a typical way in which pcre_study() is used (except that in a
+ This is a typical way in which pcre_study() is used (except that in a
real application there should be tests for errors):
int rc;
Studying a pattern does two things: first, a lower bound for the length
of subject string that is needed to match the pattern is computed. This
does not mean that there are any strings of that length that match, but
- it does guarantee that no shorter strings match. The value is used to
+ it does guarantee that no shorter strings match. The value is used to
avoid wasting time by trying to match strings that are shorter than the
- lower bound. You can find out the value in a calling program via the
+ lower bound. You can find out the value in a calling program via the
pcre_fullinfo() function.
Studying a pattern is also useful for non-anchored patterns that do not
- have a single fixed starting character. A bitmap of possible starting
- bytes is created. This speeds up finding a position in the subject at
+ have a single fixed starting character. A bitmap of possible starting
+ bytes is created. This speeds up finding a position in the subject at
which to start matching. (In 16-bit mode, the bitmap is used for 16-bit
- values less than 256. In 32-bit mode, the bitmap is used for 32-bit
+ values less than 256. In 32-bit mode, the bitmap is used for 32-bit
values less than 256.)
- These two optimizations apply to both pcre_exec() and pcre_dfa_exec(),
- and the information is also used by the JIT compiler. The optimiza-
- tions can be disabled by setting the PCRE_NO_START_OPTIMIZE option.
- You might want to do this if your pattern contains callouts or (*MARK)
- and you want to make use of these facilities in cases where matching
+ These two optimizations apply to both pcre_exec() and pcre_dfa_exec(),
+ and the information is also used by the JIT compiler. The optimiza-
+ tions can be disabled by setting the PCRE_NO_START_OPTIMIZE option.
+ You might want to do this if your pattern contains callouts or (*MARK)
+ and you want to make use of these facilities in cases where matching
fails.
- PCRE_NO_START_OPTIMIZE can be specified at either compile time or exe-
- cution time. However, if PCRE_NO_START_OPTIMIZE is passed to
+ PCRE_NO_START_OPTIMIZE can be specified at either compile time or exe-
+ cution time. However, if PCRE_NO_START_OPTIMIZE is passed to
pcre_exec(), (that is, after any JIT compilation has happened) JIT exe-
- cution is disabled. For JIT execution to work with PCRE_NO_START_OPTI-
+ cution is disabled. For JIT execution to work with PCRE_NO_START_OPTI-
MIZE, the option must be set at compile time.
There is a longer discussion of PCRE_NO_START_OPTIMIZE below.
LOCALE SUPPORT
- PCRE handles caseless matching, and determines whether characters are
- letters, digits, or whatever, by reference to a set of tables, indexed
- by character code point. When running in UTF-8 mode, or in the 16- or
+ PCRE handles caseless matching, and determines whether characters are
+ letters, digits, or whatever, by reference to a set of tables, indexed
+ by character code point. When running in UTF-8 mode, or in the 16- or
32-bit libraries, this applies only to characters with code points less
- than 256. By default, higher-valued code points never match escapes
- such as \w or \d. However, if PCRE is built with Unicode property sup-
- port, all characters can be tested with \p and \P, or, alternatively,
- the PCRE_UCP option can be set when a pattern is compiled; this causes
- \w and friends to use Unicode property support instead of the built-in
+ than 256. By default, higher-valued code points never match escapes
+ such as \w or \d. However, if PCRE is built with Unicode property sup-
+ port, all characters can be tested with \p and \P, or, alternatively,
+ the PCRE_UCP option can be set when a pattern is compiled; this causes
+ \w and friends to use Unicode property support instead of the built-in
tables.
- The use of locales with Unicode is discouraged. If you are handling
- characters with code points greater than 128, you should either use
+ The use of locales with Unicode is discouraged. If you are handling
+ characters with code points greater than 128, you should either use
Unicode support, or use locales, but not try to mix the two.
- PCRE contains an internal set of tables that are used when the final
- argument of pcre_compile() is NULL. These are sufficient for many
+ PCRE contains an internal set of tables that are used when the final
+ argument of pcre_compile() is NULL. These are sufficient for many
applications. Normally, the internal tables recognize only ASCII char-
acters. However, when PCRE is built, it is possible to cause the inter-
nal tables to be rebuilt in the default "C" locale of the local system,
which may cause them to be different.
- The internal tables can always be overridden by tables supplied by the
+ The internal tables can always be overridden by tables supplied by the
application that calls PCRE. These may be created in a different locale
- from the default. As more and more applications change to using Uni-
+ from the default. As more and more applications change to using Uni-
code, the need for this locale support is expected to die away.
- External tables are built by calling the pcre_maketables() function,
- which has no arguments, in the relevant locale. The result can then be
- passed to pcre_compile() as often as necessary. For example, to build
- and use tables that are appropriate for the French locale (where
- accented characters with values greater than 128 are treated as let-
+ External tables are built by calling the pcre_maketables() function,
+ which has no arguments, in the relevant locale. The result can then be
+ passed to pcre_compile() as often as necessary. For example, to build
+ and use tables that are appropriate for the French locale (where
+ accented characters with values greater than 128 are treated as let-
ters), the following code could be used:
setlocale(LC_CTYPE, "fr_FR");
tables = pcre_maketables();
re = pcre_compile(..., tables);
- The locale name "fr_FR" is used on Linux and other Unix-like systems;
+ The locale name "fr_FR" is used on Linux and other Unix-like systems;
if you are using Windows, the name for the French locale is "french".
- When pcre_maketables() runs, the tables are built in memory that is
- obtained via pcre_malloc. It is the caller's responsibility to ensure
- that the memory containing the tables remains available for as long as
+ When pcre_maketables() runs, the tables are built in memory that is
+ obtained via pcre_malloc. It is the caller's responsibility to ensure
+ that the memory containing the tables remains available for as long as
it is needed.
The pointer that is passed to pcre_compile() is saved with the compiled
- pattern, and the same tables are used via this pointer by pcre_study()
- and also by pcre_exec() and pcre_dfa_exec(). Thus, for any single pat-
+ pattern, and the same tables are used via this pointer by pcre_study()
+ and also by pcre_exec() and pcre_dfa_exec(). Thus, for any single pat-
tern, compilation, studying and matching all happen in the same locale,
but different patterns can be processed in different locales.
- It is possible to pass a table pointer or NULL (indicating the use of
+ It is possible to pass a table pointer or NULL (indicating the use of
the internal tables) to pcre_exec() or pcre_dfa_exec() (see the discus-
sion below in the section on matching a pattern). This facility is pro-
- vided for use with pre-compiled patterns that have been saved and
- reloaded. Character tables are not saved with patterns, so if a non-
+ vided for use with pre-compiled patterns that have been saved and
+ reloaded. Character tables are not saved with patterns, so if a non-
standard table was used at compile time, it must be provided again when
- the reloaded pattern is matched. Attempting to use this facility to
+ the reloaded pattern is matched. Attempting to use this facility to
match a pattern in a different locale from the one in which it was com-
piled is likely to lead to anomalous (usually incorrect) results.
int pcre_fullinfo(const pcre *code, const pcre_extra *extra,
int what, void *where);
- The pcre_fullinfo() function returns information about a compiled pat-
- tern. It replaces the pcre_info() function, which was removed from the
+ The pcre_fullinfo() function returns information about a compiled pat-
+ tern. It replaces the pcre_info() function, which was removed from the
library at version 8.30, after more than 10 years of obsolescence.
- The first argument for pcre_fullinfo() is a pointer to the compiled
- pattern. The second argument is the result of pcre_study(), or NULL if
- the pattern was not studied. The third argument specifies which piece
- of information is required, and the fourth argument is a pointer to a
- variable to receive the data. The yield of the function is zero for
+ The first argument for pcre_fullinfo() is a pointer to the compiled
+ pattern. The second argument is the result of pcre_study(), or NULL if
+ the pattern was not studied. The third argument specifies which piece
+ of information is required, and the fourth argument is a pointer to a
+ variable to receive the data. The yield of the function is zero for
success, or one of the following negative numbers:
PCRE_ERROR_NULL the argument code was NULL
PCRE_ERROR_BADOPTION the value of what was invalid
PCRE_ERROR_UNSET the requested field is not set
- The "magic number" is placed at the start of each compiled pattern as
- an simple check against passing an arbitrary memory pointer. The endi-
+ The "magic number" is placed at the start of each compiled pattern as
+ an simple check against passing an arbitrary memory pointer. The endi-
anness error can occur if a compiled pattern is saved and reloaded on a
- different host. Here is a typical call of pcre_fullinfo(), to obtain
+ different host. Here is a typical call of pcre_fullinfo(), to obtain
the length of the compiled pattern:
int rc;
PCRE_INFO_SIZE, /* what is required */
&length); /* where to put the data */
- The possible values for the third argument are defined in pcre.h, and
+ The possible values for the third argument are defined in pcre.h, and
are as follows:
PCRE_INFO_BACKREFMAX
- Return the number of the highest back reference in the pattern. The
- fourth argument should point to an int variable. Zero is returned if
+ Return the number of the highest back reference in the pattern. The
+ fourth argument should point to an int variable. Zero is returned if
there are no back references.
PCRE_INFO_CAPTURECOUNT
- Return the number of capturing subpatterns in the pattern. The fourth
+ Return the number of capturing subpatterns in the pattern. The fourth
argument should point to an int variable.
PCRE_INFO_DEFAULT_TABLES
- Return a pointer to the internal default character tables within PCRE.
- The fourth argument should point to an unsigned char * variable. This
+ Return a pointer to the internal default character tables within PCRE.
+ The fourth argument should point to an unsigned char * variable. This
information call is provided for internal use by the pcre_study() func-
- tion. External callers can cause PCRE to use its internal tables by
+ tion. External callers can cause PCRE to use its internal tables by
passing a NULL table pointer.
PCRE_INFO_FIRSTBYTE (deprecated)
Return information about the first data unit of any matched string, for
- a non-anchored pattern. The name of this option refers to the 8-bit
- library, where data units are bytes. The fourth argument should point
- to an int variable. Negative values are used for special cases. How-
- ever, this means that when the 32-bit library is in non-UTF-32 mode,
- the full 32-bit range of characters cannot be returned. For this rea-
- son, this value is deprecated; use PCRE_INFO_FIRSTCHARACTERFLAGS and
+ a non-anchored pattern. The name of this option refers to the 8-bit
+ library, where data units are bytes. The fourth argument should point
+ to an int variable. Negative values are used for special cases. How-
+ ever, this means that when the 32-bit library is in non-UTF-32 mode,
+ the full 32-bit range of characters cannot be returned. For this rea-
+ son, this value is deprecated; use PCRE_INFO_FIRSTCHARACTERFLAGS and
PCRE_INFO_FIRSTCHARACTER instead.
- If there is a fixed first value, for example, the letter "c" from a
- pattern such as (cat|cow|coyote), its value is returned. In the 8-bit
- library, the value is always less than 256. In the 16-bit library the
+ If there is a fixed first value, for example, the letter "c" from a
+ pattern such as (cat|cow|coyote), its value is returned. In the 8-bit
+ library, the value is always less than 256. In the 16-bit library the
value can be up to 0xffff. In the 32-bit library the value can be up to
0x10ffff.
If there is no fixed first value, and if either
- (a) the pattern was compiled with the PCRE_MULTILINE option, and every
+ (a) the pattern was compiled with the PCRE_MULTILINE option, and every
branch starts with "^", or
(b) every branch of the pattern starts with ".*" and PCRE_DOTALL is not
set (if it were set, the pattern would be anchored),
- -1 is returned, indicating that the pattern matches only at the start
- of a subject string or after any newline within the string. Otherwise
+ -1 is returned, indicating that the pattern matches only at the start
+ of a subject string or after any newline within the string. Otherwise
-2 is returned. For anchored patterns, -2 is returned.
PCRE_INFO_FIRSTCHARACTER
- Return the value of the first data unit (non-UTF character) of any
- matched string in the situation where PCRE_INFO_FIRSTCHARACTERFLAGS
- returns 1; otherwise return 0. The fourth argument should point to an
+ Return the value of the first data unit (non-UTF character) of any
+ matched string in the situation where PCRE_INFO_FIRSTCHARACTERFLAGS
+ returns 1; otherwise return 0. The fourth argument should point to an
uint_t variable.
- In the 8-bit library, the value is always less than 256. In the 16-bit
- library the value can be up to 0xffff. In the 32-bit library in UTF-32
- mode the value can be up to 0x10ffff, and up to 0xffffffff when not
+ In the 8-bit library, the value is always less than 256. In the 16-bit
+ library the value can be up to 0xffff. In the 32-bit library in UTF-32
+ mode the value can be up to 0x10ffff, and up to 0xffffffff when not
using UTF-32 mode.
PCRE_INFO_FIRSTCHARACTERFLAGS
Return information about the first data unit of any matched string, for
- a non-anchored pattern. The fourth argument should point to an int
+ a non-anchored pattern. The fourth argument should point to an int
variable.
- If there is a fixed first value, for example, the letter "c" from a
- pattern such as (cat|cow|coyote), 1 is returned, and the character
- value can be retrieved using PCRE_INFO_FIRSTCHARACTER. If there is no
+ If there is a fixed first value, for example, the letter "c" from a
+ pattern such as (cat|cow|coyote), 1 is returned, and the character
+ value can be retrieved using PCRE_INFO_FIRSTCHARACTER. If there is no
fixed first value, and if either
- (a) the pattern was compiled with the PCRE_MULTILINE option, and every
+ (a) the pattern was compiled with the PCRE_MULTILINE option, and every
branch starts with "^", or
(b) every branch of the pattern starts with ".*" and PCRE_DOTALL is not
PCRE_INFO_FIRSTTABLE
- If the pattern was studied, and this resulted in the construction of a
- 256-bit table indicating a fixed set of values for the first data unit
- in any matching string, a pointer to the table is returned. Otherwise
- NULL is returned. The fourth argument should point to an unsigned char
+ If the pattern was studied, and this resulted in the construction of a
+ 256-bit table indicating a fixed set of values for the first data unit
+ in any matching string, a pointer to the table is returned. Otherwise
+ NULL is returned. The fourth argument should point to an unsigned char
* variable.
PCRE_INFO_HASCRORLF
- Return 1 if the pattern contains any explicit matches for CR or LF
- characters, otherwise 0. The fourth argument should point to an int
- variable. An explicit match is either a literal CR or LF character, or
+ Return 1 if the pattern contains any explicit matches for CR or LF
+ characters, otherwise 0. The fourth argument should point to an int
+ variable. An explicit match is either a literal CR or LF character, or
\r or \n.
PCRE_INFO_JCHANGED
- Return 1 if the (?J) or (?-J) option setting is used in the pattern,
- otherwise 0. The fourth argument should point to an int variable. (?J)
+ Return 1 if the (?J) or (?-J) option setting is used in the pattern,
+ otherwise 0. The fourth argument should point to an int variable. (?J)
and (?-J) set and unset the local PCRE_DUPNAMES option, respectively.
PCRE_INFO_JIT
- Return 1 if the pattern was studied with one of the JIT options, and
+ Return 1 if the pattern was studied with one of the JIT options, and
just-in-time compiling was successful. The fourth argument should point
- to an int variable. A return value of 0 means that JIT support is not
- available in this version of PCRE, or that the pattern was not studied
- with a JIT option, or that the JIT compiler could not handle this par-
- ticular pattern. See the pcrejit documentation for details of what can
+ to an int variable. A return value of 0 means that JIT support is not
+ available in this version of PCRE, or that the pattern was not studied
+ with a JIT option, or that the JIT compiler could not handle this par-
+ ticular pattern. See the pcrejit documentation for details of what can
and cannot be handled.
PCRE_INFO_JITSIZE
- If the pattern was successfully studied with a JIT option, return the
- size of the JIT compiled code, otherwise return zero. The fourth argu-
+ If the pattern was successfully studied with a JIT option, return the
+ size of the JIT compiled code, otherwise return zero. The fourth argu-
ment should point to a size_t variable.
PCRE_INFO_LASTLITERAL
- Return the value of the rightmost literal data unit that must exist in
- any matched string, other than at its start, if such a value has been
+ Return the value of the rightmost literal data unit that must exist in
+ any matched string, other than at its start, if such a value has been
recorded. The fourth argument should point to an int variable. If there
is no such value, -1 is returned. For anchored patterns, a last literal
- value is recorded only if it follows something of variable length. For
+ value is recorded only if it follows something of variable length. For
example, for the pattern /^a\d+z\d+/ the returned value is "z", but for
/^a\dz\d/ the returned value is -1.
- Since for the 32-bit library using the non-UTF-32 mode, this function
- is unable to return the full 32-bit range of characters, this value is
+ Since for the 32-bit library using the non-UTF-32 mode, this function
+ is unable to return the full 32-bit range of characters, this value is
deprecated; instead the PCRE_INFO_REQUIREDCHARFLAGS and
PCRE_INFO_REQUIREDCHAR values should be used.
PCRE_INFO_MATCH_EMPTY
- Return 1 if the pattern can match an empty string, otherwise 0. The
+ Return 1 if the pattern can match an empty string, otherwise 0. The
fourth argument should point to an int variable.
PCRE_INFO_MATCHLIMIT
- If the pattern set a match limit by including an item of the form
- (*LIMIT_MATCH=nnnn) at the start, the value is returned. The fourth
- argument should point to an unsigned 32-bit integer. If no such value
- has been set, the call to pcre_fullinfo() returns the error
+ If the pattern set a match limit by including an item of the form
+ (*LIMIT_MATCH=nnnn) at the start, the value is returned. The fourth
+ argument should point to an unsigned 32-bit integer. If no such value
+ has been set, the call to pcre_fullinfo() returns the error
PCRE_ERROR_UNSET.
PCRE_INFO_MAXLOOKBEHIND
- Return the number of characters (NB not data units) in the longest
- lookbehind assertion in the pattern. This information is useful when
- doing multi-segment matching using the partial matching facilities.
+ Return the number of characters (NB not data units) in the longest
+ lookbehind assertion in the pattern. This information is useful when
+ doing multi-segment matching using the partial matching facilities.
Note that the simple assertions \b and \B require a one-character look-
- behind. \A also registers a one-character lookbehind, though it does
- not actually inspect the previous character. This is to ensure that at
+ behind. \A also registers a one-character lookbehind, though it does
+ not actually inspect the previous character. This is to ensure that at
least one character from the old segment is retained when a new segment
is processed. Otherwise, if there are no lookbehinds in the pattern, \A
might match incorrectly at the start of a new segment.
PCRE_INFO_MINLENGTH
- If the pattern was studied and a minimum length for matching subject
- strings was computed, its value is returned. Otherwise the returned
+ If the pattern was studied and a minimum length for matching subject
+ strings was computed, its value is returned. Otherwise the returned
value is -1. The value is a number of characters, which in UTF mode may
- be different from the number of data units. The fourth argument should
- point to an int variable. A non-negative value is a lower bound to the
- length of any matching string. There may not be any strings of that
- length that do actually match, but every string that does match is at
+ be different from the number of data units. The fourth argument should
+ point to an int variable. A non-negative value is a lower bound to the
+ length of any matching string. There may not be any strings of that
+ length that do actually match, but every string that does match is at
least that long.
PCRE_INFO_NAMECOUNT
PCRE_INFO_NAMEENTRYSIZE
PCRE_INFO_NAMETABLE
- PCRE supports the use of named as well as numbered capturing parenthe-
- ses. The names are just an additional way of identifying the parenthe-
+ PCRE supports the use of named as well as numbered capturing parenthe-
+ ses. The names are just an additional way of identifying the parenthe-
ses, which still acquire numbers. Several convenience functions such as
- pcre_get_named_substring() are provided for extracting captured sub-
- strings by name. It is also possible to extract the data directly, by
- first converting the name to a number in order to access the correct
+ pcre_get_named_substring() are provided for extracting captured sub-
+ strings by name. It is also possible to extract the data directly, by
+ first converting the name to a number in order to access the correct
pointers in the output vector (described with pcre_exec() below). To do
- the conversion, you need to use the name-to-number map, which is
+ the conversion, you need to use the name-to-number map, which is
described by these three values.
The map consists of a number of fixed-size entries. PCRE_INFO_NAMECOUNT
gives the number of entries, and PCRE_INFO_NAMEENTRYSIZE gives the size
- of each entry; both of these return an int value. The entry size
- depends on the length of the longest name. PCRE_INFO_NAMETABLE returns
+ of each entry; both of these return an int value. The entry size
+ depends on the length of the longest name. PCRE_INFO_NAMETABLE returns
a pointer to the first entry of the table. This is a pointer to char in
the 8-bit library, where the first two bytes of each entry are the num-
- ber of the capturing parenthesis, most significant byte first. In the
- 16-bit library, the pointer points to 16-bit data units, the first of
- which contains the parenthesis number. In the 32-bit library, the
- pointer points to 32-bit data units, the first of which contains the
- parenthesis number. The rest of the entry is the corresponding name,
+ ber of the capturing parenthesis, most significant byte first. In the
+ 16-bit library, the pointer points to 16-bit data units, the first of
+ which contains the parenthesis number. In the 32-bit library, the
+ pointer points to 32-bit data units, the first of which contains the
+ parenthesis number. The rest of the entry is the corresponding name,
zero terminated.
- The names are in alphabetical order. If (?| is used to create multiple
- groups with the same number, as described in the section on duplicate
+ The names are in alphabetical order. If (?| is used to create multiple
+ groups with the same number, as described in the section on duplicate
subpattern numbers in the pcrepattern page, the groups may be given the
- same name, but there is only one entry in the table. Different names
- for groups of the same number are not permitted. Duplicate names for
+ same name, but there is only one entry in the table. Different names
+ for groups of the same number are not permitted. Duplicate names for
subpatterns with different numbers are permitted, but only if PCRE_DUP-
- NAMES is set. They appear in the table in the order in which they were
- found in the pattern. In the absence of (?| this is the order of
- increasing number; when (?| is used this is not necessarily the case
+ NAMES is set. They appear in the table in the order in which they were
+ found in the pattern. In the absence of (?| this is the order of
+ increasing number; when (?| is used this is not necessarily the case
because later subpatterns may have lower numbers.
- As a simple example of the name/number table, consider the following
+ As a simple example of the name/number table, consider the following
pattern after compilation by the 8-bit library (assume PCRE_EXTENDED is
set, so white space - including newlines - is ignored):
(?<date> (?<year>(\d\d)?\d\d) -
(?<month>\d\d) - (?<day>\d\d) )
- There are four named subpatterns, so the table has four entries, and
- each entry in the table is eight bytes long. The table is as follows,
+ There are four named subpatterns, so the table has four entries, and
+ each entry in the table is eight bytes long. The table is as follows,
with non-printing bytes shows in hexadecimal, and undefined bytes shown
as ??:
00 04 m o n t h 00
00 02 y e a r 00 ??
- When writing code to extract data from named subpatterns using the
- name-to-number map, remember that the length of the entries is likely
+ When writing code to extract data from named subpatterns using the
+ name-to-number map, remember that the length of the entries is likely
to be different for each compiled pattern.
PCRE_INFO_OKPARTIAL
- Return 1 if the pattern can be used for partial matching with
- pcre_exec(), otherwise 0. The fourth argument should point to an int
- variable. From release 8.00, this always returns 1, because the
- restrictions that previously applied to partial matching have been
- lifted. The pcrepartial documentation gives details of partial match-
+ Return 1 if the pattern can be used for partial matching with
+ pcre_exec(), otherwise 0. The fourth argument should point to an int
+ variable. From release 8.00, this always returns 1, because the
+ restrictions that previously applied to partial matching have been
+ lifted. The pcrepartial documentation gives details of partial match-
ing.
PCRE_INFO_OPTIONS
- Return a copy of the options with which the pattern was compiled. The
- fourth argument should point to an unsigned long int variable. These
+ Return a copy of the options with which the pattern was compiled. The
+ fourth argument should point to an unsigned long int variable. These
option bits are those specified in the call to pcre_compile(), modified
by any top-level option settings at the start of the pattern itself. In
- other words, they are the options that will be in force when matching
- starts. For example, if the pattern /(?im)abc(?-i)d/ is compiled with
- the PCRE_EXTENDED option, the result is PCRE_CASELESS, PCRE_MULTILINE,
+ other words, they are the options that will be in force when matching
+ starts. For example, if the pattern /(?im)abc(?-i)d/ is compiled with
+ the PCRE_EXTENDED option, the result is PCRE_CASELESS, PCRE_MULTILINE,
and PCRE_EXTENDED.
- A pattern is automatically anchored by PCRE if all of its top-level
+ A pattern is automatically anchored by PCRE if all of its top-level
alternatives begin with one of the following:
^ unless PCRE_MULTILINE is set
PCRE_INFO_RECURSIONLIMIT
- If the pattern set a recursion limit by including an item of the form
+ If the pattern set a recursion limit by including an item of the form
(*LIMIT_RECURSION=nnnn) at the start, the value is returned. The fourth
- argument should point to an unsigned 32-bit integer. If no such value
- has been set, the call to pcre_fullinfo() returns the error
+ argument should point to an unsigned 32-bit integer. If no such value
+ has been set, the call to pcre_fullinfo() returns the error
PCRE_ERROR_UNSET.
PCRE_INFO_SIZE
- Return the size of the compiled pattern in bytes (for all three
+ Return the size of the compiled pattern in bytes (for all three
libraries). The fourth argument should point to a size_t variable. This
- value does not include the size of the pcre structure that is returned
- by pcre_compile(). The value that is passed as the argument to
- pcre_malloc() when pcre_compile() is getting memory in which to place
+ value does not include the size of the pcre structure that is returned
+ by pcre_compile(). The value that is passed as the argument to
+ pcre_malloc() when pcre_compile() is getting memory in which to place
the compiled data is the value returned by this option plus the size of
- the pcre structure. Studying a compiled pattern, with or without JIT,
+ the pcre structure. Studying a compiled pattern, with or without JIT,
does not alter the value returned by this option.
PCRE_INFO_STUDYSIZE
- Return the size in bytes (for all three libraries) of the data block
+ Return the size in bytes (for all three libraries) of the data block
pointed to by the study_data field in a pcre_extra block. If pcre_extra
- is NULL, or there is no study data, zero is returned. The fourth argu-
- ment should point to a size_t variable. The study_data field is set by
+ is NULL, or there is no study data, zero is returned. The fourth argu-
+ ment should point to a size_t variable. The study_data field is set by
pcre_study() to record information that will speed up matching (see the
- section entitled "Studying a pattern" above). The format of the
- study_data block is private, but its length is made available via this
- option so that it can be saved and restored (see the pcreprecompile
+ section entitled "Studying a pattern" above). The format of the
+ study_data block is private, but its length is made available via this
+ option so that it can be saved and restored (see the pcreprecompile
documentation for details).
PCRE_INFO_REQUIREDCHARFLAGS
- Returns 1 if there is a rightmost literal data unit that must exist in
+ Returns 1 if there is a rightmost literal data unit that must exist in
any matched string, other than at its start. The fourth argument should
- point to an int variable. If there is no such value, 0 is returned. If
+ point to an int variable. If there is no such value, 0 is returned. If
returning 1, the character value itself can be retrieved using
PCRE_INFO_REQUIREDCHAR.
For anchored patterns, a last literal value is recorded only if it fol-
- lows something of variable length. For example, for the pattern
- /^a\d+z\d+/ the returned value 1 (with "z" returned from
+ lows something of variable length. For example, for the pattern
+ /^a\d+z\d+/ the returned value 1 (with "z" returned from
PCRE_INFO_REQUIREDCHAR), but for /^a\dz\d/ the returned value is 0.
PCRE_INFO_REQUIREDCHAR
- Return the value of the rightmost literal data unit that must exist in
- any matched string, other than at its start, if such a value has been
- recorded. The fourth argument should point to an uint32_t variable. If
+ Return the value of the rightmost literal data unit that must exist in
+ any matched string, other than at its start, if such a value has been
+ recorded. The fourth argument should point to an uint32_t variable. If
there is no such value, 0 is returned.
int pcre_refcount(pcre *code, int adjust);
- The pcre_refcount() function is used to maintain a reference count in
+ The pcre_refcount() function is used to maintain a reference count in
the data block that contains a compiled pattern. It is provided for the
- benefit of applications that operate in an object-oriented manner,
+ benefit of applications that operate in an object-oriented manner,
where different parts of the application may be using the same compiled
pattern, but you want to free the block when they are all done.
When a pattern is compiled, the reference count field is initialized to
- zero. It is changed only by calling this function, whose action is to
- add the adjust value (which may be positive or negative) to it. The
+ zero. It is changed only by calling this function, whose action is to
+ add the adjust value (which may be positive or negative) to it. The
yield of the function is the new value. However, the value of the count
- is constrained to lie between 0 and 65535, inclusive. If the new value
+ is constrained to lie between 0 and 65535, inclusive. If the new value
is outside these limits, it is forced to the appropriate limit value.
- Except when it is zero, the reference count is not correctly preserved
- if a pattern is compiled on one host and then transferred to a host
+ Except when it is zero, the reference count is not correctly preserved
+ if a pattern is compiled on one host and then transferred to a host
whose byte-order is different. (This seems a highly unlikely scenario.)
const char *subject, int length, int startoffset,
int options, int *ovector, int ovecsize);
- The function pcre_exec() is called to match a subject string against a
- compiled pattern, which is passed in the code argument. If the pattern
- was studied, the result of the study should be passed in the extra
- argument. You can call pcre_exec() with the same code and extra argu-
- ments as many times as you like, in order to match different subject
+ The function pcre_exec() is called to match a subject string against a
+ compiled pattern, which is passed in the code argument. If the pattern
+ was studied, the result of the study should be passed in the extra
+ argument. You can call pcre_exec() with the same code and extra argu-
+ ments as many times as you like, in order to match different subject
strings with the same pattern.
- This function is the main matching facility of the library, and it
- operates in a Perl-like manner. For specialist use there is also an
- alternative matching function, which is described below in the section
+ This function is the main matching facility of the library, and it
+ operates in a Perl-like manner. For specialist use there is also an
+ alternative matching function, which is described below in the section
about the pcre_dfa_exec() function.
- In most applications, the pattern will have been compiled (and option-
- ally studied) in the same process that calls pcre_exec(). However, it
+ In most applications, the pattern will have been compiled (and option-
+ ally studied) in the same process that calls pcre_exec(). However, it
is possible to save compiled patterns and study data, and then use them
- later in different processes, possibly even on different hosts. For a
+ later in different processes, possibly even on different hosts. For a
discussion about this, see the pcreprecompile documentation.
Here is an example of a simple call to pcre_exec():
Extra data for pcre_exec()
- If the extra argument is not NULL, it must point to a pcre_extra data
- block. The pcre_study() function returns such a block (when it doesn't
- return NULL), but you can also create one for yourself, and pass addi-
- tional information in it. The pcre_extra block contains the following
+ If the extra argument is not NULL, it must point to a pcre_extra data
+ block. The pcre_study() function returns such a block (when it doesn't
+ return NULL), but you can also create one for yourself, and pass addi-
+ tional information in it. The pcre_extra block contains the following
fields (not necessarily in this order):
unsigned long int flags;
const unsigned char *tables;
unsigned char **mark;
- In the 16-bit version of this structure, the mark field has type
+ In the 16-bit version of this structure, the mark field has type
"PCRE_UCHAR16 **".
- In the 32-bit version of this structure, the mark field has type
+ In the 32-bit version of this structure, the mark field has type
"PCRE_UCHAR32 **".
- The flags field is used to specify which of the other fields are set.
+ The flags field is used to specify which of the other fields are set.
The flag bits are:
PCRE_EXTRA_CALLOUT_DATA
PCRE_EXTRA_STUDY_DATA
PCRE_EXTRA_TABLES
- Other flag bits should be set to zero. The study_data field and some-
- times the executable_jit field are set in the pcre_extra block that is
- returned by pcre_study(), together with the appropriate flag bits. You
- should not set these yourself, but you may add to the block by setting
+ Other flag bits should be set to zero. The study_data field and some-
+ times the executable_jit field are set in the pcre_extra block that is
+ returned by pcre_study(), together with the appropriate flag bits. You
+ should not set these yourself, but you may add to the block by setting
other fields and their corresponding flag bits.
The match_limit field provides a means of preventing PCRE from using up
- a vast amount of resources when running patterns that are not going to
- match, but which have a very large number of possibilities in their
- search trees. The classic example is a pattern that uses nested unlim-
+ a vast amount of resources when running patterns that are not going to
+ match, but which have a very large number of possibilities in their
+ search trees. The classic example is a pattern that uses nested unlim-
ited repeats.
- Internally, pcre_exec() uses a function called match(), which it calls
- repeatedly (sometimes recursively). The limit set by match_limit is
- imposed on the number of times this function is called during a match,
- which has the effect of limiting the amount of backtracking that can
+ Internally, pcre_exec() uses a function called match(), which it calls
+ repeatedly (sometimes recursively). The limit set by match_limit is
+ imposed on the number of times this function is called during a match,
+ which has the effect of limiting the amount of backtracking that can
take place. For patterns that are not anchored, the count restarts from
zero for each position in the subject string.
When pcre_exec() is called with a pattern that was successfully studied
- with a JIT option, the way that the matching is executed is entirely
+ with a JIT option, the way that the matching is executed is entirely
different. However, there is still the possibility of runaway matching
that goes on for a very long time, and so the match_limit value is also
used in this case (but in a different way) to limit how long the match-
ing can continue.
- The default value for the limit can be set when PCRE is built; the
- default default is 10 million, which handles all but the most extreme
- cases. You can override the default by suppling pcre_exec() with a
- pcre_extra block in which match_limit is set, and
- PCRE_EXTRA_MATCH_LIMIT is set in the flags field. If the limit is
+ The default value for the limit can be set when PCRE is built; the
+ default default is 10 million, which handles all but the most extreme
+ cases. You can override the default by suppling pcre_exec() with a
+ pcre_extra block in which match_limit is set, and
+ PCRE_EXTRA_MATCH_LIMIT is set in the flags field. If the limit is
exceeded, pcre_exec() returns PCRE_ERROR_MATCHLIMIT.
- A value for the match limit may also be supplied by an item at the
+ A value for the match limit may also be supplied by an item at the
start of a pattern of the form
(*LIMIT_MATCH=d)
- where d is a decimal number. However, such a setting is ignored unless
- d is less than the limit set by the caller of pcre_exec() or, if no
+ where d is a decimal number. However, such a setting is ignored unless
+ d is less than the limit set by the caller of pcre_exec() or, if no
such limit is set, less than the default.
- The match_limit_recursion field is similar to match_limit, but instead
+ The match_limit_recursion field is similar to match_limit, but instead
of limiting the total number of times that match() is called, it limits
- the depth of recursion. The recursion depth is a smaller number than
- the total number of calls, because not all calls to match() are recur-
+ the depth of recursion. The recursion depth is a smaller number than
+ the total number of calls, because not all calls to match() are recur-
sive. This limit is of use only if it is set smaller than match_limit.
- Limiting the recursion depth limits the amount of machine stack that
- can be used, or, when PCRE has been compiled to use memory on the heap
- instead of the stack, the amount of heap memory that can be used. This
- limit is not relevant, and is ignored, when matching is done using JIT
+ Limiting the recursion depth limits the amount of machine stack that
+ can be used, or, when PCRE has been compiled to use memory on the heap
+ instead of the stack, the amount of heap memory that can be used. This
+ limit is not relevant, and is ignored, when matching is done using JIT
compiled code.
- The default value for match_limit_recursion can be set when PCRE is
- built; the default default is the same value as the default for
- match_limit. You can override the default by suppling pcre_exec() with
- a pcre_extra block in which match_limit_recursion is set, and
- PCRE_EXTRA_MATCH_LIMIT_RECURSION is set in the flags field. If the
+ The default value for match_limit_recursion can be set when PCRE is
+ built; the default default is the same value as the default for
+ match_limit. You can override the default by suppling pcre_exec() with
+ a pcre_extra block in which match_limit_recursion is set, and
+ PCRE_EXTRA_MATCH_LIMIT_RECURSION is set in the flags field. If the
limit is exceeded, pcre_exec() returns PCRE_ERROR_RECURSIONLIMIT.
- A value for the recursion limit may also be supplied by an item at the
+ A value for the recursion limit may also be supplied by an item at the
start of a pattern of the form
(*LIMIT_RECURSION=d)
- where d is a decimal number. However, such a setting is ignored unless
- d is less than the limit set by the caller of pcre_exec() or, if no
+ where d is a decimal number. However, such a setting is ignored unless
+ d is less than the limit set by the caller of pcre_exec() or, if no
such limit is set, less than the default.
- The callout_data field is used in conjunction with the "callout" fea-
+ The callout_data field is used in conjunction with the "callout" fea-
ture, and is described in the pcrecallout documentation.
- The tables field is provided for use with patterns that have been pre-
+ The tables field is provided for use with patterns that have been pre-
compiled using custom character tables, saved to disc or elsewhere, and
- then reloaded, because the tables that were used to compile a pattern
- are not saved with it. See the pcreprecompile documentation for a dis-
- cussion of saving compiled patterns for later use. If NULL is passed
+ then reloaded, because the tables that were used to compile a pattern
+ are not saved with it. See the pcreprecompile documentation for a dis-
+ cussion of saving compiled patterns for later use. If NULL is passed
using this mechanism, it forces PCRE's internal tables to be used.
- Warning: The tables that pcre_exec() uses must be the same as those
- that were used when the pattern was compiled. If this is not the case,
+ Warning: The tables that pcre_exec() uses must be the same as those
+ that were used when the pattern was compiled. If this is not the case,
the behaviour of pcre_exec() is undefined. Therefore, when a pattern is
- compiled and matched in the same process, this field should never be
+ compiled and matched in the same process, this field should never be
set. In this (the most common) case, the correct table pointer is auto-
- matically passed with the compiled pattern from pcre_compile() to
+ matically passed with the compiled pattern from pcre_compile() to
pcre_exec().
- If PCRE_EXTRA_MARK is set in the flags field, the mark field must be
- set to point to a suitable variable. If the pattern contains any back-
- tracking control verbs such as (*MARK:NAME), and the execution ends up
- with a name to pass back, a pointer to the name string (zero termi-
- nated) is placed in the variable pointed to by the mark field. The
- names are within the compiled pattern; if you wish to retain such a
- name you must copy it before freeing the memory of a compiled pattern.
- If there is no name to pass back, the variable pointed to by the mark
- field is set to NULL. For details of the backtracking control verbs,
+ If PCRE_EXTRA_MARK is set in the flags field, the mark field must be
+ set to point to a suitable variable. If the pattern contains any back-
+ tracking control verbs such as (*MARK:NAME), and the execution ends up
+ with a name to pass back, a pointer to the name string (zero termi-
+ nated) is placed in the variable pointed to by the mark field. The
+ names are within the compiled pattern; if you wish to retain such a
+ name you must copy it before freeing the memory of a compiled pattern.
+ If there is no name to pass back, the variable pointed to by the mark
+ field is set to NULL. For details of the backtracking control verbs,
see the section entitled "Backtracking control" in the pcrepattern doc-
umentation.
Option bits for pcre_exec()
- The unused bits of the options argument for pcre_exec() must be zero.
- The only bits that may be set are PCRE_ANCHORED, PCRE_NEWLINE_xxx,
- PCRE_NOTBOL, PCRE_NOTEOL, PCRE_NOTEMPTY, PCRE_NOTEMPTY_ATSTART,
- PCRE_NO_START_OPTIMIZE, PCRE_NO_UTF8_CHECK, PCRE_PARTIAL_HARD, and
+ The unused bits of the options argument for pcre_exec() must be zero.
+ The only bits that may be set are PCRE_ANCHORED, PCRE_NEWLINE_xxx,
+ PCRE_NOTBOL, PCRE_NOTEOL, PCRE_NOTEMPTY, PCRE_NOTEMPTY_ATSTART,
+ PCRE_NO_START_OPTIMIZE, PCRE_NO_UTF8_CHECK, PCRE_PARTIAL_HARD, and
PCRE_PARTIAL_SOFT.
- If the pattern was successfully studied with one of the just-in-time
+ If the pattern was successfully studied with one of the just-in-time
(JIT) compile options, the only supported options for JIT execution are
- PCRE_NO_UTF8_CHECK, PCRE_NOTBOL, PCRE_NOTEOL, PCRE_NOTEMPTY,
- PCRE_NOTEMPTY_ATSTART, PCRE_PARTIAL_HARD, and PCRE_PARTIAL_SOFT. If an
- unsupported option is used, JIT execution is disabled and the normal
+ PCRE_NO_UTF8_CHECK, PCRE_NOTBOL, PCRE_NOTEOL, PCRE_NOTEMPTY,
+ PCRE_NOTEMPTY_ATSTART, PCRE_PARTIAL_HARD, and PCRE_PARTIAL_SOFT. If an
+ unsupported option is used, JIT execution is disabled and the normal
interpretive code in pcre_exec() is run.
PCRE_ANCHORED
- The PCRE_ANCHORED option limits pcre_exec() to matching at the first
- matching position. If a pattern was compiled with PCRE_ANCHORED, or
- turned out to be anchored by virtue of its contents, it cannot be made
+ The PCRE_ANCHORED option limits pcre_exec() to matching at the first
+ matching position. If a pattern was compiled with PCRE_ANCHORED, or
+ turned out to be anchored by virtue of its contents, it cannot be made
unachored at matching time.
PCRE_BSR_ANYCRLF
PCRE_BSR_UNICODE
These options (which are mutually exclusive) control what the \R escape
- sequence matches. The choice is either to match only CR, LF, or CRLF,
- or to match any Unicode newline sequence. These options override the
+ sequence matches. The choice is either to match only CR, LF, or CRLF,
+ or to match any Unicode newline sequence. These options override the
choice that was made or defaulted when the pattern was compiled.
PCRE_NEWLINE_CR
PCRE_NEWLINE_ANYCRLF
PCRE_NEWLINE_ANY
- These options override the newline definition that was chosen or
- defaulted when the pattern was compiled. For details, see the descrip-
- tion of pcre_compile() above. During matching, the newline choice
- affects the behaviour of the dot, circumflex, and dollar metacharac-
- ters. It may also alter the way the match position is advanced after a
+ These options override the newline definition that was chosen or
+ defaulted when the pattern was compiled. For details, see the descrip-
+ tion of pcre_compile() above. During matching, the newline choice
+ affects the behaviour of the dot, circumflex, and dollar metacharac-
+ ters. It may also alter the way the match position is advanced after a
match failure for an unanchored pattern.
- When PCRE_NEWLINE_CRLF, PCRE_NEWLINE_ANYCRLF, or PCRE_NEWLINE_ANY is
- set, and a match attempt for an unanchored pattern fails when the cur-
- rent position is at a CRLF sequence, and the pattern contains no
- explicit matches for CR or LF characters, the match position is
+ When PCRE_NEWLINE_CRLF, PCRE_NEWLINE_ANYCRLF, or PCRE_NEWLINE_ANY is
+ set, and a match attempt for an unanchored pattern fails when the cur-
+ rent position is at a CRLF sequence, and the pattern contains no
+ explicit matches for CR or LF characters, the match position is
advanced by two characters instead of one, in other words, to after the
CRLF.
The above rule is a compromise that makes the most common cases work as
- expected. For example, if the pattern is .+A (and the PCRE_DOTALL
+ expected. For example, if the pattern is .+A (and the PCRE_DOTALL
option is not set), it does not match the string "\r\nA" because, after
- failing at the start, it skips both the CR and the LF before retrying.
- However, the pattern [\r\n]A does match that string, because it con-
+ failing at the start, it skips both the CR and the LF before retrying.
+ However, the pattern [\r\n]A does match that string, because it con-
tains an explicit CR or LF reference, and so advances only by one char-
acter after the first failure.
An explicit match for CR of LF is either a literal appearance of one of
- those characters, or one of the \r or \n escape sequences. Implicit
- matches such as [^X] do not count, nor does \s (which includes CR and
+ those characters, or one of the \r or \n escape sequences. Implicit
+ matches such as [^X] do not count, nor does \s (which includes CR and
LF in the characters that it matches).
- Notwithstanding the above, anomalous effects may still occur when CRLF
+ Notwithstanding the above, anomalous effects may still occur when CRLF
is a valid newline sequence and explicit \r or \n escapes appear in the
pattern.
PCRE_NOTBOL
This option specifies that first character of the subject string is not
- the beginning of a line, so the circumflex metacharacter should not
- match before it. Setting this without PCRE_MULTILINE (at compile time)
- causes circumflex never to match. This option affects only the behav-
+ the beginning of a line, so the circumflex metacharacter should not
+ match before it. Setting this without PCRE_MULTILINE (at compile time)
+ causes circumflex never to match. This option affects only the behav-
iour of the circumflex metacharacter. It does not affect \A.
PCRE_NOTEOL
This option specifies that the end of the subject string is not the end
- of a line, so the dollar metacharacter should not match it nor (except
- in multiline mode) a newline immediately before it. Setting this with-
+ of a line, so the dollar metacharacter should not match it nor (except
+ in multiline mode) a newline immediately before it. Setting this with-
out PCRE_MULTILINE (at compile time) causes dollar never to match. This
- option affects only the behaviour of the dollar metacharacter. It does
+ option affects only the behaviour of the dollar metacharacter. It does
not affect \Z or \z.
PCRE_NOTEMPTY
An empty string is not considered to be a valid match if this option is
- set. If there are alternatives in the pattern, they are tried. If all
- the alternatives match the empty string, the entire match fails. For
+ set. If there are alternatives in the pattern, they are tried. If all
+ the alternatives match the empty string, the entire match fails. For
example, if the pattern
a?b?
- is applied to a string not beginning with "a" or "b", it matches an
- empty string at the start of the subject. With PCRE_NOTEMPTY set, this
+ is applied to a string not beginning with "a" or "b", it matches an
+ empty string at the start of the subject. With PCRE_NOTEMPTY set, this
match is not valid, so PCRE searches further into the string for occur-
rences of "a" or "b".
PCRE_NOTEMPTY_ATSTART
- This is like PCRE_NOTEMPTY, except that an empty string match that is
- not at the start of the subject is permitted. If the pattern is
+ This is like PCRE_NOTEMPTY, except that an empty string match that is
+ not at the start of the subject is permitted. If the pattern is
anchored, such a match can occur only if the pattern contains \K.
- Perl has no direct equivalent of PCRE_NOTEMPTY or
- PCRE_NOTEMPTY_ATSTART, but it does make a special case of a pattern
- match of the empty string within its split() function, and when using
- the /g modifier. It is possible to emulate Perl's behaviour after
+ Perl has no direct equivalent of PCRE_NOTEMPTY or
+ PCRE_NOTEMPTY_ATSTART, but it does make a special case of a pattern
+ match of the empty string within its split() function, and when using
+ the /g modifier. It is possible to emulate Perl's behaviour after
matching a null string by first trying the match again at the same off-
- set with PCRE_NOTEMPTY_ATSTART and PCRE_ANCHORED, and then if that
+ set with PCRE_NOTEMPTY_ATSTART and PCRE_ANCHORED, and then if that
fails, by advancing the starting offset (see below) and trying an ordi-
- nary match again. There is some code that demonstrates how to do this
- in the pcredemo sample program. In the most general case, you have to
- check to see if the newline convention recognizes CRLF as a newline,
- and if so, and the current character is CR followed by LF, advance the
+ nary match again. There is some code that demonstrates how to do this
+ in the pcredemo sample program. In the most general case, you have to
+ check to see if the newline convention recognizes CRLF as a newline,
+ and if so, and the current character is CR followed by LF, advance the
starting offset by two characters instead of one.
PCRE_NO_START_OPTIMIZE
- There are a number of optimizations that pcre_exec() uses at the start
- of a match, in order to speed up the process. For example, if it is
+ There are a number of optimizations that pcre_exec() uses at the start
+ of a match, in order to speed up the process. For example, if it is
known that an unanchored match must start with a specific character, it
- searches the subject for that character, and fails immediately if it
- cannot find it, without actually running the main matching function.
+ searches the subject for that character, and fails immediately if it
+ cannot find it, without actually running the main matching function.
This means that a special item such as (*COMMIT) at the start of a pat-
- tern is not considered until after a suitable starting point for the
- match has been found. Also, when callouts or (*MARK) items are in use,
+ tern is not considered until after a suitable starting point for the
+ match has been found. Also, when callouts or (*MARK) items are in use,
these "start-up" optimizations can cause them to be skipped if the pat-
tern is never actually used. The start-up optimizations are in effect a
pre-scan of the subject that takes place before the pattern is run.
- The PCRE_NO_START_OPTIMIZE option disables the start-up optimizations,
- possibly causing performance to suffer, but ensuring that in cases
- where the result is "no match", the callouts do occur, and that items
+ The PCRE_NO_START_OPTIMIZE option disables the start-up optimizations,
+ possibly causing performance to suffer, but ensuring that in cases
+ where the result is "no match", the callouts do occur, and that items
such as (*COMMIT) and (*MARK) are considered at every possible starting
- position in the subject string. If PCRE_NO_START_OPTIMIZE is set at
- compile time, it cannot be unset at matching time. The use of
+ position in the subject string. If PCRE_NO_START_OPTIMIZE is set at
+ compile time, it cannot be unset at matching time. The use of
PCRE_NO_START_OPTIMIZE at matching time (that is, passing it to
- pcre_exec()) disables JIT execution; in this situation, matching is
+ pcre_exec()) disables JIT execution; in this situation, matching is
always done using interpretively.
- Setting PCRE_NO_START_OPTIMIZE can change the outcome of a matching
+ Setting PCRE_NO_START_OPTIMIZE can change the outcome of a matching
operation. Consider the pattern
(*COMMIT)ABC
- When this is compiled, PCRE records the fact that a match must start
- with the character "A". Suppose the subject string is "DEFABC". The
- start-up optimization scans along the subject, finds "A" and runs the
- first match attempt from there. The (*COMMIT) item means that the pat-
- tern must match the current starting position, which in this case, it
- does. However, if the same match is run with PCRE_NO_START_OPTIMIZE
- set, the initial scan along the subject string does not happen. The
- first match attempt is run starting from "D" and when this fails,
- (*COMMIT) prevents any further matches being tried, so the overall
- result is "no match". If the pattern is studied, more start-up opti-
- mizations may be used. For example, a minimum length for the subject
+ When this is compiled, PCRE records the fact that a match must start
+ with the character "A". Suppose the subject string is "DEFABC". The
+ start-up optimization scans along the subject, finds "A" and runs the
+ first match attempt from there. The (*COMMIT) item means that the pat-
+ tern must match the current starting position, which in this case, it
+ does. However, if the same match is run with PCRE_NO_START_OPTIMIZE
+ set, the initial scan along the subject string does not happen. The
+ first match attempt is run starting from "D" and when this fails,
+ (*COMMIT) prevents any further matches being tried, so the overall
+ result is "no match". If the pattern is studied, more start-up opti-
+ mizations may be used. For example, a minimum length for the subject
may be recorded. Consider the pattern
(*MARK:A)(X|Y)
- The minimum length for a match is one character. If the subject is
- "ABC", there will be attempts to match "ABC", "BC", "C", and then
- finally an empty string. If the pattern is studied, the final attempt
- does not take place, because PCRE knows that the subject is too short,
- and so the (*MARK) is never encountered. In this case, studying the
- pattern does not affect the overall match result, which is still "no
+ The minimum length for a match is one character. If the subject is
+ "ABC", there will be attempts to match "ABC", "BC", "C", and then
+ finally an empty string. If the pattern is studied, the final attempt
+ does not take place, because PCRE knows that the subject is too short,
+ and so the (*MARK) is never encountered. In this case, studying the
+ pattern does not affect the overall match result, which is still "no
match", but it does affect the auxiliary information that is returned.
PCRE_NO_UTF8_CHECK
When PCRE_UTF8 is set at compile time, the validity of the subject as a
- UTF-8 string is automatically checked when pcre_exec() is subsequently
+ UTF-8 string is automatically checked when pcre_exec() is subsequently
called. The entire string is checked before any other processing takes
- place. The value of startoffset is also checked to ensure that it
- points to the start of a UTF-8 character. There is a discussion about
- the validity of UTF-8 strings in the pcreunicode page. If an invalid
- sequence of bytes is found, pcre_exec() returns the error
+ place. The value of startoffset is also checked to ensure that it
+ points to the start of a UTF-8 character. There is a discussion about
+ the validity of UTF-8 strings in the pcreunicode page. If an invalid
+ sequence of bytes is found, pcre_exec() returns the error
PCRE_ERROR_BADUTF8 or, if PCRE_PARTIAL_HARD is set and the problem is a
truncated character at the end of the subject, PCRE_ERROR_SHORTUTF8. In
- both cases, information about the precise nature of the error may also
- be returned (see the descriptions of these errors in the section enti-
- tled Error return values from pcre_exec() below). If startoffset con-
+ both cases, information about the precise nature of the error may also
+ be returned (see the descriptions of these errors in the section enti-
+ tled Error return values from pcre_exec() below). If startoffset con-
tains a value that does not point to the start of a UTF-8 character (or
to the end of the subject), PCRE_ERROR_BADUTF8_OFFSET is returned.
- If you already know that your subject is valid, and you want to skip
- these checks for performance reasons, you can set the
- PCRE_NO_UTF8_CHECK option when calling pcre_exec(). You might want to
- do this for the second and subsequent calls to pcre_exec() if you are
- making repeated calls to find all the matches in a single subject
- string. However, you should be sure that the value of startoffset
- points to the start of a character (or the end of the subject). When
+ If you already know that your subject is valid, and you want to skip
+ these checks for performance reasons, you can set the
+ PCRE_NO_UTF8_CHECK option when calling pcre_exec(). You might want to
+ do this for the second and subsequent calls to pcre_exec() if you are
+ making repeated calls to find all the matches in a single subject
+ string. However, you should be sure that the value of startoffset
+ points to the start of a character (or the end of the subject). When
PCRE_NO_UTF8_CHECK is set, the effect of passing an invalid string as a
- subject or an invalid value of startoffset is undefined. Your program
+ subject or an invalid value of startoffset is undefined. Your program
may crash or loop.
PCRE_PARTIAL_HARD
PCRE_PARTIAL_SOFT
- These options turn on the partial matching feature. For backwards com-
- patibility, PCRE_PARTIAL is a synonym for PCRE_PARTIAL_SOFT. A partial
- match occurs if the end of the subject string is reached successfully,
- but there are not enough subject characters to complete the match. If
+ These options turn on the partial matching feature. For backwards com-
+ patibility, PCRE_PARTIAL is a synonym for PCRE_PARTIAL_SOFT. A partial
+ match occurs if the end of the subject string is reached successfully,
+ but there are not enough subject characters to complete the match. If
this happens when PCRE_PARTIAL_SOFT (but not PCRE_PARTIAL_HARD) is set,
- matching continues by testing any remaining alternatives. Only if no
- complete match can be found is PCRE_ERROR_PARTIAL returned instead of
- PCRE_ERROR_NOMATCH. In other words, PCRE_PARTIAL_SOFT says that the
- caller is prepared to handle a partial match, but only if no complete
+ matching continues by testing any remaining alternatives. Only if no
+ complete match can be found is PCRE_ERROR_PARTIAL returned instead of
+ PCRE_ERROR_NOMATCH. In other words, PCRE_PARTIAL_SOFT says that the
+ caller is prepared to handle a partial match, but only if no complete
match can be found.
- If PCRE_PARTIAL_HARD is set, it overrides PCRE_PARTIAL_SOFT. In this
- case, if a partial match is found, pcre_exec() immediately returns
- PCRE_ERROR_PARTIAL, without considering any other alternatives. In
- other words, when PCRE_PARTIAL_HARD is set, a partial match is consid-
+ If PCRE_PARTIAL_HARD is set, it overrides PCRE_PARTIAL_SOFT. In this
+ case, if a partial match is found, pcre_exec() immediately returns
+ PCRE_ERROR_PARTIAL, without considering any other alternatives. In
+ other words, when PCRE_PARTIAL_HARD is set, a partial match is consid-
ered to be more important that an alternative complete match.
- In both cases, the portion of the string that was inspected when the
+ In both cases, the portion of the string that was inspected when the
partial match was found is set as the first matching string. There is a
- more detailed discussion of partial and multi-segment matching, with
+ more detailed discussion of partial and multi-segment matching, with
examples, in the pcrepartial documentation.
The string to be matched by pcre_exec()
- The subject string is passed to pcre_exec() as a pointer in subject, a
- length in length, and a starting offset in startoffset. The units for
- length and startoffset are bytes for the 8-bit library, 16-bit data
- items for the 16-bit library, and 32-bit data items for the 32-bit
+ The subject string is passed to pcre_exec() as a pointer in subject, a
+ length in length, and a starting offset in startoffset. The units for
+ length and startoffset are bytes for the 8-bit library, 16-bit data
+ items for the 16-bit library, and 32-bit data items for the 32-bit
library.
- If startoffset is negative or greater than the length of the subject,
- pcre_exec() returns PCRE_ERROR_BADOFFSET. When the starting offset is
- zero, the search for a match starts at the beginning of the subject,
- and this is by far the most common case. In UTF-8 or UTF-16 mode, the
- offset must point to the start of a character, or the end of the sub-
- ject (in UTF-32 mode, one data unit equals one character, so all off-
- sets are valid). Unlike the pattern string, the subject may contain
+ If startoffset is negative or greater than the length of the subject,
+ pcre_exec() returns PCRE_ERROR_BADOFFSET. When the starting offset is
+ zero, the search for a match starts at the beginning of the subject,
+ and this is by far the most common case. In UTF-8 or UTF-16 mode, the
+ offset must point to the start of a character, or the end of the sub-
+ ject (in UTF-32 mode, one data unit equals one character, so all off-
+ sets are valid). Unlike the pattern string, the subject may contain
binary zeroes.
- A non-zero starting offset is useful when searching for another match
- in the same subject by calling pcre_exec() again after a previous suc-
- cess. Setting startoffset differs from just passing over a shortened
- string and setting PCRE_NOTBOL in the case of a pattern that begins
+ A non-zero starting offset is useful when searching for another match
+ in the same subject by calling pcre_exec() again after a previous suc-
+ cess. Setting startoffset differs from just passing over a shortened
+ string and setting PCRE_NOTBOL in the case of a pattern that begins
with any kind of lookbehind. For example, consider the pattern
\Biss\B
- which finds occurrences of "iss" in the middle of words. (\B matches
- only if the current position in the subject is not a word boundary.)
- When applied to the string "Mississipi" the first call to pcre_exec()
- finds the first occurrence. If pcre_exec() is called again with just
- the remainder of the subject, namely "issipi", it does not match,
+ which finds occurrences of "iss" in the middle of words. (\B matches
+ only if the current position in the subject is not a word boundary.)
+ When applied to the string "Mississipi" the first call to pcre_exec()
+ finds the first occurrence. If pcre_exec() is called again with just
+ the remainder of the subject, namely "issipi", it does not match,
because \B is always false at the start of the subject, which is deemed
- to be a word boundary. However, if pcre_exec() is passed the entire
+ to be a word boundary. However, if pcre_exec() is passed the entire
string again, but with startoffset set to 4, it finds the second occur-
- rence of "iss" because it is able to look behind the starting point to
+ rence of "iss" because it is able to look behind the starting point to
discover that it is preceded by a letter.
- Finding all the matches in a subject is tricky when the pattern can
+ Finding all the matches in a subject is tricky when the pattern can
match an empty string. It is possible to emulate Perl's /g behaviour by
- first trying the match again at the same offset, with the
- PCRE_NOTEMPTY_ATSTART and PCRE_ANCHORED options, and then if that
- fails, advancing the starting offset and trying an ordinary match
+ first trying the match again at the same offset, with the
+ PCRE_NOTEMPTY_ATSTART and PCRE_ANCHORED options, and then if that
+ fails, advancing the starting offset and trying an ordinary match
again. There is some code that demonstrates how to do this in the pcre-
demo sample program. In the most general case, you have to check to see
- if the newline convention recognizes CRLF as a newline, and if so, and
+ if the newline convention recognizes CRLF as a newline, and if so, and
the current character is CR followed by LF, advance the starting offset
by two characters instead of one.
- If a non-zero starting offset is passed when the pattern is anchored,
+ If a non-zero starting offset is passed when the pattern is anchored,
one attempt to match at the given offset is made. This can only succeed
- if the pattern does not require the match to be at the start of the
+ if the pattern does not require the match to be at the start of the
subject.
How pcre_exec() returns captured substrings
- In general, a pattern matches a certain portion of the subject, and in
- addition, further substrings from the subject may be picked out by
- parts of the pattern. Following the usage in Jeffrey Friedl's book,
- this is called "capturing" in what follows, and the phrase "capturing
- subpattern" is used for a fragment of a pattern that picks out a sub-
- string. PCRE supports several other kinds of parenthesized subpattern
+ In general, a pattern matches a certain portion of the subject, and in
+ addition, further substrings from the subject may be picked out by
+ parts of the pattern. Following the usage in Jeffrey Friedl's book,
+ this is called "capturing" in what follows, and the phrase "capturing
+ subpattern" is used for a fragment of a pattern that picks out a sub-
+ string. PCRE supports several other kinds of parenthesized subpattern
that do not cause substrings to be captured.
Captured substrings are returned to the caller via a vector of integers
- whose address is passed in ovector. The number of elements in the vec-
- tor is passed in ovecsize, which must be a non-negative number. Note:
+ whose address is passed in ovector. The number of elements in the vec-
+ tor is passed in ovecsize, which must be a non-negative number. Note:
this argument is NOT the size of ovector in bytes.
- The first two-thirds of the vector is used to pass back captured sub-
- strings, each substring using a pair of integers. The remaining third
- of the vector is used as workspace by pcre_exec() while matching cap-
- turing subpatterns, and is not available for passing back information.
- The number passed in ovecsize should always be a multiple of three. If
+ The first two-thirds of the vector is used to pass back captured sub-
+ strings, each substring using a pair of integers. The remaining third
+ of the vector is used as workspace by pcre_exec() while matching cap-
+ turing subpatterns, and is not available for passing back information.
+ The number passed in ovecsize should always be a multiple of three. If
it is not, it is rounded down.
- When a match is successful, information about captured substrings is
- returned in pairs of integers, starting at the beginning of ovector,
- and continuing up to two-thirds of its length at the most. The first
- element of each pair is set to the offset of the first character in a
- substring, and the second is set to the offset of the first character
- after the end of a substring. These values are always data unit off-
- sets, even in UTF mode. They are byte offsets in the 8-bit library,
- 16-bit data item offsets in the 16-bit library, and 32-bit data item
+ When a match is successful, information about captured substrings is
+ returned in pairs of integers, starting at the beginning of ovector,
+ and continuing up to two-thirds of its length at the most. The first
+ element of each pair is set to the offset of the first character in a
+ substring, and the second is set to the offset of the first character
+ after the end of a substring. These values are always data unit off-
+ sets, even in UTF mode. They are byte offsets in the 8-bit library,
+ 16-bit data item offsets in the 16-bit library, and 32-bit data item
offsets in the 32-bit library. Note: they are not character counts.
- The first pair of integers, ovector[0] and ovector[1], identify the
- portion of the subject string matched by the entire pattern. The next
- pair is used for the first capturing subpattern, and so on. The value
+ The first pair of integers, ovector[0] and ovector[1], identify the
+ portion of the subject string matched by the entire pattern. The next
+ pair is used for the first capturing subpattern, and so on. The value
returned by pcre_exec() is one more than the highest numbered pair that
- has been set. For example, if two substrings have been captured, the
- returned value is 3. If there are no capturing subpatterns, the return
+ has been set. For example, if two substrings have been captured, the
+ returned value is 3. If there are no capturing subpatterns, the return
value from a successful match is 1, indicating that just the first pair
of offsets has been set.
If a capturing subpattern is matched repeatedly, it is the last portion
of the string that it matched that is returned.
- If the vector is too small to hold all the captured substring offsets,
+ If the vector is too small to hold all the captured substring offsets,
it is used as far as possible (up to two-thirds of its length), and the
- function returns a value of zero. If neither the actual string matched
- nor any captured substrings are of interest, pcre_exec() may be called
- with ovector passed as NULL and ovecsize as zero. However, if the pat-
- tern contains back references and the ovector is not big enough to
- remember the related substrings, PCRE has to get additional memory for
- use during matching. Thus it is usually advisable to supply an ovector
+ function returns a value of zero. If neither the actual string matched
+ nor any captured substrings are of interest, pcre_exec() may be called
+ with ovector passed as NULL and ovecsize as zero. However, if the pat-
+ tern contains back references and the ovector is not big enough to
+ remember the related substrings, PCRE has to get additional memory for
+ use during matching. Thus it is usually advisable to supply an ovector
of reasonable size.
- There are some cases where zero is returned (indicating vector over-
- flow) when in fact the vector is exactly the right size for the final
+ There are some cases where zero is returned (indicating vector over-
+ flow) when in fact the vector is exactly the right size for the final
match. For example, consider the pattern
(a)(?:(b)c|bd)
- If a vector of 6 elements (allowing for only 1 captured substring) is
+ If a vector of 6 elements (allowing for only 1 captured substring) is
given with subject string "abd", pcre_exec() will try to set the second
captured string, thereby recording a vector overflow, before failing to
- match "c" and backing up to try the second alternative. The zero
- return, however, does correctly indicate that the maximum number of
+ match "c" and backing up to try the second alternative. The zero
+ return, however, does correctly indicate that the maximum number of
slots (namely 2) have been filled. In similar cases where there is tem-
- porary overflow, but the final number of used slots is actually less
+ porary overflow, but the final number of used slots is actually less
than the maximum, a non-zero value is returned.
The pcre_fullinfo() function can be used to find out how many capturing
- subpatterns there are in a compiled pattern. The smallest size for
- ovector that will allow for n captured substrings, in addition to the
+ subpatterns there are in a compiled pattern. The smallest size for
+ ovector that will allow for n captured substrings, in addition to the
offsets of the substring matched by the whole pattern, is (n+1)*3.
- It is possible for capturing subpattern number n+1 to match some part
+ It is possible for capturing subpattern number n+1 to match some part
of the subject when subpattern n has not been used at all. For example,
- if the string "abc" is matched against the pattern (a|(z))(bc) the
+ if the string "abc" is matched against the pattern (a|(z))(bc) the
return from the function is 4, and subpatterns 1 and 3 are matched, but
- 2 is not. When this happens, both values in the offset pairs corre-
+ 2 is not. When this happens, both values in the offset pairs corre-
sponding to unused subpatterns are set to -1.
- Offset values that correspond to unused subpatterns at the end of the
- expression are also set to -1. For example, if the string "abc" is
- matched against the pattern (abc)(x(yz)?)? subpatterns 2 and 3 are not
- matched. The return from the function is 2, because the highest used
- capturing subpattern number is 1, and the offsets for for the second
- and third capturing subpatterns (assuming the vector is large enough,
+ Offset values that correspond to unused subpatterns at the end of the
+ expression are also set to -1. For example, if the string "abc" is
+ matched against the pattern (abc)(x(yz)?)? subpatterns 2 and 3 are not
+ matched. The return from the function is 2, because the highest used
+ capturing subpattern number is 1, and the offsets for for the second
+ and third capturing subpatterns (assuming the vector is large enough,
of course) are set to -1.
- Note: Elements in the first two-thirds of ovector that do not corre-
- spond to capturing parentheses in the pattern are never changed. That
- is, if a pattern contains n capturing parentheses, no more than ovec-
- tor[0] to ovector[2n+1] are set by pcre_exec(). The other elements (in
+ Note: Elements in the first two-thirds of ovector that do not corre-
+ spond to capturing parentheses in the pattern are never changed. That
+ is, if a pattern contains n capturing parentheses, no more than ovec-
+ tor[0] to ovector[2n+1] are set by pcre_exec(). The other elements (in
the first two-thirds) retain whatever values they previously had.
- Some convenience functions are provided for extracting the captured
+ Some convenience functions are provided for extracting the captured
substrings as separate strings. These are described below.
Error return values from pcre_exec()
- If pcre_exec() fails, it returns a negative number. The following are
+ If pcre_exec() fails, it returns a negative number. The following are
defined in the header file:
PCRE_ERROR_NOMATCH (-1)
PCRE_ERROR_NULL (-2)
- Either code or subject was passed as NULL, or ovector was NULL and
+ Either code or subject was passed as NULL, or ovector was NULL and
ovecsize was not zero.
PCRE_ERROR_BADOPTION (-3)
PCRE_ERROR_BADMAGIC (-4)
- PCRE stores a 4-byte "magic number" at the start of the compiled code,
+ PCRE stores a 4-byte "magic number" at the start of the compiled code,
to catch the case when it is passed a junk pointer and to detect when a
pattern that was compiled in an environment of one endianness is run in
- an environment with the other endianness. This is the error that PCRE
+ an environment with the other endianness. This is the error that PCRE
gives when the magic number is not present.
PCRE_ERROR_UNKNOWN_OPCODE (-5)
While running the pattern match, an unknown item was encountered in the
- compiled pattern. This error could be caused by a bug in PCRE or by
+ compiled pattern. This error could be caused by a bug in PCRE or by
overwriting of the compiled pattern.
PCRE_ERROR_NOMEMORY (-6)
- If a pattern contains back references, but the ovector that is passed
+ If a pattern contains back references, but the ovector that is passed
to pcre_exec() is not big enough to remember the referenced substrings,
- PCRE gets a block of memory at the start of matching to use for this
- purpose. If the call via pcre_malloc() fails, this error is given. The
+ PCRE gets a block of memory at the start of matching to use for this
+ purpose. If the call via pcre_malloc() fails, this error is given. The
memory is automatically freed at the end of matching.
- This error is also given if pcre_stack_malloc() fails in pcre_exec().
- This can happen only when PCRE has been compiled with --disable-stack-
+ This error is also given if pcre_stack_malloc() fails in pcre_exec().
+ This can happen only when PCRE has been compiled with --disable-stack-
for-recursion.
PCRE_ERROR_NOSUBSTRING (-7)
- This error is used by the pcre_copy_substring(), pcre_get_substring(),
+ This error is used by the pcre_copy_substring(), pcre_get_substring(),
and pcre_get_substring_list() functions (see below). It is never
returned by pcre_exec().
PCRE_ERROR_MATCHLIMIT (-8)
- The backtracking limit, as specified by the match_limit field in a
- pcre_extra structure (or defaulted) was reached. See the description
+ The backtracking limit, as specified by the match_limit field in a
+ pcre_extra structure (or defaulted) was reached. See the description
above.
PCRE_ERROR_CALLOUT (-9)
This error is never generated by pcre_exec() itself. It is provided for
- use by callout functions that want to yield a distinctive error code.
+ use by callout functions that want to yield a distinctive error code.
See the pcrecallout documentation for details.
PCRE_ERROR_BADUTF8 (-10)
- A string that contains an invalid UTF-8 byte sequence was passed as a
- subject, and the PCRE_NO_UTF8_CHECK option was not set. If the size of
- the output vector (ovecsize) is at least 2, the byte offset to the
- start of the the invalid UTF-8 character is placed in the first ele-
- ment, and a reason code is placed in the second element. The reason
+ A string that contains an invalid UTF-8 byte sequence was passed as a
+ subject, and the PCRE_NO_UTF8_CHECK option was not set. If the size of
+ the output vector (ovecsize) is at least 2, the byte offset to the
+ start of the the invalid UTF-8 character is placed in the first ele-
+ ment, and a reason code is placed in the second element. The reason
codes are listed in the following section. For backward compatibility,
- if PCRE_PARTIAL_HARD is set and the problem is a truncated UTF-8 char-
- acter at the end of the subject (reason codes 1 to 5),
+ if PCRE_PARTIAL_HARD is set and the problem is a truncated UTF-8 char-
+ acter at the end of the subject (reason codes 1 to 5),
PCRE_ERROR_SHORTUTF8 is returned instead of PCRE_ERROR_BADUTF8.
PCRE_ERROR_BADUTF8_OFFSET (-11)
- The UTF-8 byte sequence that was passed as a subject was checked and
- found to be valid (the PCRE_NO_UTF8_CHECK option was not set), but the
- value of startoffset did not point to the beginning of a UTF-8 charac-
+ The UTF-8 byte sequence that was passed as a subject was checked and
+ found to be valid (the PCRE_NO_UTF8_CHECK option was not set), but the
+ value of startoffset did not point to the beginning of a UTF-8 charac-
ter or the end of the subject.
PCRE_ERROR_PARTIAL (-12)
- The subject string did not match, but it did match partially. See the
+ The subject string did not match, but it did match partially. See the
pcrepartial documentation for details of partial matching.
PCRE_ERROR_BADPARTIAL (-13)
- This code is no longer in use. It was formerly returned when the
- PCRE_PARTIAL option was used with a compiled pattern containing items
- that were not supported for partial matching. From release 8.00
+ This code is no longer in use. It was formerly returned when the
+ PCRE_PARTIAL option was used with a compiled pattern containing items
+ that were not supported for partial matching. From release 8.00
onwards, there are no restrictions on partial matching.
PCRE_ERROR_INTERNAL (-14)
- An unexpected internal error has occurred. This error could be caused
+ An unexpected internal error has occurred. This error could be caused
by a bug in PCRE or by overwriting of the compiled pattern.
PCRE_ERROR_BADCOUNT (-15)
PCRE_ERROR_RECURSIONLIMIT (-21)
The internal recursion limit, as specified by the match_limit_recursion
- field in a pcre_extra structure (or defaulted) was reached. See the
+ field in a pcre_extra structure (or defaulted) was reached. See the
description above.
PCRE_ERROR_BADNEWLINE (-23)
PCRE_ERROR_SHORTUTF8 (-25)
- This error is returned instead of PCRE_ERROR_BADUTF8 when the subject
- string ends with a truncated UTF-8 character and the PCRE_PARTIAL_HARD
- option is set. Information about the failure is returned as for
- PCRE_ERROR_BADUTF8. It is in fact sufficient to detect this case, but
- this special error code for PCRE_PARTIAL_HARD precedes the implementa-
- tion of returned information; it is retained for backwards compatibil-
+ This error is returned instead of PCRE_ERROR_BADUTF8 when the subject
+ string ends with a truncated UTF-8 character and the PCRE_PARTIAL_HARD
+ option is set. Information about the failure is returned as for
+ PCRE_ERROR_BADUTF8. It is in fact sufficient to detect this case, but
+ this special error code for PCRE_PARTIAL_HARD precedes the implementa-
+ tion of returned information; it is retained for backwards compatibil-
ity.
PCRE_ERROR_RECURSELOOP (-26)
This error is returned when pcre_exec() detects a recursion loop within
- the pattern. Specifically, it means that either the whole pattern or a
- subpattern has been called recursively for the second time at the same
+ the pattern. Specifically, it means that either the whole pattern or a
+ subpattern has been called recursively for the second time at the same
position in the subject string. Some simple patterns that might do this
- are detected and faulted at compile time, but more complicated cases,
+ are detected and faulted at compile time, but more complicated cases,
in particular mutual recursions between two different subpatterns, can-
not be detected until run time.
PCRE_ERROR_JIT_STACKLIMIT (-27)
- This error is returned when a pattern that was successfully studied
- using a JIT compile option is being matched, but the memory available
- for the just-in-time processing stack is not large enough. See the
+ This error is returned when a pattern that was successfully studied
+ using a JIT compile option is being matched, but the memory available
+ for the just-in-time processing stack is not large enough. See the
pcrejit documentation for more details.
PCRE_ERROR_BADMODE (-28)
PCRE_ERROR_BADENDIANNESS (-29)
- This error is given if a pattern that was compiled and saved is
- reloaded on a host with different endianness. The utility function
+ This error is given if a pattern that was compiled and saved is
+ reloaded on a host with different endianness. The utility function
pcre_pattern_to_host_byte_order() can be used to convert such a pattern
so that it runs on the new host.
PCRE_ERROR_JIT_BADOPTION
- This error is returned when a pattern that was successfully studied
- using a JIT compile option is being matched, but the matching mode
- (partial or complete match) does not correspond to any JIT compilation
- mode. When the JIT fast path function is used, this error may be also
- given for invalid options. See the pcrejit documentation for more
+ This error is returned when a pattern that was successfully studied
+ using a JIT compile option is being matched, but the matching mode
+ (partial or complete match) does not correspond to any JIT compilation
+ mode. When the JIT fast path function is used, this error may be also
+ given for invalid options. See the pcrejit documentation for more
details.
PCRE_ERROR_BADLENGTH (-32)
- This error is given if pcre_exec() is called with a negative value for
+ This error is given if pcre_exec() is called with a negative value for
the length argument.
Error numbers -16 to -20, -22, and 30 are not used by pcre_exec().
Reason codes for invalid UTF-8 strings
- This section applies only to the 8-bit library. The corresponding
- information for the 16-bit and 32-bit libraries is given in the pcre16
+ This section applies only to the 8-bit library. The corresponding
+ information for the 16-bit and 32-bit libraries is given in the pcre16
and pcre32 pages.
When pcre_exec() returns either PCRE_ERROR_BADUTF8 or PCRE_ERROR_SHORT-
- UTF8, and the size of the output vector (ovecsize) is at least 2, the
- offset of the start of the invalid UTF-8 character is placed in the
+ UTF8, and the size of the output vector (ovecsize) is at least 2, the
+ offset of the start of the invalid UTF-8 character is placed in the
first output vector element (ovector[0]) and a reason code is placed in
- the second element (ovector[1]). The reason codes are given names in
+ the second element (ovector[1]). The reason codes are given names in
the pcre.h header file:
PCRE_UTF8_ERR1
PCRE_UTF8_ERR4
PCRE_UTF8_ERR5
- The string ends with a truncated UTF-8 character; the code specifies
- how many bytes are missing (1 to 5). Although RFC 3629 restricts UTF-8
- characters to be no longer than 4 bytes, the encoding scheme (origi-
- nally defined by RFC 2279) allows for up to 6 bytes, and this is
+ The string ends with a truncated UTF-8 character; the code specifies
+ how many bytes are missing (1 to 5). Although RFC 3629 restricts UTF-8
+ characters to be no longer than 4 bytes, the encoding scheme (origi-
+ nally defined by RFC 2279) allows for up to 6 bytes, and this is
checked first; hence the possibility of 4 or 5 missing bytes.
PCRE_UTF8_ERR6
PCRE_UTF8_ERR10
The two most significant bits of the 2nd, 3rd, 4th, 5th, or 6th byte of
- the character do not have the binary value 0b10 (that is, either the
+ the character do not have the binary value 0b10 (that is, either the
most significant bit is 0, or the next bit is 1).
PCRE_UTF8_ERR11
PCRE_UTF8_ERR12
- A character that is valid by the RFC 2279 rules is either 5 or 6 bytes
+ A character that is valid by the RFC 2279 rules is either 5 or 6 bytes
long; these code points are excluded by RFC 3629.
PCRE_UTF8_ERR13
- A 4-byte character has a value greater than 0x10fff; these code points
+ A 4-byte character has a value greater than 0x10fff; these code points
are excluded by RFC 3629.
PCRE_UTF8_ERR14
- A 3-byte character has a value in the range 0xd800 to 0xdfff; this
- range of code points are reserved by RFC 3629 for use with UTF-16, and
+ A 3-byte character has a value in the range 0xd800 to 0xdfff; this
+ range of code points are reserved by RFC 3629 for use with UTF-16, and
so are excluded from UTF-8.
PCRE_UTF8_ERR15
PCRE_UTF8_ERR18
PCRE_UTF8_ERR19
- A 2-, 3-, 4-, 5-, or 6-byte character is "overlong", that is, it codes
- for a value that can be represented by fewer bytes, which is invalid.
- For example, the two bytes 0xc0, 0xae give the value 0x2e, whose cor-
+ A 2-, 3-, 4-, 5-, or 6-byte character is "overlong", that is, it codes
+ for a value that can be represented by fewer bytes, which is invalid.
+ For example, the two bytes 0xc0, 0xae give the value 0x2e, whose cor-
rect coding uses just one byte.
PCRE_UTF8_ERR20
The two most significant bits of the first byte of a character have the
- binary value 0b10 (that is, the most significant bit is 1 and the sec-
- ond is 0). Such a byte can only validly occur as the second or subse-
+ binary value 0b10 (that is, the most significant bit is 1 and the sec-
+ ond is 0). Such a byte can only validly occur as the second or subse-
quent byte of a multi-byte character.
PCRE_UTF8_ERR21
- The first byte of a character has the value 0xfe or 0xff. These values
+ The first byte of a character has the value 0xfe or 0xff. These values
can never occur in a valid UTF-8 string.
PCRE_UTF8_ERR22
- This error code was formerly used when the presence of a so-called
- "non-character" caused an error. Unicode corrigendum #9 makes it clear
- that such characters should not cause a string to be rejected, and so
+ This error code was formerly used when the presence of a so-called
+ "non-character" caused an error. Unicode corrigendum #9 makes it clear
+ that such characters should not cause a string to be rejected, and so
this code is no longer in use and is never returned.
int pcre_get_substring_list(const char *subject,
int *ovector, int stringcount, const char ***listptr);
- Captured substrings can be accessed directly by using the offsets
- returned by pcre_exec() in ovector. For convenience, the functions
+ Captured substrings can be accessed directly by using the offsets
+ returned by pcre_exec() in ovector. For convenience, the functions
pcre_copy_substring(), pcre_get_substring(), and pcre_get_sub-
- string_list() are provided for extracting captured substrings as new,
- separate, zero-terminated strings. These functions identify substrings
- by number. The next section describes functions for extracting named
+ string_list() are provided for extracting captured substrings as new,
+ separate, zero-terminated strings. These functions identify substrings
+ by number. The next section describes functions for extracting named
substrings.
- A substring that contains a binary zero is correctly extracted and has
- a further zero added on the end, but the result is not, of course, a C
- string. However, you can process such a string by referring to the
- length that is returned by pcre_copy_substring() and pcre_get_sub-
+ A substring that contains a binary zero is correctly extracted and has
+ a further zero added on the end, but the result is not, of course, a C
+ string. However, you can process such a string by referring to the
+ length that is returned by pcre_copy_substring() and pcre_get_sub-
string(). Unfortunately, the interface to pcre_get_substring_list() is
- not adequate for handling strings containing binary zeros, because the
+ not adequate for handling strings containing binary zeros, because the
end of the final string is not independently indicated.
- The first three arguments are the same for all three of these func-
- tions: subject is the subject string that has just been successfully
+ The first three arguments are the same for all three of these func-
+ tions: subject is the subject string that has just been successfully
matched, ovector is a pointer to the vector of integer offsets that was
passed to pcre_exec(), and stringcount is the number of substrings that
- were captured by the match, including the substring that matched the
+ were captured by the match, including the substring that matched the
entire regular expression. This is the value returned by pcre_exec() if
- it is greater than zero. If pcre_exec() returned zero, indicating that
- it ran out of space in ovector, the value passed as stringcount should
+ it is greater than zero. If pcre_exec() returned zero, indicating that
+ it ran out of space in ovector, the value passed as stringcount should
be the number of elements in the vector divided by three.
- The functions pcre_copy_substring() and pcre_get_substring() extract a
- single substring, whose number is given as stringnumber. A value of
- zero extracts the substring that matched the entire pattern, whereas
- higher values extract the captured substrings. For pcre_copy_sub-
- string(), the string is placed in buffer, whose length is given by
- buffersize, while for pcre_get_substring() a new block of memory is
- obtained via pcre_malloc, and its address is returned via stringptr.
- The yield of the function is the length of the string, not including
+ The functions pcre_copy_substring() and pcre_get_substring() extract a
+ single substring, whose number is given as stringnumber. A value of
+ zero extracts the substring that matched the entire pattern, whereas
+ higher values extract the captured substrings. For pcre_copy_sub-
+ string(), the string is placed in buffer, whose length is given by
+ buffersize, while for pcre_get_substring() a new block of memory is
+ obtained via pcre_malloc, and its address is returned via stringptr.
+ The yield of the function is the length of the string, not including
the terminating zero, or one of these error codes:
PCRE_ERROR_NOMEMORY (-6)
- The buffer was too small for pcre_copy_substring(), or the attempt to
+ The buffer was too small for pcre_copy_substring(), or the attempt to
get memory failed for pcre_get_substring().
PCRE_ERROR_NOSUBSTRING (-7)
There is no substring whose number is stringnumber.
- The pcre_get_substring_list() function extracts all available sub-
- strings and builds a list of pointers to them. All this is done in a
+ The pcre_get_substring_list() function extracts all available sub-
+ strings and builds a list of pointers to them. All this is done in a
single block of memory that is obtained via pcre_malloc. The address of
- the memory block is returned via listptr, which is also the start of
- the list of string pointers. The end of the list is marked by a NULL
- pointer. The yield of the function is zero if all went well, or the
+ the memory block is returned via listptr, which is also the start of
+ the list of string pointers. The end of the list is marked by a NULL
+ pointer. The yield of the function is zero if all went well, or the
error code
PCRE_ERROR_NOMEMORY (-6)
if the attempt to get the memory block failed.
- When any of these functions encounter a substring that is unset, which
- can happen when capturing subpattern number n+1 matches some part of
- the subject, but subpattern n has not been used at all, they return an
+ When any of these functions encounter a substring that is unset, which
+ can happen when capturing subpattern number n+1 matches some part of
+ the subject, but subpattern n has not been used at all, they return an
empty string. This can be distinguished from a genuine zero-length sub-
- string by inspecting the appropriate offset in ovector, which is nega-
+ string by inspecting the appropriate offset in ovector, which is nega-
tive for unset substrings.
- The two convenience functions pcre_free_substring() and pcre_free_sub-
- string_list() can be used to free the memory returned by a previous
+ The two convenience functions pcre_free_substring() and pcre_free_sub-
+ string_list() can be used to free the memory returned by a previous
call of pcre_get_substring() or pcre_get_substring_list(), respec-
- tively. They do nothing more than call the function pointed to by
- pcre_free, which of course could be called directly from a C program.
- However, PCRE is used in some situations where it is linked via a spe-
- cial interface to another programming language that cannot use
- pcre_free directly; it is for these cases that the functions are pro-
+ tively. They do nothing more than call the function pointed to by
+ pcre_free, which of course could be called directly from a C program.
+ However, PCRE is used in some situations where it is linked via a spe-
+ cial interface to another programming language that cannot use
+ pcre_free directly; it is for these cases that the functions are pro-
vided.
int stringcount, const char *stringname,
const char **stringptr);
- To extract a substring by name, you first have to find associated num-
+ To extract a substring by name, you first have to find associated num-
ber. For example, for this pattern
(a+)b(?<xxx>\d+)...
be unique (PCRE_DUPNAMES was not set), you can find the number from the
name by calling pcre_get_stringnumber(). The first argument is the com-
piled pattern, and the second is the name. The yield of the function is
- the subpattern number, or PCRE_ERROR_NOSUBSTRING (-7) if there is no
+ the subpattern number, or PCRE_ERROR_NOSUBSTRING (-7) if there is no
subpattern of that name.
Given the number, you can extract the substring directly, or use one of
the functions described in the previous section. For convenience, there
are also two functions that do the whole job.
- Most of the arguments of pcre_copy_named_substring() and
- pcre_get_named_substring() are the same as those for the similarly
- named functions that extract by number. As these are described in the
- previous section, they are not re-described here. There are just two
+ Most of the arguments of pcre_copy_named_substring() and
+ pcre_get_named_substring() are the same as those for the similarly
+ named functions that extract by number. As these are described in the
+ previous section, they are not re-described here. There are just two
differences:
- First, instead of a substring number, a substring name is given. Sec-
+ First, instead of a substring number, a substring name is given. Sec-
ond, there is an extra argument, given at the start, which is a pointer
- to the compiled pattern. This is needed in order to gain access to the
+ to the compiled pattern. This is needed in order to gain access to the
name-to-number translation table.
- These functions call pcre_get_stringnumber(), and if it succeeds, they
- then call pcre_copy_substring() or pcre_get_substring(), as appropri-
- ate. NOTE: If PCRE_DUPNAMES is set and there are duplicate names, the
+ These functions call pcre_get_stringnumber(), and if it succeeds, they
+ then call pcre_copy_substring() or pcre_get_substring(), as appropri-
+ ate. NOTE: If PCRE_DUPNAMES is set and there are duplicate names, the
behaviour may not be what you want (see the next section).
Warning: If the pattern uses the (?| feature to set up multiple subpat-
- terns with the same number, as described in the section on duplicate
- subpattern numbers in the pcrepattern page, you cannot use names to
- distinguish the different subpatterns, because names are not included
- in the compiled code. The matching process uses only numbers. For this
- reason, the use of different names for subpatterns of the same number
+ terns with the same number, as described in the section on duplicate
+ subpattern numbers in the pcrepattern page, you cannot use names to
+ distinguish the different subpatterns, because names are not included
+ in the compiled code. The matching process uses only numbers. For this
+ reason, the use of different names for subpatterns of the same number
causes an error at compile time.
int pcre_get_stringtable_entries(const pcre *code,
const char *name, char **first, char **last);
- When a pattern is compiled with the PCRE_DUPNAMES option, names for
- subpatterns are not required to be unique. (Duplicate names are always
- allowed for subpatterns with the same number, created by using the (?|
- feature. Indeed, if such subpatterns are named, they are required to
+ When a pattern is compiled with the PCRE_DUPNAMES option, names for
+ subpatterns are not required to be unique. (Duplicate names are always
+ allowed for subpatterns with the same number, created by using the (?|
+ feature. Indeed, if such subpatterns are named, they are required to
use the same names.)
Normally, patterns with duplicate names are such that in any one match,
- only one of the named subpatterns participates. An example is shown in
+ only one of the named subpatterns participates. An example is shown in
the pcrepattern documentation.
- When duplicates are present, pcre_copy_named_substring() and
- pcre_get_named_substring() return the first substring corresponding to
- the given name that is set. If none are set, PCRE_ERROR_NOSUBSTRING
- (-7) is returned; no data is returned. The pcre_get_stringnumber()
- function returns one of the numbers that are associated with the name,
+ When duplicates are present, pcre_copy_named_substring() and
+ pcre_get_named_substring() return the first substring corresponding to
+ the given name that is set. If none are set, PCRE_ERROR_NOSUBSTRING
+ (-7) is returned; no data is returned. The pcre_get_stringnumber()
+ function returns one of the numbers that are associated with the name,
but it is not defined which it is.
- If you want to get full details of all captured substrings for a given
- name, you must use the pcre_get_stringtable_entries() function. The
+ If you want to get full details of all captured substrings for a given
+ name, you must use the pcre_get_stringtable_entries() function. The
first argument is the compiled pattern, and the second is the name. The
- third and fourth are pointers to variables which are updated by the
+ third and fourth are pointers to variables which are updated by the
function. After it has run, they point to the first and last entries in
- the name-to-number table for the given name. The function itself
- returns the length of each entry, or PCRE_ERROR_NOSUBSTRING (-7) if
- there are none. The format of the table is described above in the sec-
- tion entitled Information about a pattern above. Given all the rele-
- vant entries for the name, you can extract each of their numbers, and
+ the name-to-number table for the given name. The function itself
+ returns the length of each entry, or PCRE_ERROR_NOSUBSTRING (-7) if
+ there are none. The format of the table is described above in the sec-
+ tion entitled Information about a pattern above. Given all the rele-
+ vant entries for the name, you can extract each of their numbers, and
hence the captured data, if any.
FINDING ALL POSSIBLE MATCHES
- The traditional matching function uses a similar algorithm to Perl,
+ The traditional matching function uses a similar algorithm to Perl,
which stops when it finds the first match, starting at a given point in
- the subject. If you want to find all possible matches, or the longest
- possible match, consider using the alternative matching function (see
- below) instead. If you cannot use the alternative function, but still
- need to find all possible matches, you can kludge it up by making use
+ the subject. If you want to find all possible matches, or the longest
+ possible match, consider using the alternative matching function (see
+ below) instead. If you cannot use the alternative function, but still
+ need to find all possible matches, you can kludge it up by making use
of the callout facility, which is described in the pcrecallout documen-
tation.
What you have to do is to insert a callout right at the end of the pat-
- tern. When your callout function is called, extract and save the cur-
- rent matched substring. Then return 1, which forces pcre_exec() to
- backtrack and try other alternatives. Ultimately, when it runs out of
+ tern. When your callout function is called, extract and save the cur-
+ rent matched substring. Then return 1, which forces pcre_exec() to
+ backtrack and try other alternatives. Ultimately, when it runs out of
matches, pcre_exec() will yield PCRE_ERROR_NOMATCH.
OBTAINING AN ESTIMATE OF STACK USAGE
- Matching certain patterns using pcre_exec() can use a lot of process
- stack, which in certain environments can be rather limited in size.
- Some users find it helpful to have an estimate of the amount of stack
- that is used by pcre_exec(), to help them set recursion limits, as
- described in the pcrestack documentation. The estimate that is output
+ Matching certain patterns using pcre_exec() can use a lot of process
+ stack, which in certain environments can be rather limited in size.
+ Some users find it helpful to have an estimate of the amount of stack
+ that is used by pcre_exec(), to help them set recursion limits, as
+ described in the pcrestack documentation. The estimate that is output
by pcretest when called with the -m and -C options is obtained by call-
- ing pcre_exec with the values NULL, NULL, NULL, -999, and -999 for its
+ ing pcre_exec with the values NULL, NULL, NULL, -999, and -999 for its
first five arguments.
- Normally, if its first argument is NULL, pcre_exec() immediately
- returns the negative error code PCRE_ERROR_NULL, but with this special
- combination of arguments, it returns instead a negative number whose
- absolute value is the approximate stack frame size in bytes. (A nega-
- tive number is used so that it is clear that no match has happened.)
- The value is approximate because in some cases, recursive calls to
+ Normally, if its first argument is NULL, pcre_exec() immediately
+ returns the negative error code PCRE_ERROR_NULL, but with this special
+ combination of arguments, it returns instead a negative number whose
+ absolute value is the approximate stack frame size in bytes. (A nega-
+ tive number is used so that it is clear that no match has happened.)
+ The value is approximate because in some cases, recursive calls to
pcre_exec() occur when there are one or two additional variables on the
stack.
- If PCRE has been compiled to use the heap instead of the stack for
- recursion, the value returned is the size of each block that is
+ If PCRE has been compiled to use the heap instead of the stack for
+ recursion, the value returned is the size of each block that is
obtained from the heap.
int options, int *ovector, int ovecsize,
int *workspace, int wscount);
- The function pcre_dfa_exec() is called to match a subject string
- against a compiled pattern, using a matching algorithm that scans the
- subject string just once, and does not backtrack. This has different
- characteristics to the normal algorithm, and is not compatible with
- Perl. Some of the features of PCRE patterns are not supported. Never-
- theless, there are times when this kind of matching can be useful. For
- a discussion of the two matching algorithms, and a list of features
- that pcre_dfa_exec() does not support, see the pcrematching documenta-
+ The function pcre_dfa_exec() is called to match a subject string
+ against a compiled pattern, using a matching algorithm that scans the
+ subject string just once, and does not backtrack. This has different
+ characteristics to the normal algorithm, and is not compatible with
+ Perl. Some of the features of PCRE patterns are not supported. Never-
+ theless, there are times when this kind of matching can be useful. For
+ a discussion of the two matching algorithms, and a list of features
+ that pcre_dfa_exec() does not support, see the pcrematching documenta-
tion.
- The arguments for the pcre_dfa_exec() function are the same as for
+ The arguments for the pcre_dfa_exec() function are the same as for
pcre_exec(), plus two extras. The ovector argument is used in a differ-
- ent way, and this is described below. The other common arguments are
- used in the same way as for pcre_exec(), so their description is not
+ ent way, and this is described below. The other common arguments are
+ used in the same way as for pcre_exec(), so their description is not
repeated here.
- The two additional arguments provide workspace for the function. The
- workspace vector should contain at least 20 elements. It is used for
+ The two additional arguments provide workspace for the function. The
+ workspace vector should contain at least 20 elements. It is used for
keeping track of multiple paths through the pattern tree. More
- workspace will be needed for patterns and subjects where there are a
+ workspace will be needed for patterns and subjects where there are a
lot of potential matches.
Here is an example of a simple call to pcre_dfa_exec():
Option bits for pcre_dfa_exec()
- The unused bits of the options argument for pcre_dfa_exec() must be
- zero. The only bits that may be set are PCRE_ANCHORED, PCRE_NEW-
+ The unused bits of the options argument for pcre_dfa_exec() must be
+ zero. The only bits that may be set are PCRE_ANCHORED, PCRE_NEW-
LINE_xxx, PCRE_NOTBOL, PCRE_NOTEOL, PCRE_NOTEMPTY,
- PCRE_NOTEMPTY_ATSTART, PCRE_NO_UTF8_CHECK, PCRE_BSR_ANYCRLF,
- PCRE_BSR_UNICODE, PCRE_NO_START_OPTIMIZE, PCRE_PARTIAL_HARD, PCRE_PAR-
- TIAL_SOFT, PCRE_DFA_SHORTEST, and PCRE_DFA_RESTART. All but the last
- four of these are exactly the same as for pcre_exec(), so their
+ PCRE_NOTEMPTY_ATSTART, PCRE_NO_UTF8_CHECK, PCRE_BSR_ANYCRLF,
+ PCRE_BSR_UNICODE, PCRE_NO_START_OPTIMIZE, PCRE_PARTIAL_HARD, PCRE_PAR-
+ TIAL_SOFT, PCRE_DFA_SHORTEST, and PCRE_DFA_RESTART. All but the last
+ four of these are exactly the same as for pcre_exec(), so their
description is not repeated here.
PCRE_PARTIAL_HARD
PCRE_PARTIAL_SOFT
- These have the same general effect as they do for pcre_exec(), but the
- details are slightly different. When PCRE_PARTIAL_HARD is set for
- pcre_dfa_exec(), it returns PCRE_ERROR_PARTIAL if the end of the sub-
- ject is reached and there is still at least one matching possibility
+ These have the same general effect as they do for pcre_exec(), but the
+ details are slightly different. When PCRE_PARTIAL_HARD is set for
+ pcre_dfa_exec(), it returns PCRE_ERROR_PARTIAL if the end of the sub-
+ ject is reached and there is still at least one matching possibility
that requires additional characters. This happens even if some complete
matches have also been found. When PCRE_PARTIAL_SOFT is set, the return
code PCRE_ERROR_NOMATCH is converted into PCRE_ERROR_PARTIAL if the end
- of the subject is reached, there have been no complete matches, but
- there is still at least one matching possibility. The portion of the
- string that was inspected when the longest partial match was found is
- set as the first matching string in both cases. There is a more
- detailed discussion of partial and multi-segment matching, with exam-
+ of the subject is reached, there have been no complete matches, but
+ there is still at least one matching possibility. The portion of the
+ string that was inspected when the longest partial match was found is
+ set as the first matching string in both cases. There is a more
+ detailed discussion of partial and multi-segment matching, with exam-
ples, in the pcrepartial documentation.
PCRE_DFA_SHORTEST
- Setting the PCRE_DFA_SHORTEST option causes the matching algorithm to
+ Setting the PCRE_DFA_SHORTEST option causes the matching algorithm to
stop as soon as it has found one match. Because of the way the alterna-
- tive algorithm works, this is necessarily the shortest possible match
+ tive algorithm works, this is necessarily the shortest possible match
at the first possible matching point in the subject string.
PCRE_DFA_RESTART
When pcre_dfa_exec() returns a partial match, it is possible to call it
- again, with additional subject characters, and have it continue with
- the same match. The PCRE_DFA_RESTART option requests this action; when
- it is set, the workspace and wscount options must reference the same
- vector as before because data about the match so far is left in them
+ again, with additional subject characters, and have it continue with
+ the same match. The PCRE_DFA_RESTART option requests this action; when
+ it is set, the workspace and wscount options must reference the same
+ vector as before because data about the match so far is left in them
after a partial match. There is more discussion of this facility in the
pcrepartial documentation.
Successful returns from pcre_dfa_exec()
- When pcre_dfa_exec() succeeds, it may have matched more than one sub-
+ When pcre_dfa_exec() succeeds, it may have matched more than one sub-
string in the subject. Note, however, that all the matches from one run
- of the function start at the same point in the subject. The shorter
- matches are all initial substrings of the longer matches. For example,
+ of the function start at the same point in the subject. The shorter
+ matches are all initial substrings of the longer matches. For example,
if the pattern
<.*>
<something> <something else>
<something> <something else> <something further>
- On success, the yield of the function is a number greater than zero,
- which is the number of matched substrings. The substrings themselves
- are returned in ovector. Each string uses two elements; the first is
- the offset to the start, and the second is the offset to the end. In
- fact, all the strings have the same start offset. (Space could have
- been saved by giving this only once, but it was decided to retain some
- compatibility with the way pcre_exec() returns data, even though the
+ On success, the yield of the function is a number greater than zero,
+ which is the number of matched substrings. The substrings themselves
+ are returned in ovector. Each string uses two elements; the first is
+ the offset to the start, and the second is the offset to the end. In
+ fact, all the strings have the same start offset. (Space could have
+ been saved by giving this only once, but it was decided to retain some
+ compatibility with the way pcre_exec() returns data, even though the
meaning of the strings is different.)
The strings are returned in reverse order of length; that is, the long-
- est matching string is given first. If there were too many matches to
- fit into ovector, the yield of the function is zero, and the vector is
- filled with the longest matches. Unlike pcre_exec(), pcre_dfa_exec()
+ est matching string is given first. If there were too many matches to
+ fit into ovector, the yield of the function is zero, and the vector is
+ filled with the longest matches. Unlike pcre_exec(), pcre_dfa_exec()
can use the entire ovector for returning matched strings.
- NOTE: PCRE's "auto-possessification" optimization usually applies to
- character repeats at the end of a pattern (as well as internally). For
- example, the pattern "a\d+" is compiled as if it were "a\d++" because
+ NOTE: PCRE's "auto-possessification" optimization usually applies to
+ character repeats at the end of a pattern (as well as internally). For
+ example, the pattern "a\d+" is compiled as if it were "a\d++" because
there is no point even considering the possibility of backtracking into
- the repeated digits. For DFA matching, this means that only one possi-
- ble match is found. If you really do want multiple matches in such
- cases, either use an ungreedy repeat ("a\d+?") or set the
+ the repeated digits. For DFA matching, this means that only one possi-
+ ble match is found. If you really do want multiple matches in such
+ cases, either use an ungreedy repeat ("a\d+?") or set the
PCRE_NO_AUTO_POSSESS option when compiling.
Error returns from pcre_dfa_exec()
- The pcre_dfa_exec() function returns a negative number when it fails.
- Many of the errors are the same as for pcre_exec(), and these are
- described above. There are in addition the following errors that are
+ The pcre_dfa_exec() function returns a negative number when it fails.
+ Many of the errors are the same as for pcre_exec(), and these are
+ described above. There are in addition the following errors that are
specific to pcre_dfa_exec():
PCRE_ERROR_DFA_UITEM (-16)
- This return is given if pcre_dfa_exec() encounters an item in the pat-
- tern that it does not support, for instance, the use of \C or a back
+ This return is given if pcre_dfa_exec() encounters an item in the pat-
+ tern that it does not support, for instance, the use of \C or a back
reference.
PCRE_ERROR_DFA_UCOND (-17)
- This return is given if pcre_dfa_exec() encounters a condition item
- that uses a back reference for the condition, or a test for recursion
+ This return is given if pcre_dfa_exec() encounters a condition item
+ that uses a back reference for the condition, or a test for recursion
in a specific group. These are not supported.
PCRE_ERROR_DFA_UMLIMIT (-18)
- This return is given if pcre_dfa_exec() is called with an extra block
- that contains a setting of the match_limit or match_limit_recursion
- fields. This is not supported (these fields are meaningless for DFA
+ This return is given if pcre_dfa_exec() is called with an extra block
+ that contains a setting of the match_limit or match_limit_recursion
+ fields. This is not supported (these fields are meaningless for DFA
matching).
PCRE_ERROR_DFA_WSSIZE (-19)
- This return is given if pcre_dfa_exec() runs out of space in the
+ This return is given if pcre_dfa_exec() runs out of space in the
workspace vector.
PCRE_ERROR_DFA_RECURSE (-20)
- When a recursive subpattern is processed, the matching function calls
- itself recursively, using private vectors for ovector and workspace.
- This error is given if the output vector is not large enough. This
+ When a recursive subpattern is processed, the matching function calls
+ itself recursively, using private vectors for ovector and workspace.
+ This error is given if the output vector is not large enough. This
should be extremely rare, as a vector of size 1000 is used.
PCRE_ERROR_DFA_BADRESTART (-30)
- When pcre_dfa_exec() is called with the PCRE_DFA_RESTART option, some
- plausibility checks are made on the contents of the workspace, which
- should contain data about the previous partial match. If any of these
+ When pcre_dfa_exec() is called with the PCRE_DFA_RESTART option, some
+ plausibility checks are made on the contents of the workspace, which
+ should contain data about the previous partial match. If any of these
checks fail, this error is given.
SEE ALSO
- pcre16(3), pcre32(3), pcrebuild(3), pcrecallout(3), pcrecpp(3)(3),
+ pcre16(3), pcre32(3), pcrebuild(3), pcrecallout(3), pcrecpp(3)(3),
pcrematching(3), pcrepartial(3), pcreposix(3), pcreprecompile(3), pcre-
sample(3), pcrestack(3).
REVISION
- Last updated: 09 February 2014
- Copyright (c) 1997-2014 University of Cambridge.
+ Last updated: 18 December 2015
+ Copyright (c) 1997-2015 University of Cambridge.
------------------------------------------------------------------------------
pattern names is not as general as Perl's. This is a consequence of the
fact the PCRE works internally just with numbers, using an external ta-
ble to translate between numbers and names. In particular, a pattern
- such as (?|(?<a>A)|(?<b)B), where the two capturing parentheses have
+ such as (?|(?<a>A)|(?<b>B), where the two capturing parentheses have
the same number but different names, is not supported, and causes an
error at compile time. If it were allowed, it would not be possible to
distinguish which parentheses matched, because both names map to cap-
ate the appropriate EBCDIC code values. The \c escape is processed as
specified for Perl in the perlebcdic document. The only characters that
are allowed after \c are A-Z, a-z, or one of @, [, \, ], ^, _, or ?.
- Any other character provokes a compile-time error. The sequence \@
- encodes character code 0; the letters (in either case) encode charac-
- ters 1-26 (hex 01 to hex 1A); [, \, ], ^, and _ encode characters 27-31
- (hex 1B to hex 1F), and \? becomes either 255 (hex FF) or 95 (hex 5F).
-
- Thus, apart from \?, these escapes generate the same character code
- values as they do in an ASCII environment, though the meanings of the
- values mostly differ. For example, \G always generates code value 7,
+ Any other character provokes a compile-time error. The sequence \c@
+ encodes character code 0; after \c the letters (in either case) encode
+ characters 1-26 (hex 01 to hex 1A); [, \, ], ^, and _ encode characters
+ 27-31 (hex 1B to hex 1F), and \c? becomes either 255 (hex FF) or 95
+ (hex 5F).
+
+ Thus, apart from \c?, these escapes generate the same character code
+ values as they do in an ASCII environment, though the meanings of the
+ values mostly differ. For example, \cG always generates code value 7,
which is BEL in ASCII but DEL in EBCDIC.
- The sequence \? generates DEL (127, hex 7F) in an ASCII environment,
- but because 127 is not a control character in EBCDIC, Perl makes it
- generate the APC character. Unfortunately, there are several variants
- of EBCDIC. In most of them the APC character has the value 255 (hex
- FF), but in the one Perl calls POSIX-BC its value is 95 (hex 5F). If
- certain other characters have POSIX-BC values, PCRE makes \? generate
+ The sequence \c? generates DEL (127, hex 7F) in an ASCII environment,
+ but because 127 is not a control character in EBCDIC, Perl makes it
+ generate the APC character. Unfortunately, there are several variants
+ of EBCDIC. In most of them the APC character has the value 255 (hex
+ FF), but in the one Perl calls POSIX-BC its value is 95 (hex 5F). If
+ certain other characters have POSIX-BC values, PCRE makes \c? generate
95; otherwise it generates 255.
- After \0 up to two further octal digits are read. If there are fewer
- than two digits, just those that are present are used. Thus the
+ After \0 up to two further octal digits are read. If there are fewer
+ than two digits, just those that are present are used. Thus the
sequence \0\x\015 specifies two binary zeros followed by a CR character
(code value 13). Make sure you supply two digits after the initial zero
if the pattern character that follows is itself an octal digit.
- The escape \o must be followed by a sequence of octal digits, enclosed
- in braces. An error occurs if this is not the case. This escape is a
- recent addition to Perl; it provides way of specifying character code
- points as octal numbers greater than 0777, and it also allows octal
+ The escape \o must be followed by a sequence of octal digits, enclosed
+ in braces. An error occurs if this is not the case. This escape is a
+ recent addition to Perl; it provides way of specifying character code
+ points as octal numbers greater than 0777, and it also allows octal
numbers and back references to be unambiguously specified.
For greater clarity and unambiguity, it is best to avoid following \ by
a digit greater than zero. Instead, use \o{} or \x{} to specify charac-
- ter numbers, and \g{} to specify back references. The following para-
+ ter numbers, and \g{} to specify back references. The following para-
graphs describe the old, ambiguous syntax.
The handling of a backslash followed by a digit other than 0 is compli-
- cated, and Perl has changed in recent releases, causing PCRE also to
+ cated, and Perl has changed in recent releases, causing PCRE also to
change. Outside a character class, PCRE reads the digit and any follow-
- ing digits as a decimal number. If the number is less than 8, or if
- there have been at least that many previous capturing left parentheses
- in the expression, the entire sequence is taken as a back reference. A
- description of how this works is given later, following the discussion
+ ing digits as a decimal number. If the number is less than 8, or if
+ there have been at least that many previous capturing left parentheses
+ in the expression, the entire sequence is taken as a back reference. A
+ description of how this works is given later, following the discussion
of parenthesized subpatterns.
- Inside a character class, or if the decimal number following \ is
+ Inside a character class, or if the decimal number following \ is
greater than 7 and there have not been that many capturing subpatterns,
- PCRE handles \8 and \9 as the literal characters "8" and "9", and oth-
+ PCRE handles \8 and \9 as the literal characters "8" and "9", and oth-
erwise re-reads up to three octal digits following the backslash, using
- them to generate a data character. Any subsequent digits stand for
+ them to generate a data character. Any subsequent digits stand for
themselves. For example:
\040 is another way of writing an ASCII space
\81 is either a back reference, or the two
characters "8" and "1"
- Note that octal values of 100 or greater that are specified using this
- syntax must not be introduced by a leading zero, because no more than
+ Note that octal values of 100 or greater that are specified using this
+ syntax must not be introduced by a leading zero, because no more than
three octal digits are ever read.
- By default, after \x that is not followed by {, from zero to two hexa-
- decimal digits are read (letters can be in upper or lower case). Any
+ By default, after \x that is not followed by {, from zero to two hexa-
+ decimal digits are read (letters can be in upper or lower case). Any
number of hexadecimal digits may appear between \x{ and }. If a charac-
- ter other than a hexadecimal digit appears between \x{ and }, or if
+ ter other than a hexadecimal digit appears between \x{ and }, or if
there is no terminating }, an error occurs.
- If the PCRE_JAVASCRIPT_COMPAT option is set, the interpretation of \x
- is as just described only when it is followed by two hexadecimal dig-
- its. Otherwise, it matches a literal "x" character. In JavaScript
+ If the PCRE_JAVASCRIPT_COMPAT option is set, the interpretation of \x
+ is as just described only when it is followed by two hexadecimal dig-
+ its. Otherwise, it matches a literal "x" character. In JavaScript
mode, support for code points greater than 256 is provided by \u, which
- must be followed by four hexadecimal digits; otherwise it matches a
+ must be followed by four hexadecimal digits; otherwise it matches a
literal "u" character.
Characters whose value is less than 256 can be defined by either of the
- two syntaxes for \x (or by \u in JavaScript mode). There is no differ-
+ two syntaxes for \x (or by \u in JavaScript mode). There is no differ-
ence in the way they are handled. For example, \xdc is exactly the same
as \x{dc} (or \u00dc in JavaScript mode).
Constraints on character values
- Characters that are specified using octal or hexadecimal numbers are
+ Characters that are specified using octal or hexadecimal numbers are
limited to certain values, as follows:
8-bit non-UTF mode less than 0x100
32-bit non-UTF mode less than 0x100000000
32-bit UTF-32 mode less than 0x10ffff and a valid codepoint
- Invalid Unicode codepoints are the range 0xd800 to 0xdfff (the so-
+ Invalid Unicode codepoints are the range 0xd800 to 0xdfff (the so-
called "surrogate" codepoints), and 0xffef.
Escape sequences in character classes
All the sequences that define a single character value can be used both
- inside and outside character classes. In addition, inside a character
+ inside and outside character classes. In addition, inside a character
class, \b is interpreted as the backspace character (hex 08).
- \N is not allowed in a character class. \B, \R, and \X are not special
- inside a character class. Like other unrecognized escape sequences,
- they are treated as the literal characters "B", "R", and "X" by
- default, but cause an error if the PCRE_EXTRA option is set. Outside a
+ \N is not allowed in a character class. \B, \R, and \X are not special
+ inside a character class. Like other unrecognized escape sequences,
+ they are treated as the literal characters "B", "R", and "X" by
+ default, but cause an error if the PCRE_EXTRA option is set. Outside a
character class, these sequences have different meanings.
Unsupported escape sequences
- In Perl, the sequences \l, \L, \u, and \U are recognized by its string
- handler and used to modify the case of following characters. By
- default, PCRE does not support these escape sequences. However, if the
- PCRE_JAVASCRIPT_COMPAT option is set, \U matches a "U" character, and
+ In Perl, the sequences \l, \L, \u, and \U are recognized by its string
+ handler and used to modify the case of following characters. By
+ default, PCRE does not support these escape sequences. However, if the
+ PCRE_JAVASCRIPT_COMPAT option is set, \U matches a "U" character, and
\u can be used to define a character by code point, as described in the
previous section.
Absolute and relative back references
- The sequence \g followed by an unsigned or a negative number, option-
- ally enclosed in braces, is an absolute or relative back reference. A
+ The sequence \g followed by an unsigned or a negative number, option-
+ ally enclosed in braces, is an absolute or relative back reference. A
named back reference can be coded as \g{name}. Back references are dis-
cussed later, following the discussion of parenthesized subpatterns.
Absolute and relative subroutine calls
- For compatibility with Oniguruma, the non-Perl syntax \g followed by a
+ For compatibility with Oniguruma, the non-Perl syntax \g followed by a
name or a number enclosed either in angle brackets or single quotes, is
- an alternative syntax for referencing a subpattern as a "subroutine".
- Details are discussed later. Note that \g{...} (Perl syntax) and
- \g<...> (Oniguruma syntax) are not synonymous. The former is a back
+ an alternative syntax for referencing a subpattern as a "subroutine".
+ Details are discussed later. Note that \g{...} (Perl syntax) and
+ \g<...> (Oniguruma syntax) are not synonymous. The former is a back
reference; the latter is a subroutine call.
Generic character types
\W any "non-word" character
There is also the single sequence \N, which matches a non-newline char-
- acter. This is the same as the "." metacharacter when PCRE_DOTALL is
- not set. Perl also uses \N to match characters by name; PCRE does not
+ acter. This is the same as the "." metacharacter when PCRE_DOTALL is
+ not set. Perl also uses \N to match characters by name; PCRE does not
support this.
- Each pair of lower and upper case escape sequences partitions the com-
- plete set of characters into two disjoint sets. Any given character
- matches one, and only one, of each pair. The sequences can appear both
- inside and outside character classes. They each match one character of
- the appropriate type. If the current matching point is at the end of
- the subject string, all of them fail, because there is no character to
+ Each pair of lower and upper case escape sequences partitions the com-
+ plete set of characters into two disjoint sets. Any given character
+ matches one, and only one, of each pair. The sequences can appear both
+ inside and outside character classes. They each match one character of
+ the appropriate type. If the current matching point is at the end of
+ the subject string, all of them fail, because there is no character to
match.
- For compatibility with Perl, \s did not used to match the VT character
- (code 11), which made it different from the the POSIX "space" class.
- However, Perl added VT at release 5.18, and PCRE followed suit at
- release 8.34. The default \s characters are now HT (9), LF (10), VT
- (11), FF (12), CR (13), and space (32), which are defined as white
+ For compatibility with Perl, \s did not used to match the VT character
+ (code 11), which made it different from the the POSIX "space" class.
+ However, Perl added VT at release 5.18, and PCRE followed suit at
+ release 8.34. The default \s characters are now HT (9), LF (10), VT
+ (11), FF (12), CR (13), and space (32), which are defined as white
space in the "C" locale. This list may vary if locale-specific matching
- is taking place. For example, in some locales the "non-breaking space"
- character (\xA0) is recognized as white space, and in others the VT
+ is taking place. For example, in some locales the "non-breaking space"
+ character (\xA0) is recognized as white space, and in others the VT
character is not.
- A "word" character is an underscore or any character that is a letter
- or digit. By default, the definition of letters and digits is con-
- trolled by PCRE's low-valued character tables, and may vary if locale-
- specific matching is taking place (see "Locale support" in the pcreapi
- page). For example, in a French locale such as "fr_FR" in Unix-like
- systems, or "french" in Windows, some character codes greater than 127
- are used for accented letters, and these are then matched by \w. The
+ A "word" character is an underscore or any character that is a letter
+ or digit. By default, the definition of letters and digits is con-
+ trolled by PCRE's low-valued character tables, and may vary if locale-
+ specific matching is taking place (see "Locale support" in the pcreapi
+ page). For example, in a French locale such as "fr_FR" in Unix-like
+ systems, or "french" in Windows, some character codes greater than 127
+ are used for accented letters, and these are then matched by \w. The
use of locales with Unicode is discouraged.
- By default, characters whose code points are greater than 127 never
+ By default, characters whose code points are greater than 127 never
match \d, \s, or \w, and always match \D, \S, and \W, although this may
- vary for characters in the range 128-255 when locale-specific matching
- is happening. These escape sequences retain their original meanings
- from before Unicode support was available, mainly for efficiency rea-
- sons. If PCRE is compiled with Unicode property support, and the
- PCRE_UCP option is set, the behaviour is changed so that Unicode prop-
+ vary for characters in the range 128-255 when locale-specific matching
+ is happening. These escape sequences retain their original meanings
+ from before Unicode support was available, mainly for efficiency rea-
+ sons. If PCRE is compiled with Unicode property support, and the
+ PCRE_UCP option is set, the behaviour is changed so that Unicode prop-
erties are used to determine character types, as follows:
\d any character that matches \p{Nd} (decimal digit)
\s any character that matches \p{Z} or \h or \v
\w any character that matches \p{L} or \p{N}, plus underscore
- The upper case escapes match the inverse sets of characters. Note that
- \d matches only decimal digits, whereas \w matches any Unicode digit,
- as well as any Unicode letter, and underscore. Note also that PCRE_UCP
- affects \b, and \B because they are defined in terms of \w and \W.
+ The upper case escapes match the inverse sets of characters. Note that
+ \d matches only decimal digits, whereas \w matches any Unicode digit,
+ as well as any Unicode letter, and underscore. Note also that PCRE_UCP
+ affects \b, and \B because they are defined in terms of \w and \W.
Matching these sequences is noticeably slower when PCRE_UCP is set.
- The sequences \h, \H, \v, and \V are features that were added to Perl
- at release 5.10. In contrast to the other sequences, which match only
- ASCII characters by default, these always match certain high-valued
+ The sequences \h, \H, \v, and \V are features that were added to Perl
+ at release 5.10. In contrast to the other sequences, which match only
+ ASCII characters by default, these always match certain high-valued
code points, whether or not PCRE_UCP is set. The horizontal space char-
acters are:
Newline sequences
- Outside a character class, by default, the escape sequence \R matches
- any Unicode newline sequence. In 8-bit non-UTF-8 mode \R is equivalent
+ Outside a character class, by default, the escape sequence \R matches
+ any Unicode newline sequence. In 8-bit non-UTF-8 mode \R is equivalent
to the following:
(?>\r\n|\n|\x0b|\f|\r|\x85)
- This is an example of an "atomic group", details of which are given
+ This is an example of an "atomic group", details of which are given
below. This particular group matches either the two-character sequence
- CR followed by LF, or one of the single characters LF (linefeed,
- U+000A), VT (vertical tab, U+000B), FF (form feed, U+000C), CR (car-
- riage return, U+000D), or NEL (next line, U+0085). The two-character
+ CR followed by LF, or one of the single characters LF (linefeed,
+ U+000A), VT (vertical tab, U+000B), FF (form feed, U+000C), CR (car-
+ riage return, U+000D), or NEL (next line, U+0085). The two-character
sequence is treated as a single unit that cannot be split.
- In other modes, two additional characters whose codepoints are greater
+ In other modes, two additional characters whose codepoints are greater
than 255 are added: LS (line separator, U+2028) and PS (paragraph sepa-
- rator, U+2029). Unicode character property support is not needed for
+ rator, U+2029). Unicode character property support is not needed for
these characters to be recognized.
It is possible to restrict \R to match only CR, LF, or CRLF (instead of
- the complete set of Unicode line endings) by setting the option
+ the complete set of Unicode line endings) by setting the option
PCRE_BSR_ANYCRLF either at compile time or when the pattern is matched.
(BSR is an abbrevation for "backslash R".) This can be made the default
- when PCRE is built; if this is the case, the other behaviour can be
- requested via the PCRE_BSR_UNICODE option. It is also possible to
- specify these settings by starting a pattern string with one of the
+ when PCRE is built; if this is the case, the other behaviour can be
+ requested via the PCRE_BSR_UNICODE option. It is also possible to
+ specify these settings by starting a pattern string with one of the
following sequences:
(*BSR_ANYCRLF) CR, LF, or CRLF only
(*BSR_UNICODE) any Unicode newline sequence
These override the default and the options given to the compiling func-
- tion, but they can themselves be overridden by options given to a
- matching function. Note that these special settings, which are not
- Perl-compatible, are recognized only at the very start of a pattern,
- and that they must be in upper case. If more than one of them is
- present, the last one is used. They can be combined with a change of
+ tion, but they can themselves be overridden by options given to a
+ matching function. Note that these special settings, which are not
+ Perl-compatible, are recognized only at the very start of a pattern,
+ and that they must be in upper case. If more than one of them is
+ present, the last one is used. They can be combined with a change of
newline convention; for example, a pattern can start with:
(*ANY)(*BSR_ANYCRLF)
- They can also be combined with the (*UTF8), (*UTF16), (*UTF32), (*UTF)
+ They can also be combined with the (*UTF8), (*UTF16), (*UTF32), (*UTF)
or (*UCP) special sequences. Inside a character class, \R is treated as
- an unrecognized escape sequence, and so matches the letter "R" by
+ an unrecognized escape sequence, and so matches the letter "R" by
default, but causes an error if PCRE_EXTRA is set.
Unicode character properties
When PCRE is built with Unicode character property support, three addi-
- tional escape sequences that match characters with specific properties
- are available. When in 8-bit non-UTF-8 mode, these sequences are of
- course limited to testing characters whose codepoints are less than
+ tional escape sequences that match characters with specific properties
+ are available. When in 8-bit non-UTF-8 mode, these sequences are of
+ course limited to testing characters whose codepoints are less than
256, but they do work in this mode. The extra escape sequences are:
\p{xx} a character with the xx property
\P{xx} a character without the xx property
\X a Unicode extended grapheme cluster
- The property names represented by xx above are limited to the Unicode
+ The property names represented by xx above are limited to the Unicode
script names, the general category properties, "Any", which matches any
- character (including newline), and some special PCRE properties
- (described in the next section). Other Perl properties such as "InMu-
- sicalSymbols" are not currently supported by PCRE. Note that \P{Any}
+ character (including newline), and some special PCRE properties
+ (described in the next section). Other Perl properties such as "InMu-
+ sicalSymbols" are not currently supported by PCRE. Note that \P{Any}
does not match any characters, so always causes a match failure.
Sets of Unicode characters are defined as belonging to certain scripts.
- A character from one of these sets can be matched using a script name.
+ A character from one of these sets can be matched using a script name.
For example:
\p{Greek}
\P{Han}
- Those that are not part of an identified script are lumped together as
+ Those that are not part of an identified script are lumped together as
"Common". The current list of scripts is:
- Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak, Bengali,
- Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Car-
+ Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak, Bengali,
+ Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Car-
ian, Caucasian_Albanian, Chakma, Cham, Cherokee, Common, Coptic, Cunei-
form, Cypriot, Cyrillic, Deseret, Devanagari, Duployan, Egyptian_Hiero-
glyphs, Elbasan, Ethiopic, Georgian, Glagolitic, Gothic, Grantha,
- Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana,
- Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscrip-
- tional_Parthian, Javanese, Kaithi, Kannada, Katakana, Kayah_Li,
- Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha, Limbu, Lin-
- ear_A, Linear_B, Lisu, Lycian, Lydian, Mahajani, Malayalam, Mandaic,
- Manichaean, Meetei_Mayek, Mende_Kikakui, Meroitic_Cursive,
- Meroitic_Hieroglyphs, Miao, Modi, Mongolian, Mro, Myanmar, Nabataean,
- New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_North_Arabian,
+ Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana,
+ Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscrip-
+ tional_Parthian, Javanese, Kaithi, Kannada, Katakana, Kayah_Li,
+ Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha, Limbu, Lin-
+ ear_A, Linear_B, Lisu, Lycian, Lydian, Mahajani, Malayalam, Mandaic,
+ Manichaean, Meetei_Mayek, Mende_Kikakui, Meroitic_Cursive,
+ Meroitic_Hieroglyphs, Miao, Modi, Mongolian, Mro, Myanmar, Nabataean,
+ New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_North_Arabian,
Old_Permic, Old_Persian, Old_South_Arabian, Old_Turkic, Oriya, Osmanya,
Pahawh_Hmong, Palmyrene, Pau_Cin_Hau, Phags_Pa, Phoenician,
- Psalter_Pahlavi, Rejang, Runic, Samaritan, Saurashtra, Sharada, Sha-
- vian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac,
- Tagalog, Tagbanwa, Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu,
- Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic, Vai, Warang_Citi,
+ Psalter_Pahlavi, Rejang, Runic, Samaritan, Saurashtra, Sharada, Sha-
+ vian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac,
+ Tagalog, Tagbanwa, Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu,
+ Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic, Vai, Warang_Citi,
Yi.
Each character has exactly one Unicode general category property, spec-
- ified by a two-letter abbreviation. For compatibility with Perl, nega-
- tion can be specified by including a circumflex between the opening
- brace and the property name. For example, \p{^Lu} is the same as
+ ified by a two-letter abbreviation. For compatibility with Perl, nega-
+ tion can be specified by including a circumflex between the opening
+ brace and the property name. For example, \p{^Lu} is the same as
\P{Lu}.
If only one letter is specified with \p or \P, it includes all the gen-
- eral category properties that start with that letter. In this case, in
- the absence of negation, the curly brackets in the escape sequence are
+ eral category properties that start with that letter. In this case, in
+ the absence of negation, the curly brackets in the escape sequence are
optional; these two examples have the same effect:
\p{L}
Zp Paragraph separator
Zs Space separator
- The special property L& is also supported: it matches a character that
- has the Lu, Ll, or Lt property, in other words, a letter that is not
+ The special property L& is also supported: it matches a character that
+ has the Lu, Ll, or Lt property, in other words, a letter that is not
classified as a modifier or "other".
- The Cs (Surrogate) property applies only to characters in the range
- U+D800 to U+DFFF. Such characters are not valid in Unicode strings and
- so cannot be tested by PCRE, unless UTF validity checking has been
+ The Cs (Surrogate) property applies only to characters in the range
+ U+D800 to U+DFFF. Such characters are not valid in Unicode strings and
+ so cannot be tested by PCRE, unless UTF validity checking has been
turned off (see the discussion of PCRE_NO_UTF8_CHECK,
- PCRE_NO_UTF16_CHECK and PCRE_NO_UTF32_CHECK in the pcreapi page). Perl
+ PCRE_NO_UTF16_CHECK and PCRE_NO_UTF32_CHECK in the pcreapi page). Perl
does not support the Cs property.
- The long synonyms for property names that Perl supports (such as
- \p{Letter}) are not supported by PCRE, nor is it permitted to prefix
+ The long synonyms for property names that Perl supports (such as
+ \p{Letter}) are not supported by PCRE, nor is it permitted to prefix
any of these properties with "Is".
No character that is in the Unicode table has the Cn (unassigned) prop-
erty. Instead, this property is assumed for any code point that is not
in the Unicode table.
- Specifying caseless matching does not affect these escape sequences.
- For example, \p{Lu} always matches only upper case letters. This is
+ Specifying caseless matching does not affect these escape sequences.
+ For example, \p{Lu} always matches only upper case letters. This is
different from the behaviour of current versions of Perl.
- Matching characters by Unicode property is not fast, because PCRE has
- to do a multistage table lookup in order to find a character's prop-
+ Matching characters by Unicode property is not fast, because PCRE has
+ to do a multistage table lookup in order to find a character's prop-
erty. That is why the traditional escape sequences such as \d and \w do
not use Unicode properties in PCRE by default, though you can make them
- do so by setting the PCRE_UCP option or by starting the pattern with
+ do so by setting the PCRE_UCP option or by starting the pattern with
(*UCP).
Extended grapheme clusters
- The \X escape matches any number of Unicode characters that form an
+ The \X escape matches any number of Unicode characters that form an
"extended grapheme cluster", and treats the sequence as an atomic group
- (see below). Up to and including release 8.31, PCRE matched an ear-
+ (see below). Up to and including release 8.31, PCRE matched an ear-
lier, simpler definition that was equivalent to
(?>\PM\pM*)
- That is, it matched a character without the "mark" property, followed
- by zero or more characters with the "mark" property. Characters with
- the "mark" property are typically non-spacing accents that affect the
+ That is, it matched a character without the "mark" property, followed
+ by zero or more characters with the "mark" property. Characters with
+ the "mark" property are typically non-spacing accents that affect the
preceding character.
- This simple definition was extended in Unicode to include more compli-
- cated kinds of composite character by giving each character a grapheme
- breaking property, and creating rules that use these properties to
- define the boundaries of extended grapheme clusters. In releases of
+ This simple definition was extended in Unicode to include more compli-
+ cated kinds of composite character by giving each character a grapheme
+ breaking property, and creating rules that use these properties to
+ define the boundaries of extended grapheme clusters. In releases of
PCRE later than 8.31, \X matches one of these clusters.
- \X always matches at least one character. Then it decides whether to
+ \X always matches at least one character. Then it decides whether to
add additional characters according to the following rules for ending a
cluster:
1. End at the end of the subject string.
- 2. Do not end between CR and LF; otherwise end after any control char-
+ 2. Do not end between CR and LF; otherwise end after any control char-
acter.
- 3. Do not break Hangul (a Korean script) syllable sequences. Hangul
- characters are of five types: L, V, T, LV, and LVT. An L character may
- be followed by an L, V, LV, or LVT character; an LV or V character may
+ 3. Do not break Hangul (a Korean script) syllable sequences. Hangul
+ characters are of five types: L, V, T, LV, and LVT. An L character may
+ be followed by an L, V, LV, or LVT character; an LV or V character may
be followed by a V or T character; an LVT or T character may be follwed
only by a T character.
- 4. Do not end before extending characters or spacing marks. Characters
- with the "mark" property always have the "extend" grapheme breaking
+ 4. Do not end before extending characters or spacing marks. Characters
+ with the "mark" property always have the "extend" grapheme breaking
property.
5. Do not end after prepend characters.
PCRE's additional properties
- As well as the standard Unicode properties described above, PCRE sup-
- ports four more that make it possible to convert traditional escape
- sequences such as \w and \s to use Unicode properties. PCRE uses these
+ As well as the standard Unicode properties described above, PCRE sup-
+ ports four more that make it possible to convert traditional escape
+ sequences such as \w and \s to use Unicode properties. PCRE uses these
non-standard, non-Perl properties internally when PCRE_UCP is set. How-
ever, they may also be used explicitly. These properties are:
Xsp Any Perl space character
Xwd Any Perl "word" character
- Xan matches characters that have either the L (letter) or the N (num-
- ber) property. Xps matches the characters tab, linefeed, vertical tab,
- form feed, or carriage return, and any other character that has the Z
- (separator) property. Xsp is the same as Xps; it used to exclude ver-
- tical tab, for Perl compatibility, but Perl changed, and so PCRE fol-
- lowed at release 8.34. Xwd matches the same characters as Xan, plus
+ Xan matches characters that have either the L (letter) or the N (num-
+ ber) property. Xps matches the characters tab, linefeed, vertical tab,
+ form feed, or carriage return, and any other character that has the Z
+ (separator) property. Xsp is the same as Xps; it used to exclude ver-
+ tical tab, for Perl compatibility, but Perl changed, and so PCRE fol-
+ lowed at release 8.34. Xwd matches the same characters as Xan, plus
underscore.
- There is another non-standard property, Xuc, which matches any charac-
- ter that can be represented by a Universal Character Name in C++ and
- other programming languages. These are the characters $, @, ` (grave
- accent), and all characters with Unicode code points greater than or
- equal to U+00A0, except for the surrogates U+D800 to U+DFFF. Note that
- most base (ASCII) characters are excluded. (Universal Character Names
- are of the form \uHHHH or \UHHHHHHHH where H is a hexadecimal digit.
+ There is another non-standard property, Xuc, which matches any charac-
+ ter that can be represented by a Universal Character Name in C++ and
+ other programming languages. These are the characters $, @, ` (grave
+ accent), and all characters with Unicode code points greater than or
+ equal to U+00A0, except for the surrogates U+D800 to U+DFFF. Note that
+ most base (ASCII) characters are excluded. (Universal Character Names
+ are of the form \uHHHH or \UHHHHHHHH where H is a hexadecimal digit.
Note that the Xuc property does not match these sequences but the char-
acters that they represent.)
Resetting the match start
- The escape sequence \K causes any previously matched characters not to
+ The escape sequence \K causes any previously matched characters not to
be included in the final matched sequence. For example, the pattern:
foo\Kbar
- matches "foobar", but reports that it has matched "bar". This feature
- is similar to a lookbehind assertion (described below). However, in
- this case, the part of the subject before the real match does not have
- to be of fixed length, as lookbehind assertions do. The use of \K does
- not interfere with the setting of captured substrings. For example,
+ matches "foobar", but reports that it has matched "bar". This feature
+ is similar to a lookbehind assertion (described below). However, in
+ this case, the part of the subject before the real match does not have
+ to be of fixed length, as lookbehind assertions do. The use of \K does
+ not interfere with the setting of captured substrings. For example,
when the pattern
(foo)\Kbar
matches "foobar", the first substring is still set to "foo".
- Perl documents that the use of \K within assertions is "not well
- defined". In PCRE, \K is acted upon when it occurs inside positive
- assertions, but is ignored in negative assertions. Note that when a
- pattern such as (?=ab\K) matches, the reported start of the match can
+ Perl documents that the use of \K within assertions is "not well
+ defined". In PCRE, \K is acted upon when it occurs inside positive
+ assertions, but is ignored in negative assertions. Note that when a
+ pattern such as (?=ab\K) matches, the reported start of the match can
be greater than the end of the match.
Simple assertions
- The final use of backslash is for certain simple assertions. An asser-
- tion specifies a condition that has to be met at a particular point in
- a match, without consuming any characters from the subject string. The
- use of subpatterns for more complicated assertions is described below.
+ The final use of backslash is for certain simple assertions. An asser-
+ tion specifies a condition that has to be met at a particular point in
+ a match, without consuming any characters from the subject string. The
+ use of subpatterns for more complicated assertions is described below.
The backslashed assertions are:
\b matches at a word boundary
\z matches only at the end of the subject
\G matches at the first matching position in the subject
- Inside a character class, \b has a different meaning; it matches the
- backspace character. If any other of these assertions appears in a
- character class, by default it matches the corresponding literal char-
+ Inside a character class, \b has a different meaning; it matches the
+ backspace character. If any other of these assertions appears in a
+ character class, by default it matches the corresponding literal char-
acter (for example, \B matches the letter B). However, if the
- PCRE_EXTRA option is set, an "invalid escape sequence" error is gener-
+ PCRE_EXTRA option is set, an "invalid escape sequence" error is gener-
ated instead.
- A word boundary is a position in the subject string where the current
- character and the previous character do not both match \w or \W (i.e.
- one matches \w and the other matches \W), or the start or end of the
- string if the first or last character matches \w, respectively. In a
- UTF mode, the meanings of \w and \W can be changed by setting the
- PCRE_UCP option. When this is done, it also affects \b and \B. Neither
- PCRE nor Perl has a separate "start of word" or "end of word" metase-
- quence. However, whatever follows \b normally determines which it is.
+ A word boundary is a position in the subject string where the current
+ character and the previous character do not both match \w or \W (i.e.
+ one matches \w and the other matches \W), or the start or end of the
+ string if the first or last character matches \w, respectively. In a
+ UTF mode, the meanings of \w and \W can be changed by setting the
+ PCRE_UCP option. When this is done, it also affects \b and \B. Neither
+ PCRE nor Perl has a separate "start of word" or "end of word" metase-
+ quence. However, whatever follows \b normally determines which it is.
For example, the fragment \ba matches "a" at the start of a word.
- The \A, \Z, and \z assertions differ from the traditional circumflex
+ The \A, \Z, and \z assertions differ from the traditional circumflex
and dollar (described in the next section) in that they only ever match
- at the very start and end of the subject string, whatever options are
- set. Thus, they are independent of multiline mode. These three asser-
+ at the very start and end of the subject string, whatever options are
+ set. Thus, they are independent of multiline mode. These three asser-
tions are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options, which
- affect only the behaviour of the circumflex and dollar metacharacters.
- However, if the startoffset argument of pcre_exec() is non-zero, indi-
+ affect only the behaviour of the circumflex and dollar metacharacters.
+ However, if the startoffset argument of pcre_exec() is non-zero, indi-
cating that matching is to start at a point other than the beginning of
- the subject, \A can never match. The difference between \Z and \z is
+ the subject, \A can never match. The difference between \Z and \z is
that \Z matches before a newline at the end of the string as well as at
the very end, whereas \z matches only at the end.
- The \G assertion is true only when the current matching position is at
- the start point of the match, as specified by the startoffset argument
- of pcre_exec(). It differs from \A when the value of startoffset is
- non-zero. By calling pcre_exec() multiple times with appropriate argu-
+ The \G assertion is true only when the current matching position is at
+ the start point of the match, as specified by the startoffset argument
+ of pcre_exec(). It differs from \A when the value of startoffset is
+ non-zero. By calling pcre_exec() multiple times with appropriate argu-
ments, you can mimic Perl's /g option, and it is in this kind of imple-
mentation where \G can be useful.
- Note, however, that PCRE's interpretation of \G, as the start of the
+ Note, however, that PCRE's interpretation of \G, as the start of the
current match, is subtly different from Perl's, which defines it as the
- end of the previous match. In Perl, these can be different when the
- previously matched string was empty. Because PCRE does just one match
+ end of the previous match. In Perl, these can be different when the
+ previously matched string was empty. Because PCRE does just one match
at a time, it cannot reproduce this behaviour.
- If all the alternatives of a pattern begin with \G, the expression is
+ If all the alternatives of a pattern begin with \G, the expression is
anchored to the starting match position, and the "anchored" flag is set
in the compiled regular expression.
CIRCUMFLEX AND DOLLAR
- The circumflex and dollar metacharacters are zero-width assertions.
- That is, they test for a particular condition being true without con-
+ The circumflex and dollar metacharacters are zero-width assertions.
+ That is, they test for a particular condition being true without con-
suming any characters from the subject string.
Outside a character class, in the default matching mode, the circumflex
- character is an assertion that is true only if the current matching
- point is at the start of the subject string. If the startoffset argu-
- ment of pcre_exec() is non-zero, circumflex can never match if the
- PCRE_MULTILINE option is unset. Inside a character class, circumflex
+ character is an assertion that is true only if the current matching
+ point is at the start of the subject string. If the startoffset argu-
+ ment of pcre_exec() is non-zero, circumflex can never match if the
+ PCRE_MULTILINE option is unset. Inside a character class, circumflex
has an entirely different meaning (see below).
- Circumflex need not be the first character of the pattern if a number
- of alternatives are involved, but it should be the first thing in each
- alternative in which it appears if the pattern is ever to match that
- branch. If all possible alternatives start with a circumflex, that is,
- if the pattern is constrained to match only at the start of the sub-
- ject, it is said to be an "anchored" pattern. (There are also other
+ Circumflex need not be the first character of the pattern if a number
+ of alternatives are involved, but it should be the first thing in each
+ alternative in which it appears if the pattern is ever to match that
+ branch. If all possible alternatives start with a circumflex, that is,
+ if the pattern is constrained to match only at the start of the sub-
+ ject, it is said to be an "anchored" pattern. (There are also other
constructs that can cause a pattern to be anchored.)
- The dollar character is an assertion that is true only if the current
- matching point is at the end of the subject string, or immediately
- before a newline at the end of the string (by default). Note, however,
- that it does not actually match the newline. Dollar need not be the
+ The dollar character is an assertion that is true only if the current
+ matching point is at the end of the subject string, or immediately
+ before a newline at the end of the string (by default). Note, however,
+ that it does not actually match the newline. Dollar need not be the
last character of the pattern if a number of alternatives are involved,
- but it should be the last item in any branch in which it appears. Dol-
+ but it should be the last item in any branch in which it appears. Dol-
lar has no special meaning in a character class.
- The meaning of dollar can be changed so that it matches only at the
- very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at
+ The meaning of dollar can be changed so that it matches only at the
+ very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at
compile time. This does not affect the \Z assertion.
The meanings of the circumflex and dollar characters are changed if the
- PCRE_MULTILINE option is set. When this is the case, a circumflex
- matches immediately after internal newlines as well as at the start of
- the subject string. It does not match after a newline that ends the
- string. A dollar matches before any newlines in the string, as well as
- at the very end, when PCRE_MULTILINE is set. When newline is specified
- as the two-character sequence CRLF, isolated CR and LF characters do
+ PCRE_MULTILINE option is set. When this is the case, a circumflex
+ matches immediately after internal newlines as well as at the start of
+ the subject string. It does not match after a newline that ends the
+ string. A dollar matches before any newlines in the string, as well as
+ at the very end, when PCRE_MULTILINE is set. When newline is specified
+ as the two-character sequence CRLF, isolated CR and LF characters do
not indicate newlines.
- For example, the pattern /^abc$/ matches the subject string "def\nabc"
- (where \n represents a newline) in multiline mode, but not otherwise.
- Consequently, patterns that are anchored in single line mode because
- all branches start with ^ are not anchored in multiline mode, and a
- match for circumflex is possible when the startoffset argument of
- pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if
+ For example, the pattern /^abc$/ matches the subject string "def\nabc"
+ (where \n represents a newline) in multiline mode, but not otherwise.
+ Consequently, patterns that are anchored in single line mode because
+ all branches start with ^ are not anchored in multiline mode, and a
+ match for circumflex is possible when the startoffset argument of
+ pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if
PCRE_MULTILINE is set.
- Note that the sequences \A, \Z, and \z can be used to match the start
- and end of the subject in both modes, and if all branches of a pattern
- start with \A it is always anchored, whether or not PCRE_MULTILINE is
+ Note that the sequences \A, \Z, and \z can be used to match the start
+ and end of the subject in both modes, and if all branches of a pattern
+ start with \A it is always anchored, whether or not PCRE_MULTILINE is
set.
FULL STOP (PERIOD, DOT) AND \N
Outside a character class, a dot in the pattern matches any one charac-
- ter in the subject string except (by default) a character that signi-
+ ter in the subject string except (by default) a character that signi-
fies the end of a line.
- When a line ending is defined as a single character, dot never matches
- that character; when the two-character sequence CRLF is used, dot does
- not match CR if it is immediately followed by LF, but otherwise it
- matches all characters (including isolated CRs and LFs). When any Uni-
- code line endings are being recognized, dot does not match CR or LF or
+ When a line ending is defined as a single character, dot never matches
+ that character; when the two-character sequence CRLF is used, dot does
+ not match CR if it is immediately followed by LF, but otherwise it
+ matches all characters (including isolated CRs and LFs). When any Uni-
+ code line endings are being recognized, dot does not match CR or LF or
any of the other line ending characters.
- The behaviour of dot with regard to newlines can be changed. If the
- PCRE_DOTALL option is set, a dot matches any one character, without
+ The behaviour of dot with regard to newlines can be changed. If the
+ PCRE_DOTALL option is set, a dot matches any one character, without
exception. If the two-character sequence CRLF is present in the subject
string, it takes two dots to match it.
- The handling of dot is entirely independent of the handling of circum-
- flex and dollar, the only relationship being that they both involve
+ The handling of dot is entirely independent of the handling of circum-
+ flex and dollar, the only relationship being that they both involve
newlines. Dot has no special meaning in a character class.
- The escape sequence \N behaves like a dot, except that it is not
- affected by the PCRE_DOTALL option. In other words, it matches any
- character except one that signifies the end of a line. Perl also uses
+ The escape sequence \N behaves like a dot, except that it is not
+ affected by the PCRE_DOTALL option. In other words, it matches any
+ character except one that signifies the end of a line. Perl also uses
\N to match characters by name; PCRE does not support this.
MATCHING A SINGLE DATA UNIT
- Outside a character class, the escape sequence \C matches any one data
- unit, whether or not a UTF mode is set. In the 8-bit library, one data
- unit is one byte; in the 16-bit library it is a 16-bit unit; in the
- 32-bit library it is a 32-bit unit. Unlike a dot, \C always matches
- line-ending characters. The feature is provided in Perl in order to
+ Outside a character class, the escape sequence \C matches any one data
+ unit, whether or not a UTF mode is set. In the 8-bit library, one data
+ unit is one byte; in the 16-bit library it is a 16-bit unit; in the
+ 32-bit library it is a 32-bit unit. Unlike a dot, \C always matches
+ line-ending characters. The feature is provided in Perl in order to
match individual bytes in UTF-8 mode, but it is unclear how it can use-
- fully be used. Because \C breaks up characters into individual data
- units, matching one unit with \C in a UTF mode means that the rest of
+ fully be used. Because \C breaks up characters into individual data
+ units, matching one unit with \C in a UTF mode means that the rest of
the string may start with a malformed UTF character. This has undefined
results, because PCRE assumes that it is dealing with valid UTF strings
- (and by default it checks this at the start of processing unless the
- PCRE_NO_UTF8_CHECK, PCRE_NO_UTF16_CHECK or PCRE_NO_UTF32_CHECK option
+ (and by default it checks this at the start of processing unless the
+ PCRE_NO_UTF8_CHECK, PCRE_NO_UTF16_CHECK or PCRE_NO_UTF32_CHECK option
is used).
- PCRE does not allow \C to appear in lookbehind assertions (described
- below) in a UTF mode, because this would make it impossible to calcu-
+ PCRE does not allow \C to appear in lookbehind assertions (described
+ below) in a UTF mode, because this would make it impossible to calcu-
late the length of the lookbehind.
In general, the \C escape sequence is best avoided. However, one way of
- using it that avoids the problem of malformed UTF characters is to use
- a lookahead to check the length of the next character, as in this pat-
- tern, which could be used with a UTF-8 string (ignore white space and
+ using it that avoids the problem of malformed UTF characters is to use
+ a lookahead to check the length of the next character, as in this pat-
+ tern, which could be used with a UTF-8 string (ignore white space and
line breaks):
(?| (?=[\x00-\x7f])(\C) |
(?=[\x{800}-\x{ffff}])(\C)(\C)(\C) |
(?=[\x{10000}-\x{1fffff}])(\C)(\C)(\C)(\C))
- A group that starts with (?| resets the capturing parentheses numbers
- in each alternative (see "Duplicate Subpattern Numbers" below). The
- assertions at the start of each branch check the next UTF-8 character
- for values whose encoding uses 1, 2, 3, or 4 bytes, respectively. The
- character's individual bytes are then captured by the appropriate num-
+ A group that starts with (?| resets the capturing parentheses numbers
+ in each alternative (see "Duplicate Subpattern Numbers" below). The
+ assertions at the start of each branch check the next UTF-8 character
+ for values whose encoding uses 1, 2, 3, or 4 bytes, respectively. The
+ character's individual bytes are then captured by the appropriate num-
ber of groups.
closing square bracket. A closing square bracket on its own is not spe-
cial by default. However, if the PCRE_JAVASCRIPT_COMPAT option is set,
a lone closing square bracket causes a compile-time error. If a closing
- square bracket is required as a member of the class, it should be the
- first data character in the class (after an initial circumflex, if
+ square bracket is required as a member of the class, it should be the
+ first data character in the class (after an initial circumflex, if
present) or escaped with a backslash.
- A character class matches a single character in the subject. In a UTF
- mode, the character may be more than one data unit long. A matched
+ A character class matches a single character in the subject. In a UTF
+ mode, the character may be more than one data unit long. A matched
character must be in the set of characters defined by the class, unless
- the first character in the class definition is a circumflex, in which
+ the first character in the class definition is a circumflex, in which
case the subject character must not be in the set defined by the class.
- If a circumflex is actually required as a member of the class, ensure
+ If a circumflex is actually required as a member of the class, ensure
it is not the first character, or escape it with a backslash.
- For example, the character class [aeiou] matches any lower case vowel,
- while [^aeiou] matches any character that is not a lower case vowel.
+ For example, the character class [aeiou] matches any lower case vowel,
+ while [^aeiou] matches any character that is not a lower case vowel.
Note that a circumflex is just a convenient notation for specifying the
- characters that are in the class by enumerating those that are not. A
- class that starts with a circumflex is not an assertion; it still con-
- sumes a character from the subject string, and therefore it fails if
+ characters that are in the class by enumerating those that are not. A
+ class that starts with a circumflex is not an assertion; it still con-
+ sumes a character from the subject string, and therefore it fails if
the current pointer is at the end of the string.
In UTF-8 (UTF-16, UTF-32) mode, characters with values greater than 255
- (0xffff) can be included in a class as a literal string of data units,
+ (0xffff) can be included in a class as a literal string of data units,
or by using the \x{ escaping mechanism.
- When caseless matching is set, any letters in a class represent both
- their upper case and lower case versions, so for example, a caseless
- [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not
- match "A", whereas a caseful version would. In a UTF mode, PCRE always
- understands the concept of case for characters whose values are less
- than 128, so caseless matching is always possible. For characters with
- higher values, the concept of case is supported if PCRE is compiled
- with Unicode property support, but not otherwise. If you want to use
- caseless matching in a UTF mode for characters 128 and above, you must
- ensure that PCRE is compiled with Unicode property support as well as
+ When caseless matching is set, any letters in a class represent both
+ their upper case and lower case versions, so for example, a caseless
+ [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not
+ match "A", whereas a caseful version would. In a UTF mode, PCRE always
+ understands the concept of case for characters whose values are less
+ than 128, so caseless matching is always possible. For characters with
+ higher values, the concept of case is supported if PCRE is compiled
+ with Unicode property support, but not otherwise. If you want to use
+ caseless matching in a UTF mode for characters 128 and above, you must
+ ensure that PCRE is compiled with Unicode property support as well as
with UTF support.
- Characters that might indicate line breaks are never treated in any
- special way when matching character classes, whatever line-ending
- sequence is in use, and whatever setting of the PCRE_DOTALL and
+ Characters that might indicate line breaks are never treated in any
+ special way when matching character classes, whatever line-ending
+ sequence is in use, and whatever setting of the PCRE_DOTALL and
PCRE_MULTILINE options is used. A class such as [^a] always matches one
of these characters.
- The minus (hyphen) character can be used to specify a range of charac-
- ters in a character class. For example, [d-m] matches any letter
- between d and m, inclusive. If a minus character is required in a
- class, it must be escaped with a backslash or appear in a position
- where it cannot be interpreted as indicating a range, typically as the
+ The minus (hyphen) character can be used to specify a range of charac-
+ ters in a character class. For example, [d-m] matches any letter
+ between d and m, inclusive. If a minus character is required in a
+ class, it must be escaped with a backslash or appear in a position
+ where it cannot be interpreted as indicating a range, typically as the
first or last character in the class, or immediately after a range. For
- example, [b-d-z] matches letters in the range b to d, a hyphen charac-
+ example, [b-d-z] matches letters in the range b to d, a hyphen charac-
ter, or z.
It is not possible to have the literal character "]" as the end charac-
- ter of a range. A pattern such as [W-]46] is interpreted as a class of
- two characters ("W" and "-") followed by a literal string "46]", so it
- would match "W46]" or "-46]". However, if the "]" is escaped with a
- backslash it is interpreted as the end of range, so [W-\]46] is inter-
- preted as a class containing a range followed by two other characters.
- The octal or hexadecimal representation of "]" can also be used to end
+ ter of a range. A pattern such as [W-]46] is interpreted as a class of
+ two characters ("W" and "-") followed by a literal string "46]", so it
+ would match "W46]" or "-46]". However, if the "]" is escaped with a
+ backslash it is interpreted as the end of range, so [W-\]46] is inter-
+ preted as a class containing a range followed by two other characters.
+ The octal or hexadecimal representation of "]" can also be used to end
a range.
- An error is generated if a POSIX character class (see below) or an
- escape sequence other than one that defines a single character appears
- at a point where a range ending character is expected. For example,
+ An error is generated if a POSIX character class (see below) or an
+ escape sequence other than one that defines a single character appears
+ at a point where a range ending character is expected. For example,
[z-\xff] is valid, but [A-\d] and [A-[:digit:]] are not.
- Ranges operate in the collating sequence of character values. They can
- also be used for characters specified numerically, for example
- [\000-\037]. Ranges can include any characters that are valid for the
+ Ranges operate in the collating sequence of character values. They can
+ also be used for characters specified numerically, for example
+ [\000-\037]. Ranges can include any characters that are valid for the
current mode.
If a range that includes letters is used when caseless matching is set,
it matches the letters in either case. For example, [W-c] is equivalent
- to [][\\^_`wxyzabc], matched caselessly, and in a non-UTF mode, if
- character tables for a French locale are in use, [\xc8-\xcb] matches
- accented E characters in both cases. In UTF modes, PCRE supports the
- concept of case for characters with values greater than 128 only when
+ to [][\\^_`wxyzabc], matched caselessly, and in a non-UTF mode, if
+ character tables for a French locale are in use, [\xc8-\xcb] matches
+ accented E characters in both cases. In UTF modes, PCRE supports the
+ concept of case for characters with values greater than 128 only when
it is compiled with Unicode property support.
- The character escape sequences \d, \D, \h, \H, \p, \P, \s, \S, \v, \V,
+ The character escape sequences \d, \D, \h, \H, \p, \P, \s, \S, \v, \V,
\w, and \W may appear in a character class, and add the characters that
- they match to the class. For example, [\dABCDEF] matches any hexadeci-
- mal digit. In UTF modes, the PCRE_UCP option affects the meanings of
- \d, \s, \w and their upper case partners, just as it does when they
- appear outside a character class, as described in the section entitled
+ they match to the class. For example, [\dABCDEF] matches any hexadeci-
+ mal digit. In UTF modes, the PCRE_UCP option affects the meanings of
+ \d, \s, \w and their upper case partners, just as it does when they
+ appear outside a character class, as described in the section entitled
"Generic character types" above. The escape sequence \b has a different
- meaning inside a character class; it matches the backspace character.
- The sequences \B, \N, \R, and \X are not special inside a character
- class. Like any other unrecognized escape sequences, they are treated
- as the literal characters "B", "N", "R", and "X" by default, but cause
+ meaning inside a character class; it matches the backspace character.
+ The sequences \B, \N, \R, and \X are not special inside a character
+ class. Like any other unrecognized escape sequences, they are treated
+ as the literal characters "B", "N", "R", and "X" by default, but cause
an error if the PCRE_EXTRA option is set.
- A circumflex can conveniently be used with the upper case character
- types to specify a more restricted set of characters than the matching
- lower case type. For example, the class [^\W_] matches any letter or
+ A circumflex can conveniently be used with the upper case character
+ types to specify a more restricted set of characters than the matching
+ lower case type. For example, the class [^\W_] matches any letter or
digit, but not underscore, whereas [\w] includes underscore. A positive
character class should be read as "something OR something OR ..." and a
negative class as "NOT something AND NOT something AND NOT ...".
- The only metacharacters that are recognized in character classes are
- backslash, hyphen (only where it can be interpreted as specifying a
- range), circumflex (only at the start), opening square bracket (only
- when it can be interpreted as introducing a POSIX class name, or for a
- special compatibility feature - see the next two sections), and the
+ The only metacharacters that are recognized in character classes are
+ backslash, hyphen (only where it can be interpreted as specifying a
+ range), circumflex (only at the start), opening square bracket (only
+ when it can be interpreted as introducing a POSIX class name, or for a
+ special compatibility feature - see the next two sections), and the
terminating closing square bracket. However, escaping other non-
alphanumeric characters does no harm.
POSIX CHARACTER CLASSES
Perl supports the POSIX notation for character classes. This uses names
- enclosed by [: and :] within the enclosing square brackets. PCRE also
+ enclosed by [: and :] within the enclosing square brackets. PCRE also
supports this notation. For example,
[01[:alpha:]%]
word "word" characters (same as \w)
xdigit hexadecimal digits
- The default "space" characters are HT (9), LF (10), VT (11), FF (12),
- CR (13), and space (32). If locale-specific matching is taking place,
- the list of space characters may be different; there may be fewer or
+ The default "space" characters are HT (9), LF (10), VT (11), FF (12),
+ CR (13), and space (32). If locale-specific matching is taking place,
+ the list of space characters may be different; there may be fewer or
more of them. "Space" used to be different to \s, which did not include
VT, for Perl compatibility. However, Perl changed at release 5.18, and
- PCRE followed at release 8.34. "Space" and \s now match the same set
+ PCRE followed at release 8.34. "Space" and \s now match the same set
of characters.
- The name "word" is a Perl extension, and "blank" is a GNU extension
- from Perl 5.8. Another Perl extension is negation, which is indicated
+ The name "word" is a Perl extension, and "blank" is a GNU extension
+ from Perl 5.8. Another Perl extension is negation, which is indicated
by a ^ character after the colon. For example,
[12[:^digit:]]
- matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the
+ matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the
POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but
these are not supported, and an error is given if they are encountered.
By default, characters with values greater than 128 do not match any of
- the POSIX character classes. However, if the PCRE_UCP option is passed
- to pcre_compile(), some of the classes are changed so that Unicode
- character properties are used. This is achieved by replacing certain
+ the POSIX character classes. However, if the PCRE_UCP option is passed
+ to pcre_compile(), some of the classes are changed so that Unicode
+ character properties are used. This is achieved by replacing certain
POSIX classes by other sequences, as follows:
[:alnum:] becomes \p{Xan}
[:upper:] becomes \p{Lu}
[:word:] becomes \p{Xwd}
- Negated versions, such as [:^alpha:] use \P instead of \p. Three other
+ Negated versions, such as [:^alpha:] use \P instead of \p. Three other
POSIX classes are handled specially in UCP mode:
- [:graph:] This matches characters that have glyphs that mark the page
+ [:graph:] This matches characters that have glyphs that mark the page
when printed. In Unicode property terms, it matches all char-
acters with the L, M, N, P, S, or Cf properties, except for:
U+2066 - U+2069 Various "isolate"s
- [:print:] This matches the same characters as [:graph:] plus space
- characters that are not controls, that is, characters with
+ [:print:] This matches the same characters as [:graph:] plus space
+ characters that are not controls, that is, characters with
the Zs property.
[:punct:] This matches all characters that have the Unicode P (punctua-
- tion) property, plus those characters whose code points are
+ tion) property, plus those characters whose code points are
less than 128 that have the S (Symbol) property.
- The other POSIX classes are unchanged, and match only characters with
+ The other POSIX classes are unchanged, and match only characters with
code points less than 128.
COMPATIBILITY FEATURE FOR WORD BOUNDARIES
- In the POSIX.2 compliant library that was included in 4.4BSD Unix, the
- ugly syntax [[:<:]] and [[:>:]] is used for matching "start of word"
+ In the POSIX.2 compliant library that was included in 4.4BSD Unix, the
+ ugly syntax [[:<:]] and [[:>:]] is used for matching "start of word"
and "end of word". PCRE treats these items as follows:
[[:<:]] is converted to \b(?=\w)
[[:>:]] is converted to \b(?<=\w)
Only these exact character sequences are recognized. A sequence such as
- [a[:<:]b] provokes error for an unrecognized POSIX class name. This
- support is not compatible with Perl. It is provided to help migrations
+ [a[:<:]b] provokes error for an unrecognized POSIX class name. This
+ support is not compatible with Perl. It is provided to help migrations
from other environments, and is best not used in any new patterns. Note
- that \b matches at the start and the end of a word (see "Simple asser-
- tions" above), and in a Perl-style pattern the preceding or following
- character normally shows which is wanted, without the need for the
- assertions that are used above in order to give exactly the POSIX be-
+ that \b matches at the start and the end of a word (see "Simple asser-
+ tions" above), and in a Perl-style pattern the preceding or following
+ character normally shows which is wanted, without the need for the
+ assertions that are used above in order to give exactly the POSIX be-
haviour.
VERTICAL BAR
- Vertical bar characters are used to separate alternative patterns. For
+ Vertical bar characters are used to separate alternative patterns. For
example, the pattern
gilbert|sullivan
- matches either "gilbert" or "sullivan". Any number of alternatives may
- appear, and an empty alternative is permitted (matching the empty
+ matches either "gilbert" or "sullivan". Any number of alternatives may
+ appear, and an empty alternative is permitted (matching the empty
string). The matching process tries each alternative in turn, from left
- to right, and the first one that succeeds is used. If the alternatives
- are within a subpattern (defined below), "succeeds" means matching the
+ to right, and the first one that succeeds is used. If the alternatives
+ are within a subpattern (defined below), "succeeds" means matching the
rest of the main pattern as well as the alternative in the subpattern.
INTERNAL OPTION SETTING
- The settings of the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and
- PCRE_EXTENDED options (which are Perl-compatible) can be changed from
- within the pattern by a sequence of Perl option letters enclosed
+ The settings of the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and
+ PCRE_EXTENDED options (which are Perl-compatible) can be changed from
+ within the pattern by a sequence of Perl option letters enclosed
between "(?" and ")". The option letters are
i for PCRE_CASELESS
For example, (?im) sets caseless, multiline matching. It is also possi-
ble to unset these options by preceding the letter with a hyphen, and a
- combined setting and unsetting such as (?im-sx), which sets PCRE_CASE-
- LESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED,
- is also permitted. If a letter appears both before and after the
+ combined setting and unsetting such as (?im-sx), which sets PCRE_CASE-
+ LESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED,
+ is also permitted. If a letter appears both before and after the
hyphen, the option is unset.
- The PCRE-specific options PCRE_DUPNAMES, PCRE_UNGREEDY, and PCRE_EXTRA
- can be changed in the same way as the Perl-compatible options by using
+ The PCRE-specific options PCRE_DUPNAMES, PCRE_UNGREEDY, and PCRE_EXTRA
+ can be changed in the same way as the Perl-compatible options by using
the characters J, U and X respectively.
- When one of these option changes occurs at top level (that is, not
- inside subpattern parentheses), the change applies to the remainder of
- the pattern that follows. If the change is placed right at the start of
- a pattern, PCRE extracts it into the global options (and it will there-
- fore show up in data extracted by the pcre_fullinfo() function).
-
- An option change within a subpattern (see below for a description of
- subpatterns) affects only that part of the subpattern that follows it,
- so
+ When one of these option changes occurs at top level (that is, not
+ inside subpattern parentheses), the change applies to the remainder of
+ the pattern that follows. An option change within a subpattern (see
+ below for a description of subpatterns) affects only that part of the
+ subpattern that follows it, so
(a(?i)b)c
matches abc and aBc and no other strings (assuming PCRE_CASELESS is not
- used). By this means, options can be made to have different settings
- in different parts of the pattern. Any changes made in one alternative
- do carry on into subsequent branches within the same subpattern. For
+ used). By this means, options can be made to have different settings
+ in different parts of the pattern. Any changes made in one alternative
+ do carry on into subsequent branches within the same subpattern. For
example,
(a(?i)b|c)
- matches "ab", "aB", "c", and "C", even though when matching "C" the
- first branch is abandoned before the option setting. This is because
- the effects of option settings happen at compile time. There would be
+ matches "ab", "aB", "c", and "C", even though when matching "C" the
+ first branch is abandoned before the option setting. This is because
+ the effects of option settings happen at compile time. There would be
some very weird behaviour otherwise.
- Note: There are other PCRE-specific options that can be set by the
- application when the compiling or matching functions are called. In
- some cases the pattern can contain special leading sequences such as
- (*CRLF) to override what the application has set or what has been
- defaulted. Details are given in the section entitled "Newline
- sequences" above. There are also the (*UTF8), (*UTF16),(*UTF32), and
- (*UCP) leading sequences that can be used to set UTF and Unicode prop-
- erty modes; they are equivalent to setting the PCRE_UTF8, PCRE_UTF16,
- PCRE_UTF32 and the PCRE_UCP options, respectively. The (*UTF) sequence
- is a generic version that can be used with any of the libraries. How-
- ever, the application can set the PCRE_NEVER_UTF option, which locks
+ Note: There are other PCRE-specific options that can be set by the
+ application when the compiling or matching functions are called. In
+ some cases the pattern can contain special leading sequences such as
+ (*CRLF) to override what the application has set or what has been
+ defaulted. Details are given in the section entitled "Newline
+ sequences" above. There are also the (*UTF8), (*UTF16),(*UTF32), and
+ (*UCP) leading sequences that can be used to set UTF and Unicode prop-
+ erty modes; they are equivalent to setting the PCRE_UTF8, PCRE_UTF16,
+ PCRE_UTF32 and the PCRE_UCP options, respectively. The (*UTF) sequence
+ is a generic version that can be used with any of the libraries. How-
+ ever, the application can set the PCRE_NEVER_UTF option, which locks
out the use of the (*UTF) sequences.
cat(aract|erpillar|)
- matches "cataract", "caterpillar", or "cat". Without the parentheses,
+ matches "cataract", "caterpillar", or "cat". Without the parentheses,
it would match "cataract", "erpillar" or an empty string.
- 2. It sets up the subpattern as a capturing subpattern. This means
- that, when the whole pattern matches, that portion of the subject
+ 2. It sets up the subpattern as a capturing subpattern. This means
+ that, when the whole pattern matches, that portion of the subject
string that matched the subpattern is passed back to the caller via the
- ovector argument of the matching function. (This applies only to the
- traditional matching functions; the DFA matching functions do not sup-
+ ovector argument of the matching function. (This applies only to the
+ traditional matching functions; the DFA matching functions do not sup-
port capturing.)
Opening parentheses are counted from left to right (starting from 1) to
- obtain numbers for the capturing subpatterns. For example, if the
+ obtain numbers for the capturing subpatterns. For example, if the
string "the red king" is matched against the pattern
the ((red|white) (king|queen))
the captured substrings are "red king", "red", and "king", and are num-
bered 1, 2, and 3, respectively.
- The fact that plain parentheses fulfil two functions is not always
- helpful. There are often times when a grouping subpattern is required
- without a capturing requirement. If an opening parenthesis is followed
- by a question mark and a colon, the subpattern does not do any captur-
- ing, and is not counted when computing the number of any subsequent
- capturing subpatterns. For example, if the string "the white queen" is
+ The fact that plain parentheses fulfil two functions is not always
+ helpful. There are often times when a grouping subpattern is required
+ without a capturing requirement. If an opening parenthesis is followed
+ by a question mark and a colon, the subpattern does not do any captur-
+ ing, and is not counted when computing the number of any subsequent
+ capturing subpatterns. For example, if the string "the white queen" is
matched against the pattern
the ((?:red|white) (king|queen))
the captured substrings are "white queen" and "queen", and are numbered
1 and 2. The maximum number of capturing subpatterns is 65535.
- As a convenient shorthand, if any option settings are required at the
- start of a non-capturing subpattern, the option letters may appear
+ As a convenient shorthand, if any option settings are required at the
+ start of a non-capturing subpattern, the option letters may appear
between the "?" and the ":". Thus the two patterns
(?i:saturday|sunday)
(?:(?i)saturday|sunday)
match exactly the same set of strings. Because alternative branches are
- tried from left to right, and options are not reset until the end of
- the subpattern is reached, an option setting in one branch does affect
- subsequent branches, so the above patterns match "SUNDAY" as well as
+ tried from left to right, and options are not reset until the end of
+ the subpattern is reached, an option setting in one branch does affect
+ subsequent branches, so the above patterns match "SUNDAY" as well as
"Saturday".
DUPLICATE SUBPATTERN NUMBERS
Perl 5.10 introduced a feature whereby each alternative in a subpattern
- uses the same numbers for its capturing parentheses. Such a subpattern
- starts with (?| and is itself a non-capturing subpattern. For example,
+ uses the same numbers for its capturing parentheses. Such a subpattern
+ starts with (?| and is itself a non-capturing subpattern. For example,
consider this pattern:
(?|(Sat)ur|(Sun))day
- Because the two alternatives are inside a (?| group, both sets of cap-
- turing parentheses are numbered one. Thus, when the pattern matches,
- you can look at captured substring number one, whichever alternative
- matched. This construct is useful when you want to capture part, but
+ Because the two alternatives are inside a (?| group, both sets of cap-
+ turing parentheses are numbered one. Thus, when the pattern matches,
+ you can look at captured substring number one, whichever alternative
+ matched. This construct is useful when you want to capture part, but
not all, of one of a number of alternatives. Inside a (?| group, paren-
- theses are numbered as usual, but the number is reset at the start of
- each branch. The numbers of any capturing parentheses that follow the
- subpattern start after the highest number used in any branch. The fol-
+ theses are numbered as usual, but the number is reset at the start of
+ each branch. The numbers of any capturing parentheses that follow the
+ subpattern start after the highest number used in any branch. The fol-
lowing example is taken from the Perl documentation. The numbers under-
neath show in which buffer the captured content will be stored.
/ ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x
# 1 2 2 3 2 3 4
- A back reference to a numbered subpattern uses the most recent value
- that is set for that number by any subpattern. The following pattern
+ A back reference to a numbered subpattern uses the most recent value
+ that is set for that number by any subpattern. The following pattern
matches "abcabc" or "defdef":
/(?|(abc)|(def))\1/
- In contrast, a subroutine call to a numbered subpattern always refers
- to the first one in the pattern with the given number. The following
+ In contrast, a subroutine call to a numbered subpattern always refers
+ to the first one in the pattern with the given number. The following
pattern matches "abcabc" or "defabc":
/(?|(abc)|(def))(?1)/
- If a condition test for a subpattern's having matched refers to a non-
- unique number, the test is true if any of the subpatterns of that num-
+ If a condition test for a subpattern's having matched refers to a non-
+ unique number, the test is true if any of the subpatterns of that num-
ber have matched.
- An alternative approach to using this "branch reset" feature is to use
+ An alternative approach to using this "branch reset" feature is to use
duplicate named subpatterns, as described in the next section.
NAMED SUBPATTERNS
- Identifying capturing parentheses by number is simple, but it can be
- very hard to keep track of the numbers in complicated regular expres-
- sions. Furthermore, if an expression is modified, the numbers may
- change. To help with this difficulty, PCRE supports the naming of sub-
+ Identifying capturing parentheses by number is simple, but it can be
+ very hard to keep track of the numbers in complicated regular expres-
+ sions. Furthermore, if an expression is modified, the numbers may
+ change. To help with this difficulty, PCRE supports the naming of sub-
patterns. This feature was not added to Perl until release 5.10. Python
- had the feature earlier, and PCRE introduced it at release 4.0, using
- the Python syntax. PCRE now supports both the Perl and the Python syn-
- tax. Perl allows identically numbered subpatterns to have different
+ had the feature earlier, and PCRE introduced it at release 4.0, using
+ the Python syntax. PCRE now supports both the Perl and the Python syn-
+ tax. Perl allows identically numbered subpatterns to have different
names, but PCRE does not.
- In PCRE, a subpattern can be named in one of three ways: (?<name>...)
- or (?'name'...) as in Perl, or (?P<name>...) as in Python. References
- to capturing parentheses from other parts of the pattern, such as back
- references, recursion, and conditions, can be made by name as well as
+ In PCRE, a subpattern can be named in one of three ways: (?<name>...)
+ or (?'name'...) as in Perl, or (?P<name>...) as in Python. References
+ to capturing parentheses from other parts of the pattern, such as back
+ references, recursion, and conditions, can be made by name as well as
by number.
- Names consist of up to 32 alphanumeric characters and underscores, but
- must start with a non-digit. Named capturing parentheses are still
- allocated numbers as well as names, exactly as if the names were not
- present. The PCRE API provides function calls for extracting the name-
- to-number translation table from a compiled pattern. There is also a
+ Names consist of up to 32 alphanumeric characters and underscores, but
+ must start with a non-digit. Named capturing parentheses are still
+ allocated numbers as well as names, exactly as if the names were not
+ present. The PCRE API provides function calls for extracting the name-
+ to-number translation table from a compiled pattern. There is also a
convenience function for extracting a captured substring by name.
- By default, a name must be unique within a pattern, but it is possible
+ By default, a name must be unique within a pattern, but it is possible
to relax this constraint by setting the PCRE_DUPNAMES option at compile
- time. (Duplicate names are also always permitted for subpatterns with
- the same number, set up as described in the previous section.) Dupli-
- cate names can be useful for patterns where only one instance of the
- named parentheses can match. Suppose you want to match the name of a
- weekday, either as a 3-letter abbreviation or as the full name, and in
+ time. (Duplicate names are also always permitted for subpatterns with
+ the same number, set up as described in the previous section.) Dupli-
+ cate names can be useful for patterns where only one instance of the
+ named parentheses can match. Suppose you want to match the name of a
+ weekday, either as a 3-letter abbreviation or as the full name, and in
both cases you want to extract the abbreviation. This pattern (ignoring
the line breaks) does the job:
(?<DN>Thu)(?:rsday)?|
(?<DN>Sat)(?:urday)?
- There are five capturing substrings, but only one is ever set after a
+ There are five capturing substrings, but only one is ever set after a
match. (An alternative way of solving this problem is to use a "branch
reset" subpattern, as described in the previous section.)
- The convenience function for extracting the data by name returns the
- substring for the first (and in this example, the only) subpattern of
- that name that matched. This saves searching to find which numbered
+ The convenience function for extracting the data by name returns the
+ substring for the first (and in this example, the only) subpattern of
+ that name that matched. This saves searching to find which numbered
subpattern it was.
- If you make a back reference to a non-unique named subpattern from
- elsewhere in the pattern, the subpatterns to which the name refers are
- checked in the order in which they appear in the overall pattern. The
+ If you make a back reference to a non-unique named subpattern from
+ elsewhere in the pattern, the subpatterns to which the name refers are
+ checked in the order in which they appear in the overall pattern. The
first one that is set is used for the reference. For example, this pat-
tern matches both "foofoo" and "barbar" but not "foobar" or "barfoo":
If you make a subroutine call to a non-unique named subpattern, the one
- that corresponds to the first occurrence of the name is used. In the
+ that corresponds to the first occurrence of the name is used. In the
absence of duplicate numbers (see the previous section) this is the one
with the lowest number.
If you use a named reference in a condition test (see the section about
conditions below), either to check whether a subpattern has matched, or
- to check for recursion, all subpatterns with the same name are tested.
- If the condition is true for any one of them, the overall condition is
- true. This is the same behaviour as testing by number. For further
- details of the interfaces for handling named subpatterns, see the
+ to check for recursion, all subpatterns with the same name are tested.
+ If the condition is true for any one of them, the overall condition is
+ true. This is the same behaviour as testing by number. For further
+ details of the interfaces for handling named subpatterns, see the
pcreapi documentation.
Warning: You cannot use different names to distinguish between two sub-
- patterns with the same number because PCRE uses only the numbers when
+ patterns with the same number because PCRE uses only the numbers when
matching. For this reason, an error is given at compile time if differ-
- ent names are given to subpatterns with the same number. However, you
+ ent names are given to subpatterns with the same number. However, you
can always give the same name to subpatterns with the same number, even
when PCRE_DUPNAMES is not set.
REPETITION
- Repetition is specified by quantifiers, which can follow any of the
+ Repetition is specified by quantifiers, which can follow any of the
following items:
a literal data character
a parenthesized subpattern (including assertions)
a subroutine call to a subpattern (recursive or otherwise)
- The general repetition quantifier specifies a minimum and maximum num-
- ber of permitted matches, by giving the two numbers in curly brackets
- (braces), separated by a comma. The numbers must be less than 65536,
+ The general repetition quantifier specifies a minimum and maximum num-
+ ber of permitted matches, by giving the two numbers in curly brackets
+ (braces), separated by a comma. The numbers must be less than 65536,
and the first must be less than or equal to the second. For example:
z{2,4}
- matches "zz", "zzz", or "zzzz". A closing brace on its own is not a
- special character. If the second number is omitted, but the comma is
- present, there is no upper limit; if the second number and the comma
- are both omitted, the quantifier specifies an exact number of required
+ matches "zz", "zzz", or "zzzz". A closing brace on its own is not a
+ special character. If the second number is omitted, but the comma is
+ present, there is no upper limit; if the second number and the comma
+ are both omitted, the quantifier specifies an exact number of required
matches. Thus
[aeiou]{3,}
\d{8}
- matches exactly 8 digits. An opening curly bracket that appears in a
- position where a quantifier is not allowed, or one that does not match
- the syntax of a quantifier, is taken as a literal character. For exam-
+ matches exactly 8 digits. An opening curly bracket that appears in a
+ position where a quantifier is not allowed, or one that does not match
+ the syntax of a quantifier, is taken as a literal character. For exam-
ple, {,6} is not a quantifier, but a literal string of four characters.
In UTF modes, quantifiers apply to characters rather than to individual
- data units. Thus, for example, \x{100}{2} matches two characters, each
+ data units. Thus, for example, \x{100}{2} matches two characters, each
of which is represented by a two-byte sequence in a UTF-8 string. Simi-
- larly, \X{3} matches three Unicode extended grapheme clusters, each of
- which may be several data units long (and they may be of different
+ larly, \X{3} matches three Unicode extended grapheme clusters, each of
+ which may be several data units long (and they may be of different
lengths).
The quantifier {0} is permitted, causing the expression to behave as if
the previous item and the quantifier were not present. This may be use-
- ful for subpatterns that are referenced as subroutines from elsewhere
+ ful for subpatterns that are referenced as subroutines from elsewhere
in the pattern (but see also the section entitled "Defining subpatterns
- for use by reference only" below). Items other than subpatterns that
+ for use by reference only" below). Items other than subpatterns that
have a {0} quantifier are omitted from the compiled pattern.
- For convenience, the three most common quantifiers have single-charac-
+ For convenience, the three most common quantifiers have single-charac-
ter abbreviations:
* is equivalent to {0,}
+ is equivalent to {1,}
? is equivalent to {0,1}
- It is possible to construct infinite loops by following a subpattern
+ It is possible to construct infinite loops by following a subpattern
that can match no characters with a quantifier that has no upper limit,
for example:
(a?)*
Earlier versions of Perl and PCRE used to give an error at compile time
- for such patterns. However, because there are cases where this can be
- useful, such patterns are now accepted, but if any repetition of the
- subpattern does in fact match no characters, the loop is forcibly bro-
+ for such patterns. However, because there are cases where this can be
+ useful, such patterns are now accepted, but if any repetition of the
+ subpattern does in fact match no characters, the loop is forcibly bro-
ken.
- By default, the quantifiers are "greedy", that is, they match as much
- as possible (up to the maximum number of permitted times), without
- causing the rest of the pattern to fail. The classic example of where
+ By default, the quantifiers are "greedy", that is, they match as much
+ as possible (up to the maximum number of permitted times), without
+ causing the rest of the pattern to fail. The classic example of where
this gives problems is in trying to match comments in C programs. These
- appear between /* and */ and within the comment, individual * and /
- characters may appear. An attempt to match C comments by applying the
+ appear between /* and */ and within the comment, individual * and /
+ characters may appear. An attempt to match C comments by applying the
pattern
/\*.*\*/
/* first comment */ not comment /* second comment */
- fails, because it matches the entire string owing to the greediness of
+ fails, because it matches the entire string owing to the greediness of
the .* item.
- However, if a quantifier is followed by a question mark, it ceases to
+ However, if a quantifier is followed by a question mark, it ceases to
be greedy, and instead matches the minimum number of times possible, so
the pattern
/\*.*?\*/
- does the right thing with the C comments. The meaning of the various
- quantifiers is not otherwise changed, just the preferred number of
- matches. Do not confuse this use of question mark with its use as a
- quantifier in its own right. Because it has two uses, it can sometimes
+ does the right thing with the C comments. The meaning of the various
+ quantifiers is not otherwise changed, just the preferred number of
+ matches. Do not confuse this use of question mark with its use as a
+ quantifier in its own right. Because it has two uses, it can sometimes
appear doubled, as in
\d??\d
which matches one digit by preference, but can match two if that is the
only way the rest of the pattern matches.
- If the PCRE_UNGREEDY option is set (an option that is not available in
- Perl), the quantifiers are not greedy by default, but individual ones
- can be made greedy by following them with a question mark. In other
+ If the PCRE_UNGREEDY option is set (an option that is not available in
+ Perl), the quantifiers are not greedy by default, but individual ones
+ can be made greedy by following them with a question mark. In other
words, it inverts the default behaviour.
- When a parenthesized subpattern is quantified with a minimum repeat
- count that is greater than 1 or with a limited maximum, more memory is
- required for the compiled pattern, in proportion to the size of the
+ When a parenthesized subpattern is quantified with a minimum repeat
+ count that is greater than 1 or with a limited maximum, more memory is
+ required for the compiled pattern, in proportion to the size of the
minimum or maximum.
If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equiv-
- alent to Perl's /s) is set, thus allowing the dot to match newlines,
- the pattern is implicitly anchored, because whatever follows will be
- tried against every character position in the subject string, so there
- is no point in retrying the overall match at any position after the
- first. PCRE normally treats such a pattern as though it were preceded
+ alent to Perl's /s) is set, thus allowing the dot to match newlines,
+ the pattern is implicitly anchored, because whatever follows will be
+ tried against every character position in the subject string, so there
+ is no point in retrying the overall match at any position after the
+ first. PCRE normally treats such a pattern as though it were preceded
by \A.
- In cases where it is known that the subject string contains no new-
- lines, it is worth setting PCRE_DOTALL in order to obtain this opti-
+ In cases where it is known that the subject string contains no new-
+ lines, it is worth setting PCRE_DOTALL in order to obtain this opti-
mization, or alternatively using ^ to indicate anchoring explicitly.
- However, there are some cases where the optimization cannot be used.
+ However, there are some cases where the optimization cannot be used.
When .* is inside capturing parentheses that are the subject of a back
reference elsewhere in the pattern, a match at the start may fail where
a later one succeeds. Consider, for example:
(.*)abc\1
- If the subject is "xyz123abc123" the match point is the fourth charac-
+ If the subject is "xyz123abc123" the match point is the fourth charac-
ter. For this reason, such a pattern is not implicitly anchored.
- Another case where implicit anchoring is not applied is when the lead-
- ing .* is inside an atomic group. Once again, a match at the start may
+ Another case where implicit anchoring is not applied is when the lead-
+ ing .* is inside an atomic group. Once again, a match at the start may
fail where a later one succeeds. Consider this pattern:
(?>.*?a)b
- It matches "ab" in the subject "aab". The use of the backtracking con-
+ It matches "ab" in the subject "aab". The use of the backtracking con-
trol verbs (*PRUNE) and (*SKIP) also disable this optimization.
When a capturing subpattern is repeated, the value captured is the sub-
(tweedle[dume]{3}\s*)+
has matched "tweedledum tweedledee" the value of the captured substring
- is "tweedledee". However, if there are nested capturing subpatterns,
- the corresponding captured values may have been set in previous itera-
+ is "tweedledee". However, if there are nested capturing subpatterns,
+ the corresponding captured values may have been set in previous itera-
tions. For example, after
/(a|(b))+/
ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS
- With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy")
- repetition, failure of what follows normally causes the repeated item
- to be re-evaluated to see if a different number of repeats allows the
- rest of the pattern to match. Sometimes it is useful to prevent this,
- either to change the nature of the match, or to cause it fail earlier
- than it otherwise might, when the author of the pattern knows there is
+ With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy")
+ repetition, failure of what follows normally causes the repeated item
+ to be re-evaluated to see if a different number of repeats allows the
+ rest of the pattern to match. Sometimes it is useful to prevent this,
+ either to change the nature of the match, or to cause it fail earlier
+ than it otherwise might, when the author of the pattern knows there is
no point in carrying on.
- Consider, for example, the pattern \d+foo when applied to the subject
+ Consider, for example, the pattern \d+foo when applied to the subject
line
123456bar
After matching all 6 digits and then failing to match "foo", the normal
- action of the matcher is to try again with only 5 digits matching the
- \d+ item, and then with 4, and so on, before ultimately failing.
- "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides
- the means for specifying that once a subpattern has matched, it is not
+ action of the matcher is to try again with only 5 digits matching the
+ \d+ item, and then with 4, and so on, before ultimately failing.
+ "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides
+ the means for specifying that once a subpattern has matched, it is not
to be re-evaluated in this way.
- If we use atomic grouping for the previous example, the matcher gives
- up immediately on failing to match "foo" the first time. The notation
+ If we use atomic grouping for the previous example, the matcher gives
+ up immediately on failing to match "foo" the first time. The notation
is a kind of special parenthesis, starting with (?> as in this example:
(?>\d+)foo
- This kind of parenthesis "locks up" the part of the pattern it con-
- tains once it has matched, and a failure further into the pattern is
- prevented from backtracking into it. Backtracking past it to previous
+ This kind of parenthesis "locks up" the part of the pattern it con-
+ tains once it has matched, and a failure further into the pattern is
+ prevented from backtracking into it. Backtracking past it to previous
items, however, works as normal.
- An alternative description is that a subpattern of this type matches
- the string of characters that an identical standalone pattern would
+ An alternative description is that a subpattern of this type matches
+ the string of characters that an identical standalone pattern would
match, if anchored at the current point in the subject string.
Atomic grouping subpatterns are not capturing subpatterns. Simple cases
such as the above example can be thought of as a maximizing repeat that
- must swallow everything it can. So, while both \d+ and \d+? are pre-
- pared to adjust the number of digits they match in order to make the
+ must swallow everything it can. So, while both \d+ and \d+? are pre-
+ pared to adjust the number of digits they match in order to make the
rest of the pattern match, (?>\d+) can only match an entire sequence of
digits.
- Atomic groups in general can of course contain arbitrarily complicated
- subpatterns, and can be nested. However, when the subpattern for an
+ Atomic groups in general can of course contain arbitrarily complicated
+ subpatterns, and can be nested. However, when the subpattern for an
atomic group is just a single repeated item, as in the example above, a
- simpler notation, called a "possessive quantifier" can be used. This
- consists of an additional + character following a quantifier. Using
+ simpler notation, called a "possessive quantifier" can be used. This
+ consists of an additional + character following a quantifier. Using
this notation, the previous example can be rewritten as
\d++foo
(abc|xyz){2,3}+
- Possessive quantifiers are always greedy; the setting of the
+ Possessive quantifiers are always greedy; the setting of the
PCRE_UNGREEDY option is ignored. They are a convenient notation for the
- simpler forms of atomic group. However, there is no difference in the
- meaning of a possessive quantifier and the equivalent atomic group,
- though there may be a performance difference; possessive quantifiers
+ simpler forms of atomic group. However, there is no difference in the
+ meaning of a possessive quantifier and the equivalent atomic group,
+ though there may be a performance difference; possessive quantifiers
should be slightly faster.
- The possessive quantifier syntax is an extension to the Perl 5.8 syn-
- tax. Jeffrey Friedl originated the idea (and the name) in the first
+ The possessive quantifier syntax is an extension to the Perl 5.8 syn-
+ tax. Jeffrey Friedl originated the idea (and the name) in the first
edition of his book. Mike McCloskey liked it, so implemented it when he
- built Sun's Java package, and PCRE copied it from there. It ultimately
+ built Sun's Java package, and PCRE copied it from there. It ultimately
found its way into Perl at release 5.10.
PCRE has an optimization that automatically "possessifies" certain sim-
- ple pattern constructs. For example, the sequence A+B is treated as
- A++B because there is no point in backtracking into a sequence of A's
+ ple pattern constructs. For example, the sequence A+B is treated as
+ A++B because there is no point in backtracking into a sequence of A's
when B must follow.
- When a pattern contains an unlimited repeat inside a subpattern that
- can itself be repeated an unlimited number of times, the use of an
- atomic group is the only way to avoid some failing matches taking a
+ When a pattern contains an unlimited repeat inside a subpattern that
+ can itself be repeated an unlimited number of times, the use of an
+ atomic group is the only way to avoid some failing matches taking a
very long time indeed. The pattern
(\D+|<\d+>)*[!?]
- matches an unlimited number of substrings that either consist of non-
- digits, or digits enclosed in <>, followed by either ! or ?. When it
+ matches an unlimited number of substrings that either consist of non-
+ digits, or digits enclosed in <>, followed by either ! or ?. When it
matches, it runs quickly. However, if it is applied to
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- it takes a long time before reporting failure. This is because the
- string can be divided between the internal \D+ repeat and the external
- * repeat in a large number of ways, and all have to be tried. (The
- example uses [!?] rather than a single character at the end, because
- both PCRE and Perl have an optimization that allows for fast failure
- when a single character is used. They remember the last single charac-
- ter that is required for a match, and fail early if it is not present
- in the string.) If the pattern is changed so that it uses an atomic
+ it takes a long time before reporting failure. This is because the
+ string can be divided between the internal \D+ repeat and the external
+ * repeat in a large number of ways, and all have to be tried. (The
+ example uses [!?] rather than a single character at the end, because
+ both PCRE and Perl have an optimization that allows for fast failure
+ when a single character is used. They remember the last single charac-
+ ter that is required for a match, and fail early if it is not present
+ in the string.) If the pattern is changed so that it uses an atomic
group, like this:
((?>\D+)|<\d+>)*[!?]
Outside a character class, a backslash followed by a digit greater than
0 (and possibly further digits) is a back reference to a capturing sub-
- pattern earlier (that is, to its left) in the pattern, provided there
+ pattern earlier (that is, to its left) in the pattern, provided there
have been that many previous capturing left parentheses.
However, if the decimal number following the backslash is less than 10,
- it is always taken as a back reference, and causes an error only if
- there are not that many capturing left parentheses in the entire pat-
- tern. In other words, the parentheses that are referenced need not be
- to the left of the reference for numbers less than 10. A "forward back
- reference" of this type can make sense when a repetition is involved
- and the subpattern to the right has participated in an earlier itera-
+ it is always taken as a back reference, and causes an error only if
+ there are not that many capturing left parentheses in the entire pat-
+ tern. In other words, the parentheses that are referenced need not be
+ to the left of the reference for numbers less than 10. A "forward back
+ reference" of this type can make sense when a repetition is involved
+ and the subpattern to the right has participated in an earlier itera-
tion.
- It is not possible to have a numerical "forward back reference" to a
- subpattern whose number is 10 or more using this syntax because a
- sequence such as \50 is interpreted as a character defined in octal.
+ It is not possible to have a numerical "forward back reference" to a
+ subpattern whose number is 10 or more using this syntax because a
+ sequence such as \50 is interpreted as a character defined in octal.
See the subsection entitled "Non-printing characters" above for further
- details of the handling of digits following a backslash. There is no
- such problem when named parentheses are used. A back reference to any
+ details of the handling of digits following a backslash. There is no
+ such problem when named parentheses are used. A back reference to any
subpattern is possible using named parentheses (see below).
- Another way of avoiding the ambiguity inherent in the use of digits
- following a backslash is to use the \g escape sequence. This escape
+ Another way of avoiding the ambiguity inherent in the use of digits
+ following a backslash is to use the \g escape sequence. This escape
must be followed by an unsigned number or a negative number, optionally
enclosed in braces. These examples are all identical:
(ring), \g1
(ring), \g{1}
- An unsigned number specifies an absolute reference without the ambigu-
+ An unsigned number specifies an absolute reference without the ambigu-
ity that is present in the older syntax. It is also useful when literal
digits follow the reference. A negative number is a relative reference.
Consider this example:
The sequence \g{-1} is a reference to the most recently started captur-
ing subpattern before \g, that is, is it equivalent to \2 in this exam-
- ple. Similarly, \g{-2} would be equivalent to \1. The use of relative
- references can be helpful in long patterns, and also in patterns that
- are created by joining together fragments that contain references
+ ple. Similarly, \g{-2} would be equivalent to \1. The use of relative
+ references can be helpful in long patterns, and also in patterns that
+ are created by joining together fragments that contain references
within themselves.
- A back reference matches whatever actually matched the capturing sub-
- pattern in the current subject string, rather than anything matching
+ A back reference matches whatever actually matched the capturing sub-
+ pattern in the current subject string, rather than anything matching
the subpattern itself (see "Subpatterns as subroutines" below for a way
of doing that). So the pattern
(sens|respons)e and \1ibility
- matches "sense and sensibility" and "response and responsibility", but
- not "sense and responsibility". If caseful matching is in force at the
- time of the back reference, the case of letters is relevant. For exam-
+ matches "sense and sensibility" and "response and responsibility", but
+ not "sense and responsibility". If caseful matching is in force at the
+ time of the back reference, the case of letters is relevant. For exam-
ple,
((?i)rah)\s+\1
- matches "rah rah" and "RAH RAH", but not "RAH rah", even though the
+ matches "rah rah" and "RAH RAH", but not "RAH rah", even though the
original capturing subpattern is matched caselessly.
- There are several different ways of writing back references to named
- subpatterns. The .NET syntax \k{name} and the Perl syntax \k<name> or
- \k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's
+ There are several different ways of writing back references to named
+ subpatterns. The .NET syntax \k{name} and the Perl syntax \k<name> or
+ \k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's
unified back reference syntax, in which \g can be used for both numeric
- and named references, is also supported. We could rewrite the above
+ and named references, is also supported. We could rewrite the above
example in any of the following ways:
(?<p1>(?i)rah)\s+\k<p1>
(?P<p1>(?i)rah)\s+(?P=p1)
(?<p1>(?i)rah)\s+\g{p1}
- A subpattern that is referenced by name may appear in the pattern
+ A subpattern that is referenced by name may appear in the pattern
before or after the reference.
- There may be more than one back reference to the same subpattern. If a
- subpattern has not actually been used in a particular match, any back
+ There may be more than one back reference to the same subpattern. If a
+ subpattern has not actually been used in a particular match, any back
references to it always fail by default. For example, the pattern
(a|(bc))\2
- always fails if it starts to match "a" rather than "bc". However, if
+ always fails if it starts to match "a" rather than "bc". However, if
the PCRE_JAVASCRIPT_COMPAT option is set at compile time, a back refer-
ence to an unset value matches an empty string.
- Because there may be many capturing parentheses in a pattern, all dig-
- its following a backslash are taken as part of a potential back refer-
- ence number. If the pattern continues with a digit character, some
- delimiter must be used to terminate the back reference. If the
- PCRE_EXTENDED option is set, this can be white space. Otherwise, the
+ Because there may be many capturing parentheses in a pattern, all dig-
+ its following a backslash are taken as part of a potential back refer-
+ ence number. If the pattern continues with a digit character, some
+ delimiter must be used to terminate the back reference. If the
+ PCRE_EXTENDED option is set, this can be white space. Otherwise, the
\g{ syntax or an empty comment (see "Comments" below) can be used.
Recursive back references
- A back reference that occurs inside the parentheses to which it refers
- fails when the subpattern is first used, so, for example, (a\1) never
- matches. However, such references can be useful inside repeated sub-
+ A back reference that occurs inside the parentheses to which it refers
+ fails when the subpattern is first used, so, for example, (a\1) never
+ matches. However, such references can be useful inside repeated sub-
patterns. For example, the pattern
(a|b\1)+
matches any number of "a"s and also "aba", "ababbaa" etc. At each iter-
- ation of the subpattern, the back reference matches the character
- string corresponding to the previous iteration. In order for this to
- work, the pattern must be such that the first iteration does not need
- to match the back reference. This can be done using alternation, as in
+ ation of the subpattern, the back reference matches the character
+ string corresponding to the previous iteration. In order for this to
+ work, the pattern must be such that the first iteration does not need
+ to match the back reference. This can be done using alternation, as in
the example above, or by a quantifier with a minimum of zero.
- Back references of this type cause the group that they reference to be
- treated as an atomic group. Once the whole group has been matched, a
- subsequent matching failure cannot cause backtracking into the middle
+ Back references of this type cause the group that they reference to be
+ treated as an atomic group. Once the whole group has been matched, a
+ subsequent matching failure cannot cause backtracking into the middle
of the group.
ASSERTIONS
- An assertion is a test on the characters following or preceding the
- current matching point that does not actually consume any characters.
- The simple assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are
+ An assertion is a test on the characters following or preceding the
+ current matching point that does not actually consume any characters.
+ The simple assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are
described above.
- More complicated assertions are coded as subpatterns. There are two
- kinds: those that look ahead of the current position in the subject
- string, and those that look behind it. An assertion subpattern is
- matched in the normal way, except that it does not cause the current
+ More complicated assertions are coded as subpatterns. There are two
+ kinds: those that look ahead of the current position in the subject
+ string, and those that look behind it. An assertion subpattern is
+ matched in the normal way, except that it does not cause the current
matching position to be changed.
- Assertion subpatterns are not capturing subpatterns. If such an asser-
- tion contains capturing subpatterns within it, these are counted for
- the purposes of numbering the capturing subpatterns in the whole pat-
- tern. However, substring capturing is carried out only for positive
+ Assertion subpatterns are not capturing subpatterns. If such an asser-
+ tion contains capturing subpatterns within it, these are counted for
+ the purposes of numbering the capturing subpatterns in the whole pat-
+ tern. However, substring capturing is carried out only for positive
assertions. (Perl sometimes, but not always, does do capturing in nega-
tive assertions.)
- For compatibility with Perl, assertion subpatterns may be repeated;
- though it makes no sense to assert the same thing several times, the
- side effect of capturing parentheses may occasionally be useful. In
+ WARNING: If a positive assertion containing one or more capturing sub-
+ patterns succeeds, but failure to match later in the pattern causes
+ backtracking over this assertion, the captures within the assertion are
+ reset only if no higher numbered captures are already set. This is,
+ unfortunately, a fundamental limitation of the current implementation,
+ and as PCRE1 is now in maintenance-only status, it is unlikely ever to
+ change.
+
+ For compatibility with Perl, assertion subpatterns may be repeated;
+ though it makes no sense to assert the same thing several times, the
+ side effect of capturing parentheses may occasionally be useful. In
practice, there only three cases:
- (1) If the quantifier is {0}, the assertion is never obeyed during
- matching. However, it may contain internal capturing parenthesized
+ (1) If the quantifier is {0}, the assertion is never obeyed during
+ matching. However, it may contain internal capturing parenthesized
groups that are called from elsewhere via the subroutine mechanism.
- (2) If quantifier is {0,n} where n is greater than zero, it is treated
- as if it were {0,1}. At run time, the rest of the pattern match is
+ (2) If quantifier is {0,n} where n is greater than zero, it is treated
+ as if it were {0,1}. At run time, the rest of the pattern match is
tried with and without the assertion, the order depending on the greed-
iness of the quantifier.
- (3) If the minimum repetition is greater than zero, the quantifier is
- ignored. The assertion is obeyed just once when encountered during
+ (3) If the minimum repetition is greater than zero, the quantifier is
+ ignored. The assertion is obeyed just once when encountered during
matching.
Lookahead assertions
\w+(?=;)
- matches a word followed by a semicolon, but does not include the semi-
+ matches a word followed by a semicolon, but does not include the semi-
colon in the match, and
foo(?!bar)
- matches any occurrence of "foo" that is not followed by "bar". Note
+ matches any occurrence of "foo" that is not followed by "bar". Note
that the apparently similar pattern
(?!foo)bar
- does not find an occurrence of "bar" that is preceded by something
- other than "foo"; it finds any occurrence of "bar" whatsoever, because
+ does not find an occurrence of "bar" that is preceded by something
+ other than "foo"; it finds any occurrence of "bar" whatsoever, because
the assertion (?!foo) is always true when the next three characters are
"bar". A lookbehind assertion is needed to achieve the other effect.
If you want to force a matching failure at some point in a pattern, the
- most convenient way to do it is with (?!) because an empty string
- always matches, so an assertion that requires there not to be an empty
+ most convenient way to do it is with (?!) because an empty string
+ always matches, so an assertion that requires there not to be an empty
string must always fail. The backtracking control verb (*FAIL) or (*F)
is a synonym for (?!).
Lookbehind assertions
- Lookbehind assertions start with (?<= for positive assertions and (?<!
+ Lookbehind assertions start with (?<= for positive assertions and (?<!
for negative assertions. For example,
(?<!foo)bar
- does find an occurrence of "bar" that is not preceded by "foo". The
- contents of a lookbehind assertion are restricted such that all the
+ does find an occurrence of "bar" that is not preceded by "foo". The
+ contents of a lookbehind assertion are restricted such that all the
strings it matches must have a fixed length. However, if there are sev-
- eral top-level alternatives, they do not all have to have the same
+ eral top-level alternatives, they do not all have to have the same
fixed length. Thus
(?<=bullock|donkey)
(?<!dogs?|cats?)
- causes an error at compile time. Branches that match different length
- strings are permitted only at the top level of a lookbehind assertion.
+ causes an error at compile time. Branches that match different length
+ strings are permitted only at the top level of a lookbehind assertion.
This is an extension compared with Perl, which requires all branches to
match the same length of string. An assertion such as
(?<=ab(c|de))
- is not permitted, because its single top-level branch can match two
+ is not permitted, because its single top-level branch can match two
different lengths, but it is acceptable to PCRE if rewritten to use two
top-level branches:
(?<=abc|abde)
- In some cases, the escape sequence \K (see above) can be used instead
+ In some cases, the escape sequence \K (see above) can be used instead
of a lookbehind assertion to get round the fixed-length restriction.
- The implementation of lookbehind assertions is, for each alternative,
- to temporarily move the current position back by the fixed length and
+ The implementation of lookbehind assertions is, for each alternative,
+ to temporarily move the current position back by the fixed length and
then try to match. If there are insufficient characters before the cur-
rent position, the assertion fails.
- In a UTF mode, PCRE does not allow the \C escape (which matches a sin-
- gle data unit even in a UTF mode) to appear in lookbehind assertions,
- because it makes it impossible to calculate the length of the lookbe-
- hind. The \X and \R escapes, which can match different numbers of data
+ In a UTF mode, PCRE does not allow the \C escape (which matches a sin-
+ gle data unit even in a UTF mode) to appear in lookbehind assertions,
+ because it makes it impossible to calculate the length of the lookbe-
+ hind. The \X and \R escapes, which can match different numbers of data
units, are also not permitted.
- "Subroutine" calls (see below) such as (?2) or (?&X) are permitted in
- lookbehinds, as long as the subpattern matches a fixed-length string.
+ "Subroutine" calls (see below) such as (?2) or (?&X) are permitted in
+ lookbehinds, as long as the subpattern matches a fixed-length string.
Recursion, however, is not supported.
- Possessive quantifiers can be used in conjunction with lookbehind
+ Possessive quantifiers can be used in conjunction with lookbehind
assertions to specify efficient matching of fixed-length strings at the
end of subject strings. Consider a simple pattern such as
abcd$
- when applied to a long string that does not match. Because matching
+ when applied to a long string that does not match. Because matching
proceeds from left to right, PCRE will look for each "a" in the subject
- and then see if what follows matches the rest of the pattern. If the
+ and then see if what follows matches the rest of the pattern. If the
pattern is specified as
^.*abcd$
- the initial .* matches the entire string at first, but when this fails
+ the initial .* matches the entire string at first, but when this fails
(because there is no following "a"), it backtracks to match all but the
- last character, then all but the last two characters, and so on. Once
- again the search for "a" covers the entire string, from right to left,
+ last character, then all but the last two characters, and so on. Once
+ again the search for "a" covers the entire string, from right to left,
so we are no better off. However, if the pattern is written as
^.*+(?<=abcd)
- there can be no backtracking for the .*+ item; it can match only the
- entire string. The subsequent lookbehind assertion does a single test
- on the last four characters. If it fails, the match fails immediately.
- For long strings, this approach makes a significant difference to the
+ there can be no backtracking for the .*+ item; it can match only the
+ entire string. The subsequent lookbehind assertion does a single test
+ on the last four characters. If it fails, the match fails immediately.
+ For long strings, this approach makes a significant difference to the
processing time.
Using multiple assertions
(?<=\d{3})(?<!999)foo
- matches "foo" preceded by three digits that are not "999". Notice that
- each of the assertions is applied independently at the same point in
- the subject string. First there is a check that the previous three
- characters are all digits, and then there is a check that the same
+ matches "foo" preceded by three digits that are not "999". Notice that
+ each of the assertions is applied independently at the same point in
+ the subject string. First there is a check that the previous three
+ characters are all digits, and then there is a check that the same
three characters are not "999". This pattern does not match "foo" pre-
- ceded by six characters, the first of which are digits and the last
- three of which are not "999". For example, it doesn't match "123abc-
+ ceded by six characters, the first of which are digits and the last
+ three of which are not "999". For example, it doesn't match "123abc-
foo". A pattern to do that is
(?<=\d{3}...)(?<!999)foo
- This time the first assertion looks at the preceding six characters,
+ This time the first assertion looks at the preceding six characters,
checking that the first three are digits, and then the second assertion
checks that the preceding three characters are not "999".
(?<=(?<!foo)bar)baz
- matches an occurrence of "baz" that is preceded by "bar" which in turn
+ matches an occurrence of "baz" that is preceded by "bar" which in turn
is not preceded by "foo", while
(?<=\d{3}(?!999)...)foo
- is another pattern that matches "foo" preceded by three digits and any
+ is another pattern that matches "foo" preceded by three digits and any
three characters that are not "999".
CONDITIONAL SUBPATTERNS
- It is possible to cause the matching process to obey a subpattern con-
- ditionally or to choose between two alternative subpatterns, depending
- on the result of an assertion, or whether a specific capturing subpat-
- tern has already been matched. The two possible forms of conditional
+ It is possible to cause the matching process to obey a subpattern con-
+ ditionally or to choose between two alternative subpatterns, depending
+ on the result of an assertion, or whether a specific capturing subpat-
+ tern has already been matched. The two possible forms of conditional
subpattern are:
(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)
- If the condition is satisfied, the yes-pattern is used; otherwise the
- no-pattern (if present) is used. If there are more than two alterna-
- tives in the subpattern, a compile-time error occurs. Each of the two
+ If the condition is satisfied, the yes-pattern is used; otherwise the
+ no-pattern (if present) is used. If there are more than two alterna-
+ tives in the subpattern, a compile-time error occurs. Each of the two
alternatives may itself contain nested subpatterns of any form, includ-
ing conditional subpatterns; the restriction to two alternatives
applies only at the level of the condition. This pattern fragment is an
(?(1) (A|B|C) | (D | (?(2)E|F) | E) )
- There are four kinds of condition: references to subpatterns, refer-
+ There are four kinds of condition: references to subpatterns, refer-
ences to recursion, a pseudo-condition called DEFINE, and assertions.
Checking for a used subpattern by number
- If the text between the parentheses consists of a sequence of digits,
+ If the text between the parentheses consists of a sequence of digits,
the condition is true if a capturing subpattern of that number has pre-
- viously matched. If there is more than one capturing subpattern with
- the same number (see the earlier section about duplicate subpattern
- numbers), the condition is true if any of them have matched. An alter-
- native notation is to precede the digits with a plus or minus sign. In
- this case, the subpattern number is relative rather than absolute. The
- most recently opened parentheses can be referenced by (?(-1), the next
- most recent by (?(-2), and so on. Inside loops it can also make sense
+ viously matched. If there is more than one capturing subpattern with
+ the same number (see the earlier section about duplicate subpattern
+ numbers), the condition is true if any of them have matched. An alter-
+ native notation is to precede the digits with a plus or minus sign. In
+ this case, the subpattern number is relative rather than absolute. The
+ most recently opened parentheses can be referenced by (?(-1), the next
+ most recent by (?(-2), and so on. Inside loops it can also make sense
to refer to subsequent groups. The next parentheses to be opened can be
- referenced as (?(+1), and so on. (The value zero in any of these forms
+ referenced as (?(+1), and so on. (The value zero in any of these forms
is not used; it provokes a compile-time error.)
- Consider the following pattern, which contains non-significant white
+ Consider the following pattern, which contains non-significant white
space to make it more readable (assume the PCRE_EXTENDED option) and to
divide it into three parts for ease of discussion:
( \( )? [^()]+ (?(1) \) )
- The first part matches an optional opening parenthesis, and if that
+ The first part matches an optional opening parenthesis, and if that
character is present, sets it as the first captured substring. The sec-
- ond part matches one or more characters that are not parentheses. The
- third part is a conditional subpattern that tests whether or not the
- first set of parentheses matched. If they did, that is, if subject
- started with an opening parenthesis, the condition is true, and so the
- yes-pattern is executed and a closing parenthesis is required. Other-
- wise, since no-pattern is not present, the subpattern matches nothing.
- In other words, this pattern matches a sequence of non-parentheses,
+ ond part matches one or more characters that are not parentheses. The
+ third part is a conditional subpattern that tests whether or not the
+ first set of parentheses matched. If they did, that is, if subject
+ started with an opening parenthesis, the condition is true, and so the
+ yes-pattern is executed and a closing parenthesis is required. Other-
+ wise, since no-pattern is not present, the subpattern matches nothing.
+ In other words, this pattern matches a sequence of non-parentheses,
optionally enclosed in parentheses.
- If you were embedding this pattern in a larger one, you could use a
+ If you were embedding this pattern in a larger one, you could use a
relative reference:
...other stuff... ( \( )? [^()]+ (?(-1) \) ) ...
- This makes the fragment independent of the parentheses in the larger
+ This makes the fragment independent of the parentheses in the larger
pattern.
Checking for a used subpattern by name
- Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a
- used subpattern by name. For compatibility with earlier versions of
- PCRE, which had this facility before Perl, the syntax (?(name)...) is
+ Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a
+ used subpattern by name. For compatibility with earlier versions of
+ PCRE, which had this facility before Perl, the syntax (?(name)...) is
also recognized.
Rewriting the above example to use a named subpattern gives this:
(?<OPEN> \( )? [^()]+ (?(<OPEN>) \) )
- If the name used in a condition of this kind is a duplicate, the test
- is applied to all subpatterns of the same name, and is true if any one
+ If the name used in a condition of this kind is a duplicate, the test
+ is applied to all subpatterns of the same name, and is true if any one
of them has matched.
Checking for pattern recursion
If the condition is the string (R), and there is no subpattern with the
- name R, the condition is true if a recursive call to the whole pattern
+ name R, the condition is true if a recursive call to the whole pattern
or any subpattern has been made. If digits or a name preceded by amper-
sand follow the letter R, for example:
the condition is true if the most recent recursion is into a subpattern
whose number or name is given. This condition does not check the entire
- recursion stack. If the name used in a condition of this kind is a
+ recursion stack. If the name used in a condition of this kind is a
duplicate, the test is applied to all subpatterns of the same name, and
is true if any one of them is the most recent recursion.
- At "top level", all these recursion test conditions are false. The
+ At "top level", all these recursion test conditions are false. The
syntax for recursive patterns is described below.
Defining subpatterns for use by reference only
- If the condition is the string (DEFINE), and there is no subpattern
- with the name DEFINE, the condition is always false. In this case,
- there may be only one alternative in the subpattern. It is always
- skipped if control reaches this point in the pattern; the idea of
- DEFINE is that it can be used to define subroutines that can be refer-
- enced from elsewhere. (The use of subroutines is described below.) For
- example, a pattern to match an IPv4 address such as "192.168.23.245"
+ If the condition is the string (DEFINE), and there is no subpattern
+ with the name DEFINE, the condition is always false. In this case,
+ there may be only one alternative in the subpattern. It is always
+ skipped if control reaches this point in the pattern; the idea of
+ DEFINE is that it can be used to define subroutines that can be refer-
+ enced from elsewhere. (The use of subroutines is described below.) For
+ example, a pattern to match an IPv4 address such as "192.168.23.245"
could be written like this (ignore white space and line breaks):
(?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) )
\b (?&byte) (\.(?&byte)){3} \b
- The first part of the pattern is a DEFINE group inside which a another
- group named "byte" is defined. This matches an individual component of
- an IPv4 address (a number less than 256). When matching takes place,
- this part of the pattern is skipped because DEFINE acts like a false
- condition. The rest of the pattern uses references to the named group
- to match the four dot-separated components of an IPv4 address, insist-
+ The first part of the pattern is a DEFINE group inside which a another
+ group named "byte" is defined. This matches an individual component of
+ an IPv4 address (a number less than 256). When matching takes place,
+ this part of the pattern is skipped because DEFINE acts like a false
+ condition. The rest of the pattern uses references to the named group
+ to match the four dot-separated components of an IPv4 address, insist-
ing on a word boundary at each end.
Assertion conditions
- If the condition is not in any of the above formats, it must be an
- assertion. This may be a positive or negative lookahead or lookbehind
- assertion. Consider this pattern, again containing non-significant
+ If the condition is not in any of the above formats, it must be an
+ assertion. This may be a positive or negative lookahead or lookbehind
+ assertion. Consider this pattern, again containing non-significant
white space, and with the two alternatives on the second line:
(?(?=[^a-z]*[a-z])
\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )
- The condition is a positive lookahead assertion that matches an
- optional sequence of non-letters followed by a letter. In other words,
- it tests for the presence of at least one letter in the subject. If a
- letter is found, the subject is matched against the first alternative;
- otherwise it is matched against the second. This pattern matches
- strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are
+ The condition is a positive lookahead assertion that matches an
+ optional sequence of non-letters followed by a letter. In other words,
+ it tests for the presence of at least one letter in the subject. If a
+ letter is found, the subject is matched against the first alternative;
+ otherwise it is matched against the second. This pattern matches
+ strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are
letters and dd are digits.
There are two ways of including comments in patterns that are processed
by PCRE. In both cases, the start of the comment must not be in a char-
acter class, nor in the middle of any other sequence of related charac-
- ters such as (?: or a subpattern name or number. The characters that
+ ters such as (?: or a subpattern name or number. The characters that
make up a comment play no part in the pattern matching.
- The sequence (?# marks the start of a comment that continues up to the
- next closing parenthesis. Nested parentheses are not permitted. If the
+ The sequence (?# marks the start of a comment that continues up to the
+ next closing parenthesis. Nested parentheses are not permitted. If the
PCRE_EXTENDED option is set, an unescaped # character also introduces a
- comment, which in this case continues to immediately after the next
- newline character or character sequence in the pattern. Which charac-
+ comment, which in this case continues to immediately after the next
+ newline character or character sequence in the pattern. Which charac-
ters are interpreted as newlines is controlled by the options passed to
- a compiling function or by a special sequence at the start of the pat-
+ a compiling function or by a special sequence at the start of the pat-
tern, as described in the section entitled "Newline conventions" above.
Note that the end of this type of comment is a literal newline sequence
- in the pattern; escape sequences that happen to represent a newline do
- not count. For example, consider this pattern when PCRE_EXTENDED is
+ in the pattern; escape sequences that happen to represent a newline do
+ not count. For example, consider this pattern when PCRE_EXTENDED is
set, and the default newline convention is in force:
abc #comment \n still comment
- On encountering the # character, pcre_compile() skips along, looking
- for a newline in the pattern. The sequence \n is still literal at this
- stage, so it does not terminate the comment. Only an actual character
+ On encountering the # character, pcre_compile() skips along, looking
+ for a newline in the pattern. The sequence \n is still literal at this
+ stage, so it does not terminate the comment. Only an actual character
with the code value 0x0a (the default newline) does so.
RECURSIVE PATTERNS
- Consider the problem of matching a string in parentheses, allowing for
- unlimited nested parentheses. Without the use of recursion, the best
- that can be done is to use a pattern that matches up to some fixed
- depth of nesting. It is not possible to handle an arbitrary nesting
+ Consider the problem of matching a string in parentheses, allowing for
+ unlimited nested parentheses. Without the use of recursion, the best
+ that can be done is to use a pattern that matches up to some fixed
+ depth of nesting. It is not possible to handle an arbitrary nesting
depth.
For some time, Perl has provided a facility that allows regular expres-
- sions to recurse (amongst other things). It does this by interpolating
- Perl code in the expression at run time, and the code can refer to the
+ sions to recurse (amongst other things). It does this by interpolating
+ Perl code in the expression at run time, and the code can refer to the
expression itself. A Perl pattern using code interpolation to solve the
parentheses problem can be created like this:
refers recursively to the pattern in which it appears.
Obviously, PCRE cannot support the interpolation of Perl code. Instead,
- it supports special syntax for recursion of the entire pattern, and
- also for individual subpattern recursion. After its introduction in
- PCRE and Python, this kind of recursion was subsequently introduced
+ it supports special syntax for recursion of the entire pattern, and
+ also for individual subpattern recursion. After its introduction in
+ PCRE and Python, this kind of recursion was subsequently introduced
into Perl at release 5.10.
- A special item that consists of (? followed by a number greater than
- zero and a closing parenthesis is a recursive subroutine call of the
- subpattern of the given number, provided that it occurs inside that
- subpattern. (If not, it is a non-recursive subroutine call, which is
- described in the next section.) The special item (?R) or (?0) is a
+ A special item that consists of (? followed by a number greater than
+ zero and a closing parenthesis is a recursive subroutine call of the
+ subpattern of the given number, provided that it occurs inside that
+ subpattern. (If not, it is a non-recursive subroutine call, which is
+ described in the next section.) The special item (?R) or (?0) is a
recursive call of the entire regular expression.
- This PCRE pattern solves the nested parentheses problem (assume the
+ This PCRE pattern solves the nested parentheses problem (assume the
PCRE_EXTENDED option is set so that white space is ignored):
\( ( [^()]++ | (?R) )* \)
- First it matches an opening parenthesis. Then it matches any number of
- substrings which can either be a sequence of non-parentheses, or a
- recursive match of the pattern itself (that is, a correctly parenthe-
+ First it matches an opening parenthesis. Then it matches any number of
+ substrings which can either be a sequence of non-parentheses, or a
+ recursive match of the pattern itself (that is, a correctly parenthe-
sized substring). Finally there is a closing parenthesis. Note the use
of a possessive quantifier to avoid backtracking into sequences of non-
parentheses.
- If this were part of a larger pattern, you would not want to recurse
+ If this were part of a larger pattern, you would not want to recurse
the entire pattern, so instead you could use this:
( \( ( [^()]++ | (?1) )* \) )
- We have put the pattern into parentheses, and caused the recursion to
+ We have put the pattern into parentheses, and caused the recursion to
refer to them instead of the whole pattern.
- In a larger pattern, keeping track of parenthesis numbers can be
- tricky. This is made easier by the use of relative references. Instead
+ In a larger pattern, keeping track of parenthesis numbers can be
+ tricky. This is made easier by the use of relative references. Instead
of (?1) in the pattern above you can write (?-2) to refer to the second
- most recently opened parentheses preceding the recursion. In other
- words, a negative number counts capturing parentheses leftwards from
+ most recently opened parentheses preceding the recursion. In other
+ words, a negative number counts capturing parentheses leftwards from
the point at which it is encountered.
- It is also possible to refer to subsequently opened parentheses, by
- writing references such as (?+2). However, these cannot be recursive
- because the reference is not inside the parentheses that are refer-
- enced. They are always non-recursive subroutine calls, as described in
+ It is also possible to refer to subsequently opened parentheses, by
+ writing references such as (?+2). However, these cannot be recursive
+ because the reference is not inside the parentheses that are refer-
+ enced. They are always non-recursive subroutine calls, as described in
the next section.
- An alternative approach is to use named parentheses instead. The Perl
- syntax for this is (?&name); PCRE's earlier syntax (?P>name) is also
+ An alternative approach is to use named parentheses instead. The Perl
+ syntax for this is (?&name); PCRE's earlier syntax (?P>name) is also
supported. We could rewrite the above example as follows:
(?<pn> \( ( [^()]++ | (?&pn) )* \) )
- If there is more than one subpattern with the same name, the earliest
+ If there is more than one subpattern with the same name, the earliest
one is used.
- This particular example pattern that we have been looking at contains
+ This particular example pattern that we have been looking at contains
nested unlimited repeats, and so the use of a possessive quantifier for
matching strings of non-parentheses is important when applying the pat-
- tern to strings that do not match. For example, when this pattern is
+ tern to strings that do not match. For example, when this pattern is
applied to
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
- it yields "no match" quickly. However, if a possessive quantifier is
- not used, the match runs for a very long time indeed because there are
- so many different ways the + and * repeats can carve up the subject,
+ it yields "no match" quickly. However, if a possessive quantifier is
+ not used, the match runs for a very long time indeed because there are
+ so many different ways the + and * repeats can carve up the subject,
and all have to be tested before failure can be reported.
- At the end of a match, the values of capturing parentheses are those
- from the outermost level. If you want to obtain intermediate values, a
- callout function can be used (see below and the pcrecallout documenta-
+ At the end of a match, the values of capturing parentheses are those
+ from the outermost level. If you want to obtain intermediate values, a
+ callout function can be used (see below and the pcrecallout documenta-
tion). If the pattern above is matched against
(ab(cd)ef)
- the value for the inner capturing parentheses (numbered 2) is "ef",
- which is the last value taken on at the top level. If a capturing sub-
- pattern is not matched at the top level, its final captured value is
- unset, even if it was (temporarily) set at a deeper level during the
+ the value for the inner capturing parentheses (numbered 2) is "ef",
+ which is the last value taken on at the top level. If a capturing sub-
+ pattern is not matched at the top level, its final captured value is
+ unset, even if it was (temporarily) set at a deeper level during the
matching process.
- If there are more than 15 capturing parentheses in a pattern, PCRE has
- to obtain extra memory to store data during a recursion, which it does
+ If there are more than 15 capturing parentheses in a pattern, PCRE has
+ to obtain extra memory to store data during a recursion, which it does
by using pcre_malloc, freeing it via pcre_free afterwards. If no memory
can be obtained, the match fails with the PCRE_ERROR_NOMEMORY error.
- Do not confuse the (?R) item with the condition (R), which tests for
- recursion. Consider this pattern, which matches text in angle brack-
- ets, allowing for arbitrary nesting. Only digits are allowed in nested
- brackets (that is, when recursing), whereas any characters are permit-
+ Do not confuse the (?R) item with the condition (R), which tests for
+ recursion. Consider this pattern, which matches text in angle brack-
+ ets, allowing for arbitrary nesting. Only digits are allowed in nested
+ brackets (that is, when recursing), whereas any characters are permit-
ted at the outer level.
< (?: (?(R) \d++ | [^<>]*+) | (?R)) * >
- In this pattern, (?(R) is the start of a conditional subpattern, with
- two different alternatives for the recursive and non-recursive cases.
+ In this pattern, (?(R) is the start of a conditional subpattern, with
+ two different alternatives for the recursive and non-recursive cases.
The (?R) item is the actual recursive call.
Differences in recursion processing between PCRE and Perl
- Recursion processing in PCRE differs from Perl in two important ways.
- In PCRE (like Python, but unlike Perl), a recursive subpattern call is
+ Recursion processing in PCRE differs from Perl in two important ways.
+ In PCRE (like Python, but unlike Perl), a recursive subpattern call is
always treated as an atomic group. That is, once it has matched some of
the subject string, it is never re-entered, even if it contains untried
- alternatives and there is a subsequent matching failure. This can be
- illustrated by the following pattern, which purports to match a palin-
- dromic string that contains an odd number of characters (for example,
+ alternatives and there is a subsequent matching failure. This can be
+ illustrated by the following pattern, which purports to match a palin-
+ dromic string that contains an odd number of characters (for example,
"a", "aba", "abcba", "abcdcba"):
^(.|(.)(?1)\2)$
The idea is that it either matches a single character, or two identical
- characters surrounding a sub-palindrome. In Perl, this pattern works;
- in PCRE it does not if the pattern is longer than three characters.
+ characters surrounding a sub-palindrome. In Perl, this pattern works;
+ in PCRE it does not if the pattern is longer than three characters.
Consider the subject string "abcba":
- At the top level, the first character is matched, but as it is not at
+ At the top level, the first character is matched, but as it is not at
the end of the string, the first alternative fails; the second alterna-
tive is taken and the recursion kicks in. The recursive call to subpat-
- tern 1 successfully matches the next character ("b"). (Note that the
+ tern 1 successfully matches the next character ("b"). (Note that the
beginning and end of line tests are not part of the recursion).
- Back at the top level, the next character ("c") is compared with what
- subpattern 2 matched, which was "a". This fails. Because the recursion
- is treated as an atomic group, there are now no backtracking points,
- and so the entire match fails. (Perl is able, at this point, to re-
- enter the recursion and try the second alternative.) However, if the
+ Back at the top level, the next character ("c") is compared with what
+ subpattern 2 matched, which was "a". This fails. Because the recursion
+ is treated as an atomic group, there are now no backtracking points,
+ and so the entire match fails. (Perl is able, at this point, to re-
+ enter the recursion and try the second alternative.) However, if the
pattern is written with the alternatives in the other order, things are
different:
^((.)(?1)\2|.)$
- This time, the recursing alternative is tried first, and continues to
- recurse until it runs out of characters, at which point the recursion
- fails. But this time we do have another alternative to try at the
- higher level. That is the big difference: in the previous case the
+ This time, the recursing alternative is tried first, and continues to
+ recurse until it runs out of characters, at which point the recursion
+ fails. But this time we do have another alternative to try at the
+ higher level. That is the big difference: in the previous case the
remaining alternative is at a deeper recursion level, which PCRE cannot
use.
- To change the pattern so that it matches all palindromic strings, not
- just those with an odd number of characters, it is tempting to change
+ To change the pattern so that it matches all palindromic strings, not
+ just those with an odd number of characters, it is tempting to change
the pattern to this:
^((.)(?1)\2|.?)$
- Again, this works in Perl, but not in PCRE, and for the same reason.
- When a deeper recursion has matched a single character, it cannot be
- entered again in order to match an empty string. The solution is to
- separate the two cases, and write out the odd and even cases as alter-
+ Again, this works in Perl, but not in PCRE, and for the same reason.
+ When a deeper recursion has matched a single character, it cannot be
+ entered again in order to match an empty string. The solution is to
+ separate the two cases, and write out the odd and even cases as alter-
natives at the higher level:
^(?:((.)(?1)\2|)|((.)(?3)\4|.))
- If you want to match typical palindromic phrases, the pattern has to
+ If you want to match typical palindromic phrases, the pattern has to
ignore all non-word characters, which can be done like this:
^\W*+(?:((.)\W*+(?1)\W*+\2|)|((.)\W*+(?3)\W*+\4|\W*+.\W*+))\W*+$
If run with the PCRE_CASELESS option, this pattern matches phrases such
as "A man, a plan, a canal: Panama!" and it works well in both PCRE and
- Perl. Note the use of the possessive quantifier *+ to avoid backtrack-
- ing into sequences of non-word characters. Without this, PCRE takes a
- great deal longer (ten times or more) to match typical phrases, and
+ Perl. Note the use of the possessive quantifier *+ to avoid backtrack-
+ ing into sequences of non-word characters. Without this, PCRE takes a
+ great deal longer (ten times or more) to match typical phrases, and
Perl takes so long that you think it has gone into a loop.
- WARNING: The palindrome-matching patterns above work only if the sub-
- ject string does not start with a palindrome that is shorter than the
- entire string. For example, although "abcba" is correctly matched, if
- the subject is "ababa", PCRE finds the palindrome "aba" at the start,
- then fails at top level because the end of the string does not follow.
- Once again, it cannot jump back into the recursion to try other alter-
+ WARNING: The palindrome-matching patterns above work only if the sub-
+ ject string does not start with a palindrome that is shorter than the
+ entire string. For example, although "abcba" is correctly matched, if
+ the subject is "ababa", PCRE finds the palindrome "aba" at the start,
+ then fails at top level because the end of the string does not follow.
+ Once again, it cannot jump back into the recursion to try other alter-
natives, so the entire match fails.
- The second way in which PCRE and Perl differ in their recursion pro-
- cessing is in the handling of captured values. In Perl, when a subpat-
- tern is called recursively or as a subpattern (see the next section),
- it has no access to any values that were captured outside the recur-
- sion, whereas in PCRE these values can be referenced. Consider this
+ The second way in which PCRE and Perl differ in their recursion pro-
+ cessing is in the handling of captured values. In Perl, when a subpat-
+ tern is called recursively or as a subpattern (see the next section),
+ it has no access to any values that were captured outside the recur-
+ sion, whereas in PCRE these values can be referenced. Consider this
pattern:
^(.)(\1|a(?2))
- In PCRE, this pattern matches "bab". The first capturing parentheses
- match "b", then in the second group, when the back reference \1 fails
- to match "b", the second alternative matches "a" and then recurses. In
- the recursion, \1 does now match "b" and so the whole match succeeds.
- In Perl, the pattern fails to match because inside the recursive call
+ In PCRE, this pattern matches "bab". The first capturing parentheses
+ match "b", then in the second group, when the back reference \1 fails
+ to match "b", the second alternative matches "a" and then recurses. In
+ the recursion, \1 does now match "b" and so the whole match succeeds.
+ In Perl, the pattern fails to match because inside the recursive call
\1 cannot access the externally set value.
SUBPATTERNS AS SUBROUTINES
- If the syntax for a recursive subpattern call (either by number or by
- name) is used outside the parentheses to which it refers, it operates
- like a subroutine in a programming language. The called subpattern may
- be defined before or after the reference. A numbered reference can be
+ If the syntax for a recursive subpattern call (either by number or by
+ name) is used outside the parentheses to which it refers, it operates
+ like a subroutine in a programming language. The called subpattern may
+ be defined before or after the reference. A numbered reference can be
absolute or relative, as in these examples:
(...(absolute)...)...(?2)...
(sens|respons)e and \1ibility
- matches "sense and sensibility" and "response and responsibility", but
+ matches "sense and sensibility" and "response and responsibility", but
not "sense and responsibility". If instead the pattern
(sens|respons)e and (?1)ibility
- is used, it does match "sense and responsibility" as well as the other
- two strings. Another example is given in the discussion of DEFINE
+ is used, it does match "sense and responsibility" as well as the other
+ two strings. Another example is given in the discussion of DEFINE
above.
- All subroutine calls, whether recursive or not, are always treated as
- atomic groups. That is, once a subroutine has matched some of the sub-
+ All subroutine calls, whether recursive or not, are always treated as
+ atomic groups. That is, once a subroutine has matched some of the sub-
ject string, it is never re-entered, even if it contains untried alter-
- natives and there is a subsequent matching failure. Any capturing
- parentheses that are set during the subroutine call revert to their
+ natives and there is a subsequent matching failure. Any capturing
+ parentheses that are set during the subroutine call revert to their
previous values afterwards.
- Processing options such as case-independence are fixed when a subpat-
- tern is defined, so if it is used as a subroutine, such options cannot
+ Processing options such as case-independence are fixed when a subpat-
+ tern is defined, so if it is used as a subroutine, such options cannot
be changed for different calls. For example, consider this pattern:
(abc)(?i:(?-1))
- It matches "abcabc". It does not match "abcABC" because the change of
+ It matches "abcabc". It does not match "abcABC" because the change of
processing option does not affect the called subpattern.
ONIGURUMA SUBROUTINE SYNTAX
- For compatibility with Oniguruma, the non-Perl syntax \g followed by a
+ For compatibility with Oniguruma, the non-Perl syntax \g followed by a
name or a number enclosed either in angle brackets or single quotes, is
- an alternative syntax for referencing a subpattern as a subroutine,
- possibly recursively. Here are two of the examples used above, rewrit-
+ an alternative syntax for referencing a subpattern as a subroutine,
+ possibly recursively. Here are two of the examples used above, rewrit-
ten using this syntax:
(?<pn> \( ( (?>[^()]+) | \g<pn> )* \) )
(sens|respons)e and \g'1'ibility
- PCRE supports an extension to Oniguruma: if a number is preceded by a
+ PCRE supports an extension to Oniguruma: if a number is preceded by a
plus or a minus sign it is taken as a relative reference. For example:
(abc)(?i:\g<-1>)
- Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not
- synonymous. The former is a back reference; the latter is a subroutine
+ Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not
+ synonymous. The former is a back reference; the latter is a subroutine
call.
CALLOUTS
Perl has a feature whereby using the sequence (?{...}) causes arbitrary
- Perl code to be obeyed in the middle of matching a regular expression.
+ Perl code to be obeyed in the middle of matching a regular expression.
This makes it possible, amongst other things, to extract different sub-
strings that match the same pair of parentheses when there is a repeti-
tion.
PCRE provides a similar feature, but of course it cannot obey arbitrary
Perl code. The feature is called "callout". The caller of PCRE provides
- an external function by putting its entry point in the global variable
- pcre_callout (8-bit library) or pcre[16|32]_callout (16-bit or 32-bit
- library). By default, this variable contains NULL, which disables all
+ an external function by putting its entry point in the global variable
+ pcre_callout (8-bit library) or pcre[16|32]_callout (16-bit or 32-bit
+ library). By default, this variable contains NULL, which disables all
calling out.
- Within a regular expression, (?C) indicates the points at which the
- external function is to be called. If you want to identify different
- callout points, you can put a number less than 256 after the letter C.
- The default value is zero. For example, this pattern has two callout
+ Within a regular expression, (?C) indicates the points at which the
+ external function is to be called. If you want to identify different
+ callout points, you can put a number less than 256 after the letter C.
+ The default value is zero. For example, this pattern has two callout
points:
(?C1)abc(?C2)def
- If the PCRE_AUTO_CALLOUT flag is passed to a compiling function, call-
- outs are automatically installed before each item in the pattern. They
- are all numbered 255. If there is a conditional group in the pattern
+ If the PCRE_AUTO_CALLOUT flag is passed to a compiling function, call-
+ outs are automatically installed before each item in the pattern. They
+ are all numbered 255. If there is a conditional group in the pattern
whose condition is an assertion, an additional callout is inserted just
before the condition. An explicit callout may also be set at this posi-
tion, as in this example:
Note that this applies only to assertion conditions, not to other types
of condition.
- During matching, when PCRE reaches a callout point, the external func-
- tion is called. It is provided with the number of the callout, the
- position in the pattern, and, optionally, one item of data originally
- supplied by the caller of the matching function. The callout function
+ During matching, when PCRE reaches a callout point, the external func-
+ tion is called. It is provided with the number of the callout, the
+ position in the pattern, and, optionally, one item of data originally
+ supplied by the caller of the matching function. The callout function
may cause matching to proceed, to backtrack, or to fail altogether.
- By default, PCRE implements a number of optimizations at compile time
- and matching time, and one side-effect is that sometimes callouts are
- skipped. If you need all possible callouts to happen, you need to set
- options that disable the relevant optimizations. More details, and a
- complete description of the interface to the callout function, are
+ By default, PCRE implements a number of optimizations at compile time
+ and matching time, and one side-effect is that sometimes callouts are
+ skipped. If you need all possible callouts to happen, you need to set
+ options that disable the relevant optimizations. More details, and a
+ complete description of the interface to the callout function, are
given in the pcrecallout documentation.
BACKTRACKING CONTROL
- Perl 5.10 introduced a number of "Special Backtracking Control Verbs",
- which are still described in the Perl documentation as "experimental
- and subject to change or removal in a future version of Perl". It goes
- on to say: "Their usage in production code should be noted to avoid
- problems during upgrades." The same remarks apply to the PCRE features
+ Perl 5.10 introduced a number of "Special Backtracking Control Verbs",
+ which are still described in the Perl documentation as "experimental
+ and subject to change or removal in a future version of Perl". It goes
+ on to say: "Their usage in production code should be noted to avoid
+ problems during upgrades." The same remarks apply to the PCRE features
described in this section.
- The new verbs make use of what was previously invalid syntax: an open-
+ The new verbs make use of what was previously invalid syntax: an open-
ing parenthesis followed by an asterisk. They are generally of the form
- (*VERB) or (*VERB:NAME). Some may take either form, possibly behaving
- differently depending on whether or not a name is present. A name is
+ (*VERB) or (*VERB:NAME). Some may take either form, possibly behaving
+ differently depending on whether or not a name is present. A name is
any sequence of characters that does not include a closing parenthesis.
The maximum length of name is 255 in the 8-bit library and 65535 in the
- 16-bit and 32-bit libraries. If the name is empty, that is, if the
- closing parenthesis immediately follows the colon, the effect is as if
- the colon were not there. Any number of these verbs may occur in a
+ 16-bit and 32-bit libraries. If the name is empty, that is, if the
+ closing parenthesis immediately follows the colon, the effect is as if
+ the colon were not there. Any number of these verbs may occur in a
pattern.
- Since these verbs are specifically related to backtracking, most of
- them can be used only when the pattern is to be matched using one of
- the traditional matching functions, because these use a backtracking
- algorithm. With the exception of (*FAIL), which behaves like a failing
- negative assertion, the backtracking control verbs cause an error if
+ Since these verbs are specifically related to backtracking, most of
+ them can be used only when the pattern is to be matched using one of
+ the traditional matching functions, because these use a backtracking
+ algorithm. With the exception of (*FAIL), which behaves like a failing
+ negative assertion, the backtracking control verbs cause an error if
encountered by a DFA matching function.
- The behaviour of these verbs in repeated groups, assertions, and in
+ The behaviour of these verbs in repeated groups, assertions, and in
subpatterns called as subroutines (whether or not recursively) is docu-
mented below.
Optimizations that affect backtracking verbs
- PCRE contains some optimizations that are used to speed up matching by
+ PCRE contains some optimizations that are used to speed up matching by
running some checks at the start of each match attempt. For example, it
- may know the minimum length of matching subject, or that a particular
+ may know the minimum length of matching subject, or that a particular
character must be present. When one of these optimizations bypasses the
- running of a match, any included backtracking verbs will not, of
+ running of a match, any included backtracking verbs will not, of
course, be processed. You can suppress the start-of-match optimizations
- by setting the PCRE_NO_START_OPTIMIZE option when calling pcre_com-
+ by setting the PCRE_NO_START_OPTIMIZE option when calling pcre_com-
pile() or pcre_exec(), or by starting the pattern with (*NO_START_OPT).
There is more discussion of this option in the section entitled "Option
bits for pcre_exec()" in the pcreapi documentation.
- Experiments with Perl suggest that it too has similar optimizations,
+ Experiments with Perl suggest that it too has similar optimizations,
sometimes leading to anomalous results.
Verbs that act immediately
- The following verbs act as soon as they are encountered. They may not
+ The following verbs act as soon as they are encountered. They may not
be followed by a name.
(*ACCEPT)
- This verb causes the match to end successfully, skipping the remainder
- of the pattern. However, when it is inside a subpattern that is called
- as a subroutine, only that subpattern is ended successfully. Matching
+ This verb causes the match to end successfully, skipping the remainder
+ of the pattern. However, when it is inside a subpattern that is called
+ as a subroutine, only that subpattern is ended successfully. Matching
then continues at the outer level. If (*ACCEPT) in triggered in a posi-
- tive assertion, the assertion succeeds; in a negative assertion, the
+ tive assertion, the assertion succeeds; in a negative assertion, the
assertion fails.
- If (*ACCEPT) is inside capturing parentheses, the data so far is cap-
+ If (*ACCEPT) is inside capturing parentheses, the data so far is cap-
tured. For example:
A((?:A|B(*ACCEPT)|C)D)
- This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap-
+ This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap-
tured by the outer parentheses.
(*FAIL) or (*F)
- This verb causes a matching failure, forcing backtracking to occur. It
- is equivalent to (?!) but easier to read. The Perl documentation notes
- that it is probably useful only when combined with (?{}) or (??{}).
- Those are, of course, Perl features that are not present in PCRE. The
- nearest equivalent is the callout feature, as for example in this pat-
+ This verb causes a matching failure, forcing backtracking to occur. It
+ is equivalent to (?!) but easier to read. The Perl documentation notes
+ that it is probably useful only when combined with (?{}) or (??{}).
+ Those are, of course, Perl features that are not present in PCRE. The
+ nearest equivalent is the callout feature, as for example in this pat-
tern:
a+(?C)(*FAIL)
- A match with the string "aaaa" always fails, but the callout is taken
+ A match with the string "aaaa" always fails, but the callout is taken
before each backtrack happens (in this example, 10 times).
Recording which path was taken
- There is one verb whose main purpose is to track how a match was
- arrived at, though it also has a secondary use in conjunction with
+ There is one verb whose main purpose is to track how a match was
+ arrived at, though it also has a secondary use in conjunction with
advancing the match starting point (see (*SKIP) below).
(*MARK:NAME) or (*:NAME)
- A name is always required with this verb. There may be as many
- instances of (*MARK) as you like in a pattern, and their names do not
+ A name is always required with this verb. There may be as many
+ instances of (*MARK) as you like in a pattern, and their names do not
have to be unique.
- When a match succeeds, the name of the last-encountered (*MARK:NAME),
- (*PRUNE:NAME), or (*THEN:NAME) on the matching path is passed back to
- the caller as described in the section entitled "Extra data for
- pcre_exec()" in the pcreapi documentation. Here is an example of
- pcretest output, where the /K modifier requests the retrieval and out-
+ When a match succeeds, the name of the last-encountered (*MARK:NAME),
+ (*PRUNE:NAME), or (*THEN:NAME) on the matching path is passed back to
+ the caller as described in the section entitled "Extra data for
+ pcre_exec()" in the pcreapi documentation. Here is an example of
+ pcretest output, where the /K modifier requests the retrieval and out-
putting of (*MARK) data:
re> /X(*MARK:A)Y|X(*MARK:B)Z/K
MK: B
The (*MARK) name is tagged with "MK:" in this output, and in this exam-
- ple it indicates which of the two alternatives matched. This is a more
- efficient way of obtaining this information than putting each alterna-
+ ple it indicates which of the two alternatives matched. This is a more
+ efficient way of obtaining this information than putting each alterna-
tive in its own capturing parentheses.
- If a verb with a name is encountered in a positive assertion that is
- true, the name is recorded and passed back if it is the last-encoun-
+ If a verb with a name is encountered in a positive assertion that is
+ true, the name is recorded and passed back if it is the last-encoun-
tered. This does not happen for negative assertions or failing positive
assertions.
- After a partial match or a failed match, the last encountered name in
+ After a partial match or a failed match, the last encountered name in
the entire match process is returned. For example:
re> /X(*MARK:A)Y|X(*MARK:B)Z/K
data> XP
No match, mark = B
- Note that in this unanchored example the mark is retained from the
+ Note that in this unanchored example the mark is retained from the
match attempt that started at the letter "X" in the subject. Subsequent
match attempts starting at "P" and then with an empty string do not get
as far as the (*MARK) item, but nevertheless do not reset it.
- If you are interested in (*MARK) values after failed matches, you
- should probably set the PCRE_NO_START_OPTIMIZE option (see above) to
+ If you are interested in (*MARK) values after failed matches, you
+ should probably set the PCRE_NO_START_OPTIMIZE option (see above) to
ensure that the match is always attempted.
Verbs that act after backtracking
The following verbs do nothing when they are encountered. Matching con-
- tinues with what follows, but if there is no subsequent match, causing
- a backtrack to the verb, a failure is forced. That is, backtracking
- cannot pass to the left of the verb. However, when one of these verbs
+ tinues with what follows, but if there is no subsequent match, causing
+ a backtrack to the verb, a failure is forced. That is, backtracking
+ cannot pass to the left of the verb. However, when one of these verbs
appears inside an atomic group or an assertion that is true, its effect
- is confined to that group, because once the group has been matched,
- there is never any backtracking into it. In this situation, backtrack-
- ing can "jump back" to the left of the entire atomic group or asser-
- tion. (Remember also, as stated above, that this localization also
+ is confined to that group, because once the group has been matched,
+ there is never any backtracking into it. In this situation, backtrack-
+ ing can "jump back" to the left of the entire atomic group or asser-
+ tion. (Remember also, as stated above, that this localization also
applies in subroutine calls.)
- These verbs differ in exactly what kind of failure occurs when back-
- tracking reaches them. The behaviour described below is what happens
- when the verb is not in a subroutine or an assertion. Subsequent sec-
+ These verbs differ in exactly what kind of failure occurs when back-
+ tracking reaches them. The behaviour described below is what happens
+ when the verb is not in a subroutine or an assertion. Subsequent sec-
tions cover these special cases.
(*COMMIT)
- This verb, which may not be followed by a name, causes the whole match
+ This verb, which may not be followed by a name, causes the whole match
to fail outright if there is a later matching failure that causes back-
- tracking to reach it. Even if the pattern is unanchored, no further
+ tracking to reach it. Even if the pattern is unanchored, no further
attempts to find a match by advancing the starting point take place. If
- (*COMMIT) is the only backtracking verb that is encountered, once it
+ (*COMMIT) is the only backtracking verb that is encountered, once it
has been passed pcre_exec() is committed to finding a match at the cur-
rent starting point, or not at all. For example:
a+(*COMMIT)b
- This matches "xxaab" but not "aacaab". It can be thought of as a kind
+ This matches "xxaab" but not "aacaab". It can be thought of as a kind
of dynamic anchor, or "I've started, so I must finish." The name of the
- most recently passed (*MARK) in the path is passed back when (*COMMIT)
+ most recently passed (*MARK) in the path is passed back when (*COMMIT)
forces a match failure.
- If there is more than one backtracking verb in a pattern, a different
- one that follows (*COMMIT) may be triggered first, so merely passing
+ If there is more than one backtracking verb in a pattern, a different
+ one that follows (*COMMIT) may be triggered first, so merely passing
(*COMMIT) during a match does not always guarantee that a match must be
at this starting point.
- Note that (*COMMIT) at the start of a pattern is not the same as an
- anchor, unless PCRE's start-of-match optimizations are turned off, as
+ Note that (*COMMIT) at the start of a pattern is not the same as an
+ anchor, unless PCRE's start-of-match optimizations are turned off, as
shown in this output from pcretest:
re> /(*COMMIT)abc/
For this pattern, PCRE knows that any match must start with "a", so the
optimization skips along the subject to "a" before applying the pattern
- to the first set of data. The match attempt then succeeds. In the sec-
- ond set of data, the escape sequence \Y is interpreted by the pcretest
- program. It causes the PCRE_NO_START_OPTIMIZE option to be set when
+ to the first set of data. The match attempt then succeeds. In the sec-
+ ond set of data, the escape sequence \Y is interpreted by the pcretest
+ program. It causes the PCRE_NO_START_OPTIMIZE option to be set when
pcre_exec() is called. This disables the optimization that skips along
to the first character. The pattern is now applied starting at "x", and
- so the (*COMMIT) causes the match to fail without trying any other
+ so the (*COMMIT) causes the match to fail without trying any other
starting points.
(*PRUNE) or (*PRUNE:NAME)
- This verb causes the match to fail at the current starting position in
+ This verb causes the match to fail at the current starting position in
the subject if there is a later matching failure that causes backtrack-
- ing to reach it. If the pattern is unanchored, the normal "bumpalong"
- advance to the next starting character then happens. Backtracking can
- occur as usual to the left of (*PRUNE), before it is reached, or when
- matching to the right of (*PRUNE), but if there is no match to the
- right, backtracking cannot cross (*PRUNE). In simple cases, the use of
- (*PRUNE) is just an alternative to an atomic group or possessive quan-
+ ing to reach it. If the pattern is unanchored, the normal "bumpalong"
+ advance to the next starting character then happens. Backtracking can
+ occur as usual to the left of (*PRUNE), before it is reached, or when
+ matching to the right of (*PRUNE), but if there is no match to the
+ right, backtracking cannot cross (*PRUNE). In simple cases, the use of
+ (*PRUNE) is just an alternative to an atomic group or possessive quan-
tifier, but there are some uses of (*PRUNE) that cannot be expressed in
- any other way. In an anchored pattern (*PRUNE) has the same effect as
+ any other way. In an anchored pattern (*PRUNE) has the same effect as
(*COMMIT).
The behaviour of (*PRUNE:NAME) is the not the same as
- (*MARK:NAME)(*PRUNE). It is like (*MARK:NAME) in that the name is
- remembered for passing back to the caller. However, (*SKIP:NAME)
+ (*MARK:NAME)(*PRUNE). It is like (*MARK:NAME) in that the name is
+ remembered for passing back to the caller. However, (*SKIP:NAME)
searches only for names set with (*MARK).
(*SKIP)
- This verb, when given without a name, is like (*PRUNE), except that if
- the pattern is unanchored, the "bumpalong" advance is not to the next
+ This verb, when given without a name, is like (*PRUNE), except that if
+ the pattern is unanchored, the "bumpalong" advance is not to the next
character, but to the position in the subject where (*SKIP) was encoun-
- tered. (*SKIP) signifies that whatever text was matched leading up to
+ tered. (*SKIP) signifies that whatever text was matched leading up to
it cannot be part of a successful match. Consider:
a+(*SKIP)b
- If the subject is "aaaac...", after the first match attempt fails
- (starting at the first character in the string), the starting point
+ If the subject is "aaaac...", after the first match attempt fails
+ (starting at the first character in the string), the starting point
skips on to start the next attempt at "c". Note that a possessive quan-
- tifer does not have the same effect as this example; although it would
- suppress backtracking during the first match attempt, the second
- attempt would start at the second character instead of skipping on to
+ tifer does not have the same effect as this example; although it would
+ suppress backtracking during the first match attempt, the second
+ attempt would start at the second character instead of skipping on to
"c".
(*SKIP:NAME)
When (*SKIP) has an associated name, its behaviour is modified. When it
is triggered, the previous path through the pattern is searched for the
- most recent (*MARK) that has the same name. If one is found, the
+ most recent (*MARK) that has the same name. If one is found, the
"bumpalong" advance is to the subject position that corresponds to that
(*MARK) instead of to where (*SKIP) was encountered. If no (*MARK) with
a matching name is found, the (*SKIP) is ignored.
- Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It
+ Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It
ignores names that are set by (*PRUNE:NAME) or (*THEN:NAME).
(*THEN) or (*THEN:NAME)
- This verb causes a skip to the next innermost alternative when back-
- tracking reaches it. That is, it cancels any further backtracking
- within the current alternative. Its name comes from the observation
+ This verb causes a skip to the next innermost alternative when back-
+ tracking reaches it. That is, it cancels any further backtracking
+ within the current alternative. Its name comes from the observation
that it can be used for a pattern-based if-then-else block:
( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ...
- If the COND1 pattern matches, FOO is tried (and possibly further items
- after the end of the group if FOO succeeds); on failure, the matcher
- skips to the second alternative and tries COND2, without backtracking
- into COND1. If that succeeds and BAR fails, COND3 is tried. If subse-
- quently BAZ fails, there are no more alternatives, so there is a back-
- track to whatever came before the entire group. If (*THEN) is not
+ If the COND1 pattern matches, FOO is tried (and possibly further items
+ after the end of the group if FOO succeeds); on failure, the matcher
+ skips to the second alternative and tries COND2, without backtracking
+ into COND1. If that succeeds and BAR fails, COND3 is tried. If subse-
+ quently BAZ fails, there are no more alternatives, so there is a back-
+ track to whatever came before the entire group. If (*THEN) is not
inside an alternation, it acts like (*PRUNE).
- The behaviour of (*THEN:NAME) is the not the same as
- (*MARK:NAME)(*THEN). It is like (*MARK:NAME) in that the name is
- remembered for passing back to the caller. However, (*SKIP:NAME)
+ The behaviour of (*THEN:NAME) is the not the same as
+ (*MARK:NAME)(*THEN). It is like (*MARK:NAME) in that the name is
+ remembered for passing back to the caller. However, (*SKIP:NAME)
searches only for names set with (*MARK).
- A subpattern that does not contain a | character is just a part of the
- enclosing alternative; it is not a nested alternation with only one
- alternative. The effect of (*THEN) extends beyond such a subpattern to
- the enclosing alternative. Consider this pattern, where A, B, etc. are
- complex pattern fragments that do not contain any | characters at this
+ A subpattern that does not contain a | character is just a part of the
+ enclosing alternative; it is not a nested alternation with only one
+ alternative. The effect of (*THEN) extends beyond such a subpattern to
+ the enclosing alternative. Consider this pattern, where A, B, etc. are
+ complex pattern fragments that do not contain any | characters at this
level:
A (B(*THEN)C) | D
- If A and B are matched, but there is a failure in C, matching does not
+ If A and B are matched, but there is a failure in C, matching does not
backtrack into A; instead it moves to the next alternative, that is, D.
- However, if the subpattern containing (*THEN) is given an alternative,
+ However, if the subpattern containing (*THEN) is given an alternative,
it behaves differently:
A (B(*THEN)C | (*FAIL)) | D
- The effect of (*THEN) is now confined to the inner subpattern. After a
+ The effect of (*THEN) is now confined to the inner subpattern. After a
failure in C, matching moves to (*FAIL), which causes the whole subpat-
- tern to fail because there are no more alternatives to try. In this
+ tern to fail because there are no more alternatives to try. In this
case, matching does now backtrack into A.
- Note that a conditional subpattern is not considered as having two
- alternatives, because only one is ever used. In other words, the |
+ Note that a conditional subpattern is not considered as having two
+ alternatives, because only one is ever used. In other words, the |
character in a conditional subpattern has a different meaning. Ignoring
white space, consider:
^.*? (?(?=a) a | b(*THEN)c )
- If the subject is "ba", this pattern does not match. Because .*? is
- ungreedy, it initially matches zero characters. The condition (?=a)
- then fails, the character "b" is matched, but "c" is not. At this
- point, matching does not backtrack to .*? as might perhaps be expected
- from the presence of the | character. The conditional subpattern is
+ If the subject is "ba", this pattern does not match. Because .*? is
+ ungreedy, it initially matches zero characters. The condition (?=a)
+ then fails, the character "b" is matched, but "c" is not. At this
+ point, matching does not backtrack to .*? as might perhaps be expected
+ from the presence of the | character. The conditional subpattern is
part of the single alternative that comprises the whole pattern, and so
- the match fails. (If there was a backtrack into .*?, allowing it to
+ the match fails. (If there was a backtrack into .*?, allowing it to
match "b", the match would succeed.)
- The verbs just described provide four different "strengths" of control
+ The verbs just described provide four different "strengths" of control
when subsequent matching fails. (*THEN) is the weakest, carrying on the
- match at the next alternative. (*PRUNE) comes next, failing the match
- at the current starting position, but allowing an advance to the next
- character (for an unanchored pattern). (*SKIP) is similar, except that
+ match at the next alternative. (*PRUNE) comes next, failing the match
+ at the current starting position, but allowing an advance to the next
+ character (for an unanchored pattern). (*SKIP) is similar, except that
the advance may be more than one character. (*COMMIT) is the strongest,
causing the entire match to fail.
More than one backtracking verb
- If more than one backtracking verb is present in a pattern, the one
- that is backtracked onto first acts. For example, consider this pat-
+ If more than one backtracking verb is present in a pattern, the one
+ that is backtracked onto first acts. For example, consider this pat-
tern, where A, B, etc. are complex pattern fragments:
(A(*COMMIT)B(*THEN)C|ABD)
- If A matches but B fails, the backtrack to (*COMMIT) causes the entire
+ If A matches but B fails, the backtrack to (*COMMIT) causes the entire
match to fail. However, if A and B match, but C fails, the backtrack to
- (*THEN) causes the next alternative (ABD) to be tried. This behaviour
- is consistent, but is not always the same as Perl's. It means that if
- two or more backtracking verbs appear in succession, all the the last
+ (*THEN) causes the next alternative (ABD) to be tried. This behaviour
+ is consistent, but is not always the same as Perl's. It means that if
+ two or more backtracking verbs appear in succession, all the the last
of them has no effect. Consider this example:
...(*COMMIT)(*PRUNE)...
If there is a matching failure to the right, backtracking onto (*PRUNE)
- causes it to be triggered, and its action is taken. There can never be
+ causes it to be triggered, and its action is taken. There can never be
a backtrack onto (*COMMIT).
Backtracking verbs in repeated groups
- PCRE differs from Perl in its handling of backtracking verbs in
+ PCRE differs from Perl in its handling of backtracking verbs in
repeated groups. For example, consider:
/(a(*COMMIT)b)+ac/
- If the subject is "abac", Perl matches, but PCRE fails because the
+ If the subject is "abac", Perl matches, but PCRE fails because the
(*COMMIT) in the second repeat of the group acts.
Backtracking verbs in assertions
- (*FAIL) in an assertion has its normal effect: it forces an immediate
+ (*FAIL) in an assertion has its normal effect: it forces an immediate
backtrack.
(*ACCEPT) in a positive assertion causes the assertion to succeed with-
- out any further processing. In a negative assertion, (*ACCEPT) causes
+ out any further processing. In a negative assertion, (*ACCEPT) causes
the assertion to fail without any further processing.
- The other backtracking verbs are not treated specially if they appear
- in a positive assertion. In particular, (*THEN) skips to the next
- alternative in the innermost enclosing group that has alternations,
+ The other backtracking verbs are not treated specially if they appear
+ in a positive assertion. In particular, (*THEN) skips to the next
+ alternative in the innermost enclosing group that has alternations,
whether or not this is within the assertion.
- Negative assertions are, however, different, in order to ensure that
- changing a positive assertion into a negative assertion changes its
+ Negative assertions are, however, different, in order to ensure that
+ changing a positive assertion into a negative assertion changes its
result. Backtracking into (*COMMIT), (*SKIP), or (*PRUNE) causes a neg-
ative assertion to be true, without considering any further alternative
branches in the assertion. Backtracking into (*THEN) causes it to skip
- to the next enclosing alternative within the assertion (the normal be-
- haviour), but if the assertion does not have such an alternative,
+ to the next enclosing alternative within the assertion (the normal be-
+ haviour), but if the assertion does not have such an alternative,
(*THEN) behaves like (*PRUNE).
Backtracking verbs in subroutines
- These behaviours occur whether or not the subpattern is called recur-
+ These behaviours occur whether or not the subpattern is called recur-
sively. Perl's treatment of subroutines is different in some cases.
- (*FAIL) in a subpattern called as a subroutine has its normal effect:
+ (*FAIL) in a subpattern called as a subroutine has its normal effect:
it forces an immediate backtrack.
- (*ACCEPT) in a subpattern called as a subroutine causes the subroutine
- match to succeed without any further processing. Matching then contin-
+ (*ACCEPT) in a subpattern called as a subroutine causes the subroutine
+ match to succeed without any further processing. Matching then contin-
ues after the subroutine call.
(*COMMIT), (*SKIP), and (*PRUNE) in a subpattern called as a subroutine
cause the subroutine match to fail.
- (*THEN) skips to the next alternative in the innermost enclosing group
- within the subpattern that has alternatives. If there is no such group
+ (*THEN) skips to the next alternative in the innermost enclosing group
+ within the subpattern that has alternatives. If there is no such group
within the subpattern, (*THEN) causes the subroutine match to fail.
SEE ALSO
- pcreapi(3), pcrecallout(3), pcrematching(3), pcresyntax(3), pcre(3),
+ pcreapi(3), pcrecallout(3), pcrematching(3), pcresyntax(3), pcre(3),
pcre16(3), pcre32(3).
REVISION
- Last updated: 14 June 2015
- Copyright (c) 1997-2015 University of Cambridge.
+ Last updated: 23 October 2016
+ Copyright (c) 1997-2016 University of Cambridge.
------------------------------------------------------------------------------
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.
+ 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
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
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
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.
------------------------------------------------------------------------------
/* The current PCRE version information. */
#define PCRE_MAJOR 8
-#define PCRE_MINOR 38
+#define PCRE_MINOR 41
#define PCRE_PRERELEASE
-#define PCRE_DATE 2015-11-23
+#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
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
+ Copyright (c) 1997-2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
supporting internal functions that are not used by other modules. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#define NLBLOCK cd /* Block containing newline information */
#define PSSTART start_pattern /* Field containing pattern start */
"lookbehind assertion is not fixed length\0"
"malformed number or name after (?(\0"
"conditional group contains more than two branches\0"
- "assertion expected after (?(\0"
+ "assertion expected after (?( or (?(?C)\0"
"(?R or (?[+-]digits must be followed by )\0"
/* 30 */
"unknown POSIX class name\0"
/* 85 */
"parentheses are too deeply nested (stack check)\0"
"digits missing in \\x{} or \\o{}\0"
+ "regular expression is too complicated\0"
;
/* Table to identify digits and hex digits. This is used when compiling
pcre_uint32 ec;
pcre_uchar mcbuffer[8];
+ /* Come here to restart the loop without advancing the pointer. */
+
+ REDO_LOOP:
+
/* Get next character in the pattern */
c = *ptr;
if (code > cd->start_workspace + cd->workspace_size -
WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */
{
- *errorcodeptr = ERR52;
+ *errorcodeptr = (code >= cd->start_workspace + cd->workspace_size)?
+ ERR52 : ERR87;
goto FAILED;
}
goto FAILED;
}
- /* If in \Q...\E, check for the end; if not, we have a literal */
+ /* If in \Q...\E, check for the end; if not, we have a literal. Otherwise an
+ isolated \E is ignored. */
- if (inescq && c != CHAR_NULL)
+ if (c != CHAR_NULL)
{
if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
{
ptr++;
continue;
}
- else
+ else if (inescq)
{
if (previous_callout != NULL)
{
}
goto NORMAL_CHAR;
}
- /* Control does not reach here. */
+
+ /* Check for the start of a \Q...\E sequence. We must do this here rather
+ than later in case it is immediately followed by \E, which turns it into a
+ "do nothing" sequence. */
+
+ if (c == CHAR_BACKSLASH && ptr[1] == CHAR_Q)
+ {
+ inescq = TRUE;
+ ptr++;
+ continue;
+ }
}
- /* In extended mode, skip white space and comments. We need a loop in order
- to check for more white space and more comments after a comment. */
+ /* In extended mode, skip white space and comments. */
if ((options & PCRE_EXTENDED) != 0)
{
- for (;;)
+ const pcre_uchar *wscptr = ptr;
+ while (MAX_255(c) && (cd->ctypes[c] & ctype_space) != 0) c = *(++ptr);
+ if (c == CHAR_NUMBER_SIGN)
{
- while (MAX_255(c) && (cd->ctypes[c] & ctype_space) != 0) c = *(++ptr);
- if (c != CHAR_NUMBER_SIGN) break;
ptr++;
while (*ptr != CHAR_NULL)
{
if (utf) FORWARDCHAR(ptr);
#endif
}
- c = *ptr; /* Either NULL or the char after a newline */
}
+
+ /* If we skipped any characters, restart the loop. Otherwise, we didn't see
+ a comment. */
+
+ if (ptr > wscptr) goto REDO_LOOP;
+ }
+
+ /* Skip over (?# comments. We need to do this here because we want to know if
+ the next thing is a quantifier, and these comments may come between an item
+ and its quantifier. */
+
+ if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK &&
+ ptr[2] == CHAR_NUMBER_SIGN)
+ {
+ ptr += 3;
+ while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
+ if (*ptr == CHAR_NULL)
+ {
+ *errorcodeptr = ERR18;
+ goto FAILED;
+ }
+ continue;
}
/* See if the next thing is a quantifier. */
if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0)
{
nestptr = ptr + 7;
- ptr = sub_start_of_word - 1;
- continue;
+ ptr = sub_start_of_word;
+ goto REDO_LOOP;
}
if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
{
nestptr = ptr + 7;
- ptr = sub_end_of_word - 1;
- continue;
+ ptr = sub_end_of_word;
+ goto REDO_LOOP;
}
/* Handle a real character class. */
ptr = tempptr + 1;
continue;
- /* For the other POSIX classes (ascii, xdigit) we are going to fall
- through to the non-UCP case and build a bit map for characters with
- code points less than 256. If we are in a negated POSIX class
- within a non-negated overall class, characters with code points
- greater than 255 must all match. In the special case where we have
- not yet generated any xclass data, and this is the final item in
- the overall class, we need do nothing: later on, the opcode
+ /* For the other POSIX classes (ascii, cntrl, xdigit) we are going
+ to fall through to the non-UCP case and build a bit map for
+ characters with code points less than 256. If we are in a negated
+ POSIX class, characters with code points greater than 255 must
+ either all match or all not match. In the special case where we
+ have not yet generated any xclass data, and this is the final item
+ in the overall class, we need do nothing: later on, the opcode
OP_NCLASS will be used to indicate that characters greater than 255
are acceptable. If we have already seen an xclass item or one may
follow (we have to assume that it might if this is not the end of
- the class), explicitly match all wide codepoints. */
+ the class), explicitly list all wide codepoints, which will then
+ either not match or match, depending on whether the class is or is
+ not negated. */
default:
- if (!negate_class && local_negate &&
+ if (local_negate &&
(xclass || tempptr[2] != CHAR_RIGHT_SQUARE_BRACKET))
{
*class_uchardata++ = XCL_RANGE;
#endif
#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
{
+ /* For non-UCP wide characters, in a non-negative class containing \S or
+ similar (should_flip_negation is set), all characters greater than 255
+ must be in the class. */
+
+ if (
+#if defined COMPILE_PCRE8
+ utf &&
+#endif
+ should_flip_negation && !negate_class && (options & PCRE_UCP) == 0)
+ {
+ *class_uchardata++ = XCL_RANGE;
+ if (utf) /* Will always be utf in the 8-bit library */
+ {
+ class_uchardata += PRIV(ord2utf)(0x100, class_uchardata);
+ class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata);
+ }
+ else /* Can only happen for the 16-bit & 32-bit libraries */
+ {
+#if defined COMPILE_PCRE16
+ *class_uchardata++ = 0x100;
+ *class_uchardata++ = 0xffffu;
+#elif defined COMPILE_PCRE32
+ *class_uchardata++ = 0x100;
+ *class_uchardata++ = 0xffffffffu;
+#endif
+ }
+ }
+
*class_uchardata++ = XCL_END; /* Marks the end of extra data */
*code++ = OP_XCLASS;
code += LINK_SIZE;
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,
/* If previous was a character type match (\d or similar), abolish it and
create a suitable repeat item. The code is shared with single-character
repeats by setting op_type to add a suitable offset into repeat_type. Note
- that the Unicode property types will be present only when SUPPORT_UCP is
+ the the Unicode property types will be present only when SUPPORT_UCP is
defined, but we don't wrap the little bits of code here because it just
makes it horribly messy. */
case CHAR_LEFT_PARENTHESIS:
ptr++;
- /* First deal with comments. Putting this code right at the start ensures
- that comments have no bad side effects. */
-
- if (ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN)
- {
- ptr += 2;
- while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
- if (*ptr == CHAR_NULL)
- {
- *errorcodeptr = ERR18;
- goto FAILED;
- }
- continue;
- }
-
/* Now deal with various "verbs" that can be introduced by '*'. */
if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':'
cd->had_accept = TRUE;
for (oc = cd->open_caps; oc != NULL; oc = oc->next)
{
- *code++ = OP_CLOSE;
- PUT2INC(code, 0, oc->number);
+ if (lengthptr != NULL)
+ {
+#ifdef COMPILE_PCRE8
+ *lengthptr += 1 + IMM2_SIZE;
+#elif defined COMPILE_PCRE16
+ *lengthptr += 2 + IMM2_SIZE;
+#elif defined COMPILE_PCRE32
+ *lengthptr += 4 + IMM2_SIZE;
+#endif
+ }
+ else
+ {
+ *code++ = OP_CLOSE;
+ PUT2INC(code, 0, oc->number);
+ }
}
setverb = *code++ =
(cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break;
if (ptr[i] == CHAR_RIGHT_PARENTHESIS)
tempptr += i + 1;
+
+ /* tempptr should now be pointing to the opening parenthesis of the
+ assertion condition. */
+
+ if (*tempptr != CHAR_LEFT_PARENTHESIS)
+ {
+ *errorcodeptr = ERR28;
+ goto FAILED;
+ }
}
/* For conditions that are assertions, check the syntax, and then exit
slot = cd->name_table;
for (i = 0; i < cd->names_found; i++)
{
- if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0) break;
+ if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0 &&
+ slot[IMM2_SIZE+namelen] == 0) break;
slot += cd->name_entry_size;
}
issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance
only mode, we finesse the bug by allowing more memory always. */
- *lengthptr += 2 + 2*LINK_SIZE;
+ *lengthptr += 4 + 4*LINK_SIZE;
/* It is even worse than that. The current reference may be to an
existing named group with a different number (so apparently not
so far in order to get the number. If the name is not found, leave
the value of recno as 0 for a forward reference. */
- else
+ /* This patch (removing "else") fixes a problem when a reference is
+ to multiple identically named nested groups from within the nest.
+ Once again, it is not the "proper" fix, and it results in an
+ over-allocation of memory. */
+
+ /* else */
{
ng = cd->named_groups;
for (i = 0; i < cd->names_found; i++, ng++)
newoptions = (options | set) & (~unset);
/* If the options ended with ')' this is not the start of a nested
- group with option changes, so the options change at this level. If this
- item is right at the start of the pattern, the options can be
- abstracted and made external in the pre-compile phase, and ignored in
- the compile phase. This can be helpful when matching -- for instance in
- caseless checking of required bytes.
-
- If the code pointer is not (cd->start_code + 1 + LINK_SIZE), we are
- definitely *not* at the start of the pattern because something has been
- compiled. In the pre-compile phase, however, the code pointer can have
- that value after the start, because it gets reset as code is discarded
- during the pre-compile. However, this can happen only at top level - if
- we are within parentheses, the starting BRA will still be present. At
- any parenthesis level, the length value can be used to test if anything
- has been compiled at that level. Thus, a test for both these conditions
- is necessary to ensure we correctly detect the start of the pattern in
- both phases.
-
+ group with option changes, so the options change at this level.
If we are not at the pattern start, reset the greedy defaults and the
case value for firstchar and reqchar. */
if (*ptr == CHAR_RIGHT_PARENTHESIS)
{
- if (code == cd->start_code + 1 + LINK_SIZE &&
- (lengthptr == NULL || *lengthptr == 2 + 2*LINK_SIZE))
- {
- cd->external_options = newoptions;
- }
- else
- {
- greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);
- greedy_non_default = greedy_default ^ 1;
- req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS:0;
- }
+ greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);
+ greedy_non_default = greedy_default ^ 1;
+ req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS:0;
/* Change options at this level, and pass them back for use
in subsequent branches. */
}
}
- /* For a forward assertion, we take the reqchar, if set. This can be
- helpful if the pattern that follows the assertion doesn't set a different
- char. For example, it's useful for /(?=abcde).+/. We can't set firstchar
- for an assertion, however because it leads to incorrect effect for patterns
- such as /(?=a)a.+/ when the "real" "a" would then become a reqchar instead
- of a firstchar. This is overcome by a scan at the end if there's no
- firstchar, looking for an asserted first char. */
-
- else if (bravalue == OP_ASSERT && subreqcharflags >= 0)
+ /* For a forward assertion, we take the reqchar, if set, provided that the
+ group has also set a first char. This can be helpful if the pattern that
+ follows the assertion doesn't set a different char. For example, it's
+ useful for /(?=abcde).+/. We can't set firstchar for an assertion, however
+ because it leads to incorrect effect for patterns such as /(?=a)a.+/ when
+ the "real" "a" would then become a reqchar instead of a firstchar. This is
+ overcome by a scan at the end if there's no firstchar, looking for an
+ asserted first char. */
+
+ else if (bravalue == OP_ASSERT && subreqcharflags >= 0 &&
+ subfirstcharflags >= 0)
{
reqchar = subreqchar;
reqcharflags = subreqcharflags;
c = ec;
else
{
- if (escape == ESC_Q) /* Handle start of quoted string */
- {
- if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
- ptr += 2; /* avoid empty string */
- else inescq = TRUE;
- continue;
- }
-
- if (escape == ESC_E) continue; /* Perl ignores an orphan \E */
-
/* For metasequences that actually match a character, we disable the
setting of a first character if it hasn't already been set. */
if (mclength == 1 || req_caseopt == 0)
{
- firstchar = mcbuffer[0] | req_caseopt;
firstchar = mcbuffer[0];
firstcharflags = req_caseopt;
the beginning or after \n). As in the case of is_anchored() (see above), we
have to take account of back references to capturing brackets that contain .*
because in that case we can't make the assumption. Also, the appearance of .*
-inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not
-count, because once again the assumption no longer holds.
+inside atomic brackets or in an assertion, or in a pattern that contains *PRUNE
+or *SKIP does not count, because once again the assumption no longer holds.
Arguments:
code points to start of expression (the bracket)
the less precise approach
cd points to the compile data
atomcount atomic group level
+ inassert TRUE if in an assertion
Returns: TRUE or FALSE
*/
static BOOL
is_startline(const pcre_uchar *code, unsigned int bracket_map,
- compile_data *cd, int atomcount)
+ compile_data *cd, int atomcount, BOOL inassert)
{
do {
const pcre_uchar *scode = first_significant_code(
return FALSE;
default: /* Assertion */
- if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, bracket_map, cd, atomcount, TRUE)) return FALSE;
do scode += GET(scode, 1); while (*scode == OP_ALT);
scode += 1 + LINK_SIZE;
break;
if (op == OP_BRA || op == OP_BRAPOS ||
op == OP_SBRA || op == OP_SBRAPOS)
{
- if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, bracket_map, cd, atomcount, inassert)) return FALSE;
}
/* Capturing brackets */
{
int n = GET2(scode, 1+LINK_SIZE);
int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
- if (!is_startline(scode, new_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, new_map, cd, atomcount, inassert)) return FALSE;
}
/* Positive forward assertions */
else if (op == OP_ASSERT)
{
- if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, bracket_map, cd, atomcount, TRUE)) return FALSE;
}
/* Atomic brackets */
else if (op == OP_ONCE || op == OP_ONCE_NC)
{
- if (!is_startline(scode, bracket_map, cd, atomcount + 1)) return FALSE;
+ if (!is_startline(scode, bracket_map, cd, atomcount + 1, inassert)) return FALSE;
}
/* .* means "start at start or after \n" if it isn't in atomic brackets or
- brackets that may be referenced, as long as the pattern does not contain
- *PRUNE or *SKIP, because these break the feature. Consider, for example,
- /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the
- start of a line. */
+ brackets that may be referenced or an assertion, as long as the pattern does
+ not contain *PRUNE or *SKIP, because these break the feature. Consider, for
+ example, /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e.
+ not at the start of a line. */
else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)
{
if (scode[1] != OP_ANY || (bracket_map & cd->backref_map) != 0 ||
- atomcount > 0 || cd->had_pruneorskip)
+ atomcount > 0 || cd->had_pruneorskip || inassert)
return FALSE;
}
re->flags |= PCRE_FIRSTSET;
}
- else if (is_startline(codestart, 0, cd, 0)) re->flags |= PCRE_STARTLINE;
+ else if (is_startline(codestart, 0, cd, 0, FALSE)) re->flags |= PCRE_STARTLINE;
}
}
/* This module contains the external function pcre_config(). */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
/* Keep the original link size. */
static int real_link_size = LINK_SIZE;
pattern matching using an NFA algorithm, trying to mimic Perl as closely as
possible. There are also some static supporting functions. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#define NLBLOCK md /* Block containing newline information */
#define PSSTART start_subject /* Field containing processed string start */
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;
}
}
information about a compiled pattern. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
for these functions came from Scott Wimer. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
code the compiled regex
stringname the name of the capturing substring
ovector the vector of matched substrings
+ stringcount number of captured substrings
Returns: the number of the first that is set,
or the number of the last one if none are set,
#if defined COMPILE_PCRE8
static int
-get_first_set(const pcre *code, const char *stringname, int *ovector)
+get_first_set(const pcre *code, const char *stringname, int *ovector,
+ int stringcount)
#elif defined COMPILE_PCRE16
static int
-get_first_set(const pcre16 *code, PCRE_SPTR16 stringname, int *ovector)
+get_first_set(const pcre16 *code, PCRE_SPTR16 stringname, int *ovector,
+ int stringcount)
#elif defined COMPILE_PCRE32
static int
-get_first_set(const pcre32 *code, PCRE_SPTR32 stringname, int *ovector)
+get_first_set(const pcre32 *code, PCRE_SPTR32 stringname, int *ovector,
+ int stringcount)
#endif
{
const REAL_PCRE *re = (const REAL_PCRE *)code;
for (entry = (pcre_uchar *)first; entry <= (pcre_uchar *)last; entry += entrysize)
{
int n = GET2(entry, 0);
- if (ovector[n*2] >= 0) return n;
+ if (n < stringcount && ovector[n*2] >= 0) return n;
}
return GET2(entry, 0);
}
PCRE_UCHAR32 *buffer, int size)
#endif
{
-int n = get_first_set(code, stringname, ovector);
+int n = get_first_set(code, stringname, ovector, stringcount);
if (n <= 0) return n;
#if defined COMPILE_PCRE8
return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size);
pcre_uchar *p;
for (i = 0; i < double_count; i += 2)
- size += sizeof(pcre_uchar *) + IN_UCHARS(ovector[i+1] - ovector[i] + 1);
+ {
+ size += sizeof(pcre_uchar *) + IN_UCHARS(1);
+ if (ovector[i+1] > ovector[i]) size += IN_UCHARS(ovector[i+1] - ovector[i]);
+ }
stringlist = (pcre_uchar **)(PUBL(malloc))(size);
if (stringlist == NULL) return PCRE_ERROR_NOMEMORY;
for (i = 0; i < double_count; i += 2)
{
- int len = ovector[i+1] - ovector[i];
+ int len = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0;
memcpy(p, subject + ovector[i], IN_UCHARS(len));
*stringlist++ = p;
p += len;
PCRE_SPTR32 *stringptr)
#endif
{
-int n = get_first_set(code, stringname, ovector);
+int n = get_first_set(code, stringname, ovector, stringcount);
if (n <= 0) return n;
#if defined COMPILE_PCRE8
return pcre_get_substring(subject, ovector, stringcount, n, stringptr);
Also, when compiling for Virtual Pascal, things are done differently, and
global variables are not used. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
+ Copyright (c) 1997-2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
typedef pcre_uint16 pcre_uchar;
#define UCHAR_SHIFT (1)
-#define IN_UCHARS(x) ((x) << UCHAR_SHIFT)
+#define IN_UCHARS(x) ((x) * 2)
#define MAX_255(c) ((c) <= 255u)
#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
typedef pcre_uint32 pcre_uchar;
#define UCHAR_SHIFT (2)
-#define IN_UCHARS(x) ((x) << UCHAR_SHIFT)
+#define IN_UCHARS(x) ((x) * 4)
#define MAX_255(c) ((c) <= 255u)
#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59,
ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69,
ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79,
- ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERRCOUNT };
+ ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERRCOUNT };
/* JIT compiling modes. The function list is indexed by them. */
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
/* 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)]
pcre_uchar *mark_ptr;
void *callout_data;
/* Everything else after. */
- pcre_uint32 limit_match;
+ sljit_u32 limit_match;
int real_offset_count;
int offset_count;
- pcre_uint8 notbol;
- pcre_uint8 noteol;
- pcre_uint8 notempty;
- pcre_uint8 notempty_atstart;
+ sljit_u8 notbol;
+ sljit_u8 noteol;
+ sljit_u8 notempty;
+ sljit_u8 notempty_atstart;
} jit_arguments;
typedef struct executable_functions {
sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES];
PUBL(jit_callback) callback;
void *userdata;
- pcre_uint32 top_bracket;
- pcre_uint32 limit_match;
+ sljit_u32 top_bracket;
+ sljit_u32 limit_match;
} executable_functions;
typedef struct jump_list {
struct sljit_label *matchingpath;
} braminzero_backtrack;
-typedef struct iterator_backtrack {
+typedef struct char_iterator_backtrack {
backtrack_common common;
/* Next iteration. */
struct sljit_label *matchingpath;
-} iterator_backtrack;
+ union {
+ jump_list *backtracks;
+ struct {
+ unsigned int othercasebit;
+ pcre_uchar chr;
+ BOOL enabled;
+ } charpos;
+ } u;
+} char_iterator_backtrack;
+
+typedef struct ref_iterator_backtrack {
+ backtrack_common common;
+ /* Next iteration. */
+ struct sljit_label *matchingpath;
+} ref_iterator_backtrack;
typedef struct recurse_entry {
struct recurse_entry *next;
/* First byte code. */
pcre_uchar *start;
/* Maps private data offset to each opcode. */
- sljit_si *private_data_ptrs;
+ sljit_s32 *private_data_ptrs;
/* Chain list of read-only data ptrs. */
void *read_only_data_head;
/* Tells whether the capturing bracket is optimized. */
- pcre_uint8 *optimized_cbracket;
+ sljit_u8 *optimized_cbracket;
/* Tells whether the starting offset is a target of then. */
- pcre_uint8 *then_offsets;
+ sljit_u8 *then_offsets;
/* Current position where a THEN must jump. */
then_trap_backtrack *then_trap;
/* Starting offset of private data for capturing brackets. */
- int cbra_ptr;
+ sljit_s32 cbra_ptr;
/* Output vector starting point. Must be divisible by 2. */
- int ovector_start;
+ sljit_s32 ovector_start;
+ /* Points to the starting character of the current match. */
+ sljit_s32 start_ptr;
/* Last known position of the requested byte. */
- int req_char_ptr;
+ sljit_s32 req_char_ptr;
/* Head of the last recursion. */
- int recursive_head_ptr;
- /* First inspected character for partial matching. */
- int start_used_ptr;
+ sljit_s32 recursive_head_ptr;
+ /* First inspected character for partial matching.
+ (Needed for avoiding zero length partial matches.) */
+ sljit_s32 start_used_ptr;
/* Starting pointer for partial soft matches. */
- int hit_start;
- /* End pointer of the first line. */
- int first_line_end;
+ sljit_s32 hit_start;
+ /* Pointer of the match end position. */
+ sljit_s32 match_end_ptr;
/* Points to the marked string. */
- int mark_ptr;
+ sljit_s32 mark_ptr;
/* Recursive control verb management chain. */
- int control_head_ptr;
+ sljit_s32 control_head_ptr;
/* Points to the last matched capture block index. */
- int capture_last_ptr;
- /* Points to the starting position of the current match. */
- int start_ptr;
+ sljit_s32 capture_last_ptr;
+ /* Fast forward skipping byte code pointer. */
+ pcre_uchar *fast_forward_bc_ptr;
+ /* Locals used by fast fail optimization. */
+ sljit_s32 fast_fail_start_ptr;
+ sljit_s32 fast_fail_end_ptr;
/* Flipped and lower case tables. */
- const pcre_uint8 *fcc;
+ const sljit_u8 *fcc;
sljit_sw lcc;
/* Mode can be PCRE_STUDY_JIT_COMPILE and others. */
int mode;
BOOL has_skip_arg;
/* (*THEN) is found in the pattern. */
BOOL has_then;
- /* Needs to know the start position anytime. */
- BOOL needs_start_ptr;
+ /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */
+ BOOL has_skip_in_assert_back;
/* Currently in recurse or negative assert. */
BOOL local_exit;
/* Currently in a positive assert. */
BOOL positive_assert;
/* Newline control. */
int nltype;
- pcre_uint32 nlmax;
- pcre_uint32 nlmin;
+ sljit_u32 nlmax;
+ sljit_u32 nlmin;
int newline;
int bsr_nltype;
- pcre_uint32 bsr_nlmax;
- pcre_uint32 bsr_nlmin;
+ sljit_u32 bsr_nlmax;
+ sljit_u32 bsr_nlmin;
/* Dollar endonly. */
int endonly;
/* Tables. */
BOOL utf;
#ifdef SUPPORT_UCP
BOOL use_ucp;
+ jump_list *getucd;
#endif
#ifdef COMPILE_PCRE8
jump_list *utfreadchar;
jump_list *utfreadtype8;
#endif
#endif /* SUPPORT_UTF */
-#ifdef SUPPORT_UCP
- jump_list *getucd;
-#endif
} compiler_common;
/* For byte_sequence_compare. */
#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
int ucharptr;
union {
- sljit_si asint;
- sljit_uh asushort;
+ sljit_s32 asint;
+ sljit_u16 asushort;
#if defined COMPILE_PCRE8
- sljit_ub asbyte;
- sljit_ub asuchars[4];
+ sljit_u8 asbyte;
+ sljit_u8 asuchars[4];
#elif defined COMPILE_PCRE16
- sljit_uh asuchars[2];
+ sljit_u16 asuchars[2];
#elif defined COMPILE_PCRE32
- sljit_ui asuchars[1];
+ sljit_u32 asuchars[1];
#endif
} c;
union {
- sljit_si asint;
- sljit_uh asushort;
+ sljit_s32 asint;
+ sljit_u16 asushort;
#if defined COMPILE_PCRE8
- sljit_ub asbyte;
- sljit_ub asuchars[4];
+ sljit_u8 asbyte;
+ sljit_u8 asuchars[4];
#elif defined COMPILE_PCRE16
- sljit_uh asuchars[2];
+ sljit_u16 asuchars[2];
#elif defined COMPILE_PCRE32
- sljit_ui asuchars[1];
+ sljit_u32 asuchars[1];
#endif
} oc;
#endif
#undef CMP
/* Used for accessing the elements of the stack. */
-#define STACK(i) ((-(i) - 1) * (int)sizeof(sljit_sw))
+#define STACK(i) ((i) * (int)sizeof(sljit_sw))
#define TMP1 SLJIT_R0
#define TMP2 SLJIT_R2
#define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start])
#if defined COMPILE_PCRE8
-#define MOV_UCHAR SLJIT_MOV_UB
-#define MOVU_UCHAR SLJIT_MOVU_UB
+#define MOV_UCHAR SLJIT_MOV_U8
+#define MOVU_UCHAR SLJIT_MOVU_U8
#elif defined COMPILE_PCRE16
-#define MOV_UCHAR SLJIT_MOV_UH
-#define MOVU_UCHAR SLJIT_MOVU_UH
+#define MOV_UCHAR SLJIT_MOV_U16
+#define MOVU_UCHAR SLJIT_MOVU_U16
#elif defined COMPILE_PCRE32
-#define MOV_UCHAR SLJIT_MOV_UI
-#define MOVU_UCHAR SLJIT_MOVU_UI
+#define MOV_UCHAR SLJIT_MOV_U32
+#define MOVU_UCHAR SLJIT_MOVU_U32
#else
#error Unsupported compiling mode
#endif
sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w))
#define CMPTO(type, src1, src1w, src2, src2w, label) \
sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label))
-#define OP_FLAGS(op, dst, dstw, src, srcw, type) \
- sljit_emit_op_flags(compiler, (op), (dst), (dstw), (src), (srcw), (type))
+#define OP_FLAGS(op, dst, dstw, type) \
+ sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type))
#define GET_LOCAL_BASE(dst, dstw, offset) \
sljit_get_local_base(compiler, (dst), (dstw), (offset))
#define READ_CHAR_MAX 0x7fffffff
+#define INVALID_UTF_CHAR 888
+
static pcre_uchar *bracketend(pcre_uchar *cc)
{
SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
return count;
}
-static int ones_in_half_byte[16] = {
- /* 0 */ 0, 1, 1, 2, /* 4 */ 1, 2, 2, 3,
- /* 8 */ 1, 2, 2, 3, /* 12 */ 2, 3, 3, 4
-};
-
/* Functions whose might need modification for all new supported opcodes:
next_opcode
check_opcode_types
default:
/* All opcodes are supported now! */
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
}
{
int count;
pcre_uchar *slot;
+pcre_uchar *assert_back_end = cc - 1;
/* Calculate important variables (like stack size) and checks whether all opcodes are supported. */
while (cc < ccend)
cc += 2 + 2 * LINK_SIZE;
break;
+ case OP_ASSERTBACK:
+ slot = bracketend(cc);
+ if (slot > assert_back_end)
+ assert_back_end = slot;
+ cc += 1 + LINK_SIZE;
+ break;
+
case OP_THEN_ARG:
common->has_then = TRUE;
common->control_head_ptr = 1;
/* Fall through. */
case OP_PRUNE_ARG:
- common->needs_start_ptr = TRUE;
- /* Fall through. */
-
case OP_MARK:
if (common->mark_ptr == 0)
{
case OP_THEN:
common->has_then = TRUE;
common->control_head_ptr = 1;
- /* Fall through. */
+ cc += 1;
+ break;
- case OP_PRUNE:
case OP_SKIP:
- common->needs_start_ptr = TRUE;
+ if (cc < assert_back_end)
+ common->has_skip_in_assert_back = TRUE;
cc += 1;
break;
case OP_SKIP_ARG:
common->control_head_ptr = 1;
common->has_skip_arg = TRUE;
+ if (cc < assert_back_end)
+ common->has_skip_in_assert_back = TRUE;
cc += 1 + 2 + cc[1];
break;
return TRUE;
}
+static BOOL is_accelerated_repeat(pcre_uchar *cc)
+{
+switch(*cc)
+ {
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ return (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI);
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ return TRUE;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+ case OP_XCLASS:
+ cc += (*cc == OP_XCLASS) ? GET(cc, 1) : (int)(1 + (32 / sizeof(pcre_uchar)));
+#else
+ cc += (1 + (32 / sizeof(pcre_uchar)));
+#endif
+
+ switch(*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ return TRUE;
+ }
+ break;
+ }
+return FALSE;
+}
+
+static SLJIT_INLINE BOOL detect_fast_forward_skip(compiler_common *common, int *private_data_start)
+{
+pcre_uchar *cc = common->start;
+pcre_uchar *end;
+
+/* Skip not repeated brackets. */
+while (TRUE)
+ {
+ switch(*cc)
+ {
+ case OP_SOD:
+ case OP_SOM:
+ case OP_SET_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ /* Zero width assertions. */
+ cc++;
+ continue;
+ }
+
+ if (*cc != OP_BRA && *cc != OP_CBRA)
+ break;
+
+ end = cc + GET(cc, 1);
+ if (*end != OP_KET || PRIVATE_DATA(end) != 0)
+ return FALSE;
+ if (*cc == OP_CBRA)
+ {
+ if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+ return FALSE;
+ cc += IMM2_SIZE;
+ }
+ cc += 1 + LINK_SIZE;
+ }
+
+if (is_accelerated_repeat(cc))
+ {
+ common->fast_forward_bc_ptr = cc;
+ common->private_data_ptrs[(cc + 1) - common->start] = *private_data_start;
+ *private_data_start += sizeof(sljit_sw);
+ return TRUE;
+ }
+return FALSE;
+}
+
+static SLJIT_INLINE void detect_fast_fail(compiler_common *common, pcre_uchar *cc, int *private_data_start, sljit_s32 depth)
+{
+ pcre_uchar *next_alt;
+
+ SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA);
+
+ if (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+ return;
+
+ next_alt = bracketend(cc) - (1 + LINK_SIZE);
+ if (*next_alt != OP_KET || PRIVATE_DATA(next_alt) != 0)
+ return;
+
+ do
+ {
+ next_alt = cc + GET(cc, 1);
+
+ cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0);
+
+ while (TRUE)
+ {
+ switch(*cc)
+ {
+ case OP_SOD:
+ case OP_SOM:
+ case OP_SET_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ /* Zero width assertions. */
+ cc++;
+ continue;
+ }
+ break;
+ }
+
+ if (depth > 0 && (*cc == OP_BRA || *cc == OP_CBRA))
+ detect_fast_fail(common, cc, private_data_start, depth - 1);
+
+ if (is_accelerated_repeat(cc))
+ {
+ common->private_data_ptrs[(cc + 1) - common->start] = *private_data_start;
+
+ if (common->fast_fail_start_ptr == 0)
+ common->fast_fail_start_ptr = *private_data_start;
+
+ *private_data_start += sizeof(sljit_sw);
+ common->fast_fail_end_ptr = *private_data_start;
+
+ if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
+ return;
+ }
+
+ cc = next_alt;
+ }
+ while (*cc == OP_ALT);
+}
+
static int get_class_iterator_size(pcre_uchar *cc)
{
+sljit_u32 min;
+sljit_u32 max;
switch(*cc)
{
case OP_CRSTAR:
case OP_CRRANGE:
case OP_CRMINRANGE:
- if (GET2(cc, 1) == GET2(cc, 1 + IMM2_SIZE))
- return 0;
- return 2;
+ min = GET2(cc, 1);
+ max = GET2(cc, 1 + IMM2_SIZE);
+ if (max == 0)
+ return (*cc == OP_CRRANGE) ? 2 : 1;
+ max -= min;
+ if (max > 2)
+ max = 2;
+ return max;
default:
return 0;
case OP_CLASS:
case OP_NCLASS:
- size += 1 + 32 / sizeof(pcre_uchar);
space = get_class_iterator_size(cc + size);
+ size = 1 + 32 / sizeof(pcre_uchar);
break;
#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
case OP_XCLASS:
- size = GET(cc, 1);
space = get_class_iterator_size(cc + size);
+ size = GET(cc, 1);
break;
#endif
case OP_CLASS:
case OP_NCLASS:
case OP_XCLASS:
+ case OP_CALLOUT:
cc = next_opcode(common, cc);
SLJIT_ASSERT(cc != NULL);
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0));
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
setsom_found = TRUE;
}
cc += 1;
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
setmark_found = TRUE;
}
cc += 1 + 2 + cc[1];
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0));
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
setsom_found = TRUE;
}
if (common->mark_ptr != 0 && !setmark_found)
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
setmark_found = TRUE;
}
if (common->capture_last_ptr != 0 && !capture_last_found)
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
capture_last_found = TRUE;
}
cc += 1 + LINK_SIZE;
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
capture_last_found = TRUE;
}
offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
- stackpos += (int)sizeof(sljit_sw);
+ stackpos -= (int)sizeof(sljit_sw);
cc += 1 + LINK_SIZE + IMM2_SIZE;
break;
BOOL tmp2empty = TRUE;
pcre_uchar *alternative;
enum {
- start,
loop,
end
} status;
-status = save ? start : loop;
-stackptr = STACK(stackptr - 2);
+status = loop;
+stackptr = STACK(stackptr);
stacktop = STACK(stacktop - 1);
if (!save)
{
- stackptr += (needs_control_head ? 2 : 1) * sizeof(sljit_sw);
+ stacktop -= (needs_control_head ? 2 : 1) * sizeof(sljit_sw);
if (stackptr < stacktop)
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr);
/* The tmp1next must be TRUE in either way. */
}
+SLJIT_ASSERT(common->recursive_head_ptr != 0);
+
do
{
count = 0;
- switch(status)
+ if (cc >= ccend)
{
- case start:
- SLJIT_ASSERT(save && common->recursive_head_ptr != 0);
+ if (!save)
+ break;
+
count = 1;
srcw[0] = common->recursive_head_ptr;
if (needs_control_head)
{
SLJIT_ASSERT(common->control_head_ptr != 0);
count = 2;
- srcw[1] = common->control_head_ptr;
+ srcw[0] = common->control_head_ptr;
+ srcw[1] = common->recursive_head_ptr;
+ }
+ status = end;
+ }
+ else switch(*cc)
+ {
+ case OP_KET:
+ if (PRIVATE_DATA(cc) != 0)
+ {
+ count = 1;
+ srcw[0] = PRIVATE_DATA(cc);
+ SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0);
+ cc += PRIVATE_DATA(cc + 1);
}
- status = loop;
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_ONCE_NC:
+ case OP_BRAPOS:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_SCOND:
+ count = 1;
+ srcw[0] = PRIVATE_DATA(cc);
+ SLJIT_ASSERT(srcw[0] != 0);
+ cc += 1 + LINK_SIZE;
break;
- case loop:
- if (cc >= ccend)
+ case OP_CBRA:
+ case OP_SCBRA:
+ if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
{
- status = end;
- break;
+ count = 1;
+ srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
}
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
- switch(*cc)
- {
- case OP_KET:
- if (PRIVATE_DATA(cc) != 0)
- {
- count = 1;
- srcw[0] = PRIVATE_DATA(cc);
- SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0);
- cc += PRIVATE_DATA(cc + 1);
- }
- cc += 1 + LINK_SIZE;
- break;
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ count = 2;
+ srcw[0] = PRIVATE_DATA(cc);
+ srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+ SLJIT_ASSERT(srcw[0] != 0 && srcw[1] != 0);
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
- case OP_ASSERT:
- case OP_ASSERT_NOT:
- case OP_ASSERTBACK:
- case OP_ASSERTBACK_NOT:
- case OP_ONCE:
- case OP_ONCE_NC:
- case OP_BRAPOS:
- case OP_SBRA:
- case OP_SBRAPOS:
- case OP_SCOND:
+ case OP_COND:
+ /* Might be a hidden SCOND. */
+ alternative = cc + GET(cc, 1);
+ if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+ {
count = 1;
srcw[0] = PRIVATE_DATA(cc);
SLJIT_ASSERT(srcw[0] != 0);
- cc += 1 + LINK_SIZE;
- break;
-
- case OP_CBRA:
- case OP_SCBRA:
- if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
- {
- count = 1;
- srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
- }
- cc += 1 + LINK_SIZE + IMM2_SIZE;
- break;
+ }
+ cc += 1 + LINK_SIZE;
+ break;
- case OP_CBRAPOS:
- case OP_SCBRAPOS:
- count = 2;
+ CASE_ITERATOR_PRIVATE_DATA_1
+ if (PRIVATE_DATA(cc))
+ {
+ count = 1;
srcw[0] = PRIVATE_DATA(cc);
- srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
- SLJIT_ASSERT(srcw[0] != 0 && srcw[1] != 0);
- cc += 1 + LINK_SIZE + IMM2_SIZE;
- break;
-
- case OP_COND:
- /* Might be a hidden SCOND. */
- alternative = cc + GET(cc, 1);
- if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
- {
- count = 1;
- srcw[0] = PRIVATE_DATA(cc);
- SLJIT_ASSERT(srcw[0] != 0);
- }
- cc += 1 + LINK_SIZE;
- break;
-
- CASE_ITERATOR_PRIVATE_DATA_1
- if (PRIVATE_DATA(cc))
- {
- count = 1;
- srcw[0] = PRIVATE_DATA(cc);
- }
- cc += 2;
+ }
+ cc += 2;
#ifdef SUPPORT_UTF
- if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
- break;
+ break;
- CASE_ITERATOR_PRIVATE_DATA_2A
- if (PRIVATE_DATA(cc))
- {
- count = 2;
- srcw[0] = PRIVATE_DATA(cc);
- srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
- }
- cc += 2;
+ CASE_ITERATOR_PRIVATE_DATA_2A
+ if (PRIVATE_DATA(cc))
+ {
+ count = 2;
+ srcw[0] = PRIVATE_DATA(cc);
+ srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
+ }
+ cc += 2;
#ifdef SUPPORT_UTF
- if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
- break;
+ break;
- CASE_ITERATOR_PRIVATE_DATA_2B
- if (PRIVATE_DATA(cc))
- {
- count = 2;
- srcw[0] = PRIVATE_DATA(cc);
- srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
- }
- cc += 2 + IMM2_SIZE;
+ CASE_ITERATOR_PRIVATE_DATA_2B
+ if (PRIVATE_DATA(cc))
+ {
+ count = 2;
+ srcw[0] = PRIVATE_DATA(cc);
+ srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
+ }
+ cc += 2 + IMM2_SIZE;
#ifdef SUPPORT_UTF
- if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
- break;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+ if (PRIVATE_DATA(cc))
+ {
+ count = 1;
+ srcw[0] = PRIVATE_DATA(cc);
+ }
+ cc += 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+ if (PRIVATE_DATA(cc))
+ {
+ count = 2;
+ srcw[0] = PRIVATE_DATA(cc);
+ srcw[1] = srcw[0] + sizeof(sljit_sw);
+ }
+ cc += 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+ if (PRIVATE_DATA(cc))
+ {
+ count = 2;
+ srcw[0] = PRIVATE_DATA(cc);
+ srcw[1] = srcw[0] + sizeof(sljit_sw);
+ }
+ cc += 1 + IMM2_SIZE;
+ break;
- CASE_ITERATOR_TYPE_PRIVATE_DATA_1
- if (PRIVATE_DATA(cc))
+ case OP_CLASS:
+ case OP_NCLASS:
+#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+ case OP_XCLASS:
+ size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar);
+#else
+ size = 1 + 32 / (int)sizeof(pcre_uchar);
+#endif
+ if (PRIVATE_DATA(cc))
+ switch(get_class_iterator_size(cc + size))
{
+ case 1:
count = 1;
srcw[0] = PRIVATE_DATA(cc);
- }
- cc += 1;
- break;
+ break;
- CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
- if (PRIVATE_DATA(cc))
- {
+ case 2:
count = 2;
srcw[0] = PRIVATE_DATA(cc);
srcw[1] = srcw[0] + sizeof(sljit_sw);
- }
- cc += 1;
- break;
+ break;
- CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
- if (PRIVATE_DATA(cc))
- {
- count = 2;
- srcw[0] = PRIVATE_DATA(cc);
- srcw[1] = srcw[0] + sizeof(sljit_sw);
+ default:
+ SLJIT_UNREACHABLE();
+ break;
}
- cc += 1 + IMM2_SIZE;
- break;
-
- case OP_CLASS:
- case OP_NCLASS:
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- case OP_XCLASS:
- size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar);
-#else
- size = 1 + 32 / (int)sizeof(pcre_uchar);
-#endif
- if (PRIVATE_DATA(cc))
- switch(get_class_iterator_size(cc + size))
- {
- case 1:
- count = 1;
- srcw[0] = PRIVATE_DATA(cc);
- break;
-
- case 2:
- count = 2;
- srcw[0] = PRIVATE_DATA(cc);
- srcw[1] = srcw[0] + sizeof(sljit_sw);
- break;
-
- default:
- SLJIT_ASSERT_STOP();
- break;
- }
- cc += size;
- break;
-
- default:
- cc = next_opcode(common, cc);
- SLJIT_ASSERT(cc != NULL);
- break;
- }
+ cc += size;
break;
- case end:
- SLJIT_ASSERT_STOP();
+ default:
+ cc = next_opcode(common, cc);
+ SLJIT_ASSERT(cc != NULL);
break;
}
SLJIT_ASSERT(cc == ccend && stackptr == stacktop && (save || (tmp1empty && tmp2empty)));
}
-static SLJIT_INLINE pcre_uchar *set_then_offsets(compiler_common *common, pcre_uchar *cc, pcre_uint8 *current_offset)
+static SLJIT_INLINE pcre_uchar *set_then_offsets(compiler_common *common, pcre_uchar *cc, sljit_u8 *current_offset)
{
pcre_uchar *end = bracketend(cc);
BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT;
{
DEFINE_COMPILER;
-OP2(SLJIT_SUB | SLJIT_SET_E, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1);
+OP2(SLJIT_SUB | SLJIT_SET_Z, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1);
add_jump(compiler, &common->calllimit, JUMP(SLJIT_ZERO));
}
/* May destroy all locals and registers except TMP2. */
DEFINE_COMPILER;
-OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
+SLJIT_ASSERT(size > 0);
+OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
#ifdef DESTROY_REGISTERS
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP1, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0);
#endif
-add_stub(common, CMP(SLJIT_GREATER, STACK_TOP, 0, STACK_LIMIT, 0));
+add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0));
}
static SLJIT_INLINE void free_stack(compiler_common *common, int size)
{
DEFINE_COMPILER;
-OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
+
+SLJIT_ASSERT(size > 0);
+OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
}
static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size)
OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
loop = LABEL();
OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw), SLJIT_R0, 0);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, loop);
}
}
+static SLJIT_INLINE void reset_fast_fail(compiler_common *common)
+{
+DEFINE_COMPILER;
+sljit_s32 i;
+
+SLJIT_ASSERT(common->fast_fail_start_ptr < common->fast_fail_end_ptr);
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+for (i = common->fast_fail_start_ptr; i < common->fast_fail_end_ptr; i += sizeof(sljit_sw))
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), i, TMP1, 0);
+}
+
static SLJIT_INLINE void do_reset_match(compiler_common *common, int length)
{
DEFINE_COMPILER;
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
loop = LABEL();
OP1(SLJIT_MOVU, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0);
- OP2(SLJIT_SUB | SLJIT_SET_E, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, loop);
}
{
while (current != NULL)
{
- switch (current[-2])
+ switch (current[1])
{
case type_then_trap:
break;
case type_mark:
- if (STRCMP_UC_UC(skip_arg, (pcre_uchar *)current[-3]) == 0)
- return current[-4];
+ if (STRCMP_UC_UC(skip_arg, (pcre_uchar *)current[2]) == 0)
+ return current[3];
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
- SLJIT_ASSERT(current > (sljit_sw*)current[-1]);
- current = (sljit_sw*)current[-1];
+ SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]);
+ current = (sljit_sw*)current[0];
}
return -1;
}
OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
-OP1(SLJIT_MOV_SI, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offset_count));
+OP1(SLJIT_MOV_S32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offset_count));
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0);
OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int));
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOVU_SI, SLJIT_MEM1(SLJIT_R2), sizeof(int), SLJIT_S1, 0);
-OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+OP1(SLJIT_MOVU_S32, SLJIT_MEM1(SLJIT_R2), sizeof(int), SLJIT_S1, 0);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, loop);
JUMPHERE(early_quit);
OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_PARTIAL);
-OP1(SLJIT_MOV_SI, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, real_offset_count));
+OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, real_offset_count));
CMPTO(SLJIT_SIG_LESS, SLJIT_R2, 0, SLJIT_IMM, 2, quit);
/* Store match begin and end. */
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_R1), 2 * sizeof(int), SLJIT_R2, 0);
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), 2 * sizeof(int), SLJIT_R2, 0);
JUMPHERE(jump);
OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_used_ptr : common->hit_start);
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_R1), sizeof(int), SLJIT_S1, 0);
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), sizeof(int), SLJIT_S1, 0);
OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S0, 0);
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R2, 0);
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R2, 0);
JUMPTO(SLJIT_JUMP, quit);
}
JUMPHERE(jump);
}
-static void peek_char(compiler_common *common, pcre_uint32 max)
+static void peek_char(compiler_common *common, sljit_u32 max)
{
/* Reads the character into TMP1, keeps STR_PTR.
Does not check STR_END. TMP2 Destroyed. */
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
-static BOOL is_char7_bitset(const pcre_uint8 *bitset, BOOL nclass)
+static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass)
{
/* Tells whether the character codes below 128 are enough
to determine a match. */
-const pcre_uint8 value = nclass ? 0xff : 0;
-const pcre_uint8 *end = bitset + 32;
+const sljit_u8 value = nclass ? 0xff : 0;
+const sljit_u8 *end = bitset + 32;
bitset += 16;
do
OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
if (full_read)
{
jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xc0);
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
JUMPHERE(jump);
}
#endif /* SUPPORT_UTF && COMPILE_PCRE8 */
-static void read_char_range(compiler_common *common, pcre_uint32 min, pcre_uint32 max, BOOL update_str_ptr)
+static void read_char_range(compiler_common *common, sljit_u32 min, sljit_u32 max, BOOL update_str_ptr)
{
/* Reads the precise value of a character into TMP1, if the character is
between min and max (c >= min && c <= max). Otherwise it returns with a value
{
OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xf0);
if (update_str_ptr)
- OP1(SLJIT_MOV_UB, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x7);
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
{
OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xe0);
if (update_str_ptr)
- OP1(SLJIT_MOV_UB, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xf);
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
add_jump(compiler, (max < 0x10000) ? &common->utfreadchar16 : &common->utfreadchar, JUMP(SLJIT_FAST_CALL));
else if (max < 128)
{
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
}
else
if (!update_str_ptr)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
else
- OP1(SLJIT_MOV_UB, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
{
/* This can be an extra read in some situations, but hopefully
it is needed in most cases. */
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xc0);
if (!update_str_ptr)
{
OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
JUMPHERE(jump2);
}
else
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
#endif
-OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
#if !defined COMPILE_PCRE8
JUMPHERE(jump);
#endif
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
/* Skip low surrogate if necessary. */
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
return;
if (nltype == NLTYPE_ANY)
{
add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
add_jump(compiler, backtracks, JUMP(jumpifmatch ? SLJIT_NOT_ZERO : SLJIT_ZERO));
}
else if (nltype == NLTYPE_ANYCRLF)
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
/* Searching for the first zero. */
-OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
jump = JUMP(SLJIT_NOT_ZERO);
/* Two byte sequence. */
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
-OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000);
jump = JUMP(SLJIT_NOT_ZERO);
/* Three byte sequence. */
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
/* Searching for the first zero. */
-OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
jump = JUMP(SLJIT_NOT_ZERO);
/* Two byte sequence. */
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
JUMPHERE(jump);
-OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400);
-OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_NOT_ZERO);
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO);
/* This code runs only in 8 bit mode. No need to shift the value. */
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
-OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20);
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20);
jump = JUMP(SLJIT_NOT_ZERO);
/* Two byte sequence. */
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0);
-OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
JUMPHERE(compare);
/* We only have types for characters less than 256. */
JUMPHERE(jump);
-OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
/* Search the UCD record for the character comes in TMP1.
Returns chartype in TMP1 and UCD offset in TMP2. */
DEFINE_COMPILER;
+#ifdef COMPILE_PCRE32
+struct sljit_jump *jump;
+#endif
+
+#if defined SLJIT_DEBUG && SLJIT_DEBUG
+/* dummy_ucd_record */
+const ucd_record *record = GET_UCD(INVALID_UTF_CHAR);
+SLJIT_ASSERT(record->script == ucp_Common && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther);
+SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0);
+#endif
SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 8);
sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+#ifdef COMPILE_PCRE32
+if (!common->utf)
+ {
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10ffff + 1);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+ JUMPHERE(jump);
+ }
+#endif
+
OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
-OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
-OP1(SLJIT_MOV_UH, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
-OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
#endif
-static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf, BOOL firstline)
+static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf)
{
DEFINE_COMPILER;
struct sljit_label *mainloop;
struct sljit_label *newlinelabel = NULL;
struct sljit_jump *start;
struct sljit_jump *end = NULL;
-struct sljit_jump *nl = NULL;
+struct sljit_jump *end2 = NULL;
#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
struct sljit_jump *singlechar;
#endif
BOOL newlinecheck = FALSE;
BOOL readuchar = FALSE;
-if (!(hascrorlf || firstline) && (common->nltype == NLTYPE_ANY ||
- common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
+if (!(hascrorlf || (common->match_end_ptr != 0)) &&
+ (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
newlinecheck = TRUE;
-if (firstline)
+if (common->match_end_ptr != 0)
{
/* Search for the end of the first line. */
- SLJIT_ASSERT(common->first_line_end != 0);
OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
if (common->nltype == NLTYPE_FIXED && common->newline > 255)
CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop);
CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop);
JUMPHERE(end);
- OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->first_line_end, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
}
else
{
end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
mainloop = LABEL();
/* Continual stores does not cause data dependency. */
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->first_line_end, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0);
read_char_range(common, common->nlmin, common->nlmax, TRUE);
check_newlinechar(common, common->nltype, &newline, TRUE);
CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, mainloop);
JUMPHERE(end);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->first_line_end, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0);
set_jumps(newline, LABEL());
}
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
- nl = JUMP(SLJIT_JUMP);
+ end2 = JUMP(SLJIT_JUMP);
}
mainloop = LABEL();
if (common->utf)
{
singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
JUMPHERE(singlechar);
}
{
singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
JUMPHERE(singlechar);
if (newlinecheck)
{
JUMPHERE(end);
- JUMPHERE(nl);
+ JUMPHERE(end2);
}
return mainloop;
}
#define MAX_N_CHARS 16
-#define MAX_N_BYTES 8
+#define MAX_DIFF_CHARS 6
-static SLJIT_INLINE void add_prefix_byte(pcre_uint8 byte, pcre_uint8 *bytes)
+static SLJIT_INLINE void add_prefix_char(pcre_uchar chr, pcre_uchar *chars)
{
-pcre_uint8 len = bytes[0];
-int i;
+pcre_uchar i, len;
+len = chars[0];
if (len == 255)
return;
if (len == 0)
{
- bytes[0] = 1;
- bytes[1] = byte;
+ chars[0] = 1;
+ chars[1] = chr;
return;
}
for (i = len; i > 0; i--)
- if (bytes[i] == byte)
+ if (chars[i] == chr)
return;
-if (len >= MAX_N_BYTES - 1)
+if (len >= MAX_DIFF_CHARS - 1)
{
- bytes[0] = 255;
+ chars[0] = 255;
return;
}
len++;
-bytes[len] = byte;
-bytes[0] = len;
+chars[len] = chr;
+chars[0] = len;
}
-static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars, pcre_uint32 *rec_count)
+static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uchar *chars, int max_chars, sljit_u32 *rec_count)
{
/* Recursive function, which scans prefix literals. */
-BOOL last, any, caseless;
+BOOL last, any, class, caseless;
int len, repeat, len_save, consumed = 0;
-pcre_uint32 chr, mask;
+sljit_u32 chr; /* Any unicode character. */
+sljit_u8 *bytes, *bytes_end, byte;
pcre_uchar *alternative, *cc_save, *oc;
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
pcre_uchar othercase[8];
last = TRUE;
any = FALSE;
+ class = FALSE;
caseless = FALSE;
switch (*cc)
#ifdef SUPPORT_UTF
if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
#endif
- max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars, rec_count);
+ max_chars = scan_prefix(common, cc + len, chars, max_chars, rec_count);
if (max_chars == 0)
return consumed;
last = FALSE;
alternative = cc + GET(cc, 1);
while (*alternative == OP_ALT)
{
- max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars, rec_count);
+ max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, max_chars, rec_count);
if (max_chars == 0)
return consumed;
alternative += GET(alternative, 1);
case OP_CLASS:
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && !is_char7_bitset((const pcre_uint8 *)(cc + 1), FALSE)) return consumed;
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)(cc + 1), FALSE))
+ return consumed;
#endif
- any = TRUE;
- cc += 1 + 32 / sizeof(pcre_uchar);
+ class = TRUE;
break;
case OP_NCLASS:
#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
if (common->utf) return consumed;
#endif
- any = TRUE;
- cc += 1 + 32 / sizeof(pcre_uchar);
+ class = TRUE;
break;
#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
case OP_DIGIT:
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && !is_char7_bitset((const pcre_uint8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
return consumed;
#endif
any = TRUE;
case OP_WHITESPACE:
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && !is_char7_bitset((const pcre_uint8 *)common->ctypes - cbit_length + cbit_space, FALSE))
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE))
return consumed;
#endif
any = TRUE;
case OP_WORDCHAR:
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && !is_char7_bitset((const pcre_uint8 *)common->ctypes - cbit_length + cbit_word, FALSE))
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE))
return consumed;
#endif
any = TRUE;
cc++;
break;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UTF
case OP_NOTPROP:
case OP_PROP:
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#ifndef COMPILE_PCRE32
if (common->utf) return consumed;
#endif
any = TRUE;
if (any)
{
-#if defined COMPILE_PCRE8
- mask = 0xff;
-#elif defined COMPILE_PCRE16
- mask = 0xffff;
-#elif defined COMPILE_PCRE32
- mask = 0xffffffff;
-#else
- SLJIT_ASSERT_STOP();
-#endif
+ do
+ {
+ chars[0] = 255;
+
+ consumed++;
+ if (--max_chars == 0)
+ return consumed;
+ chars += MAX_DIFF_CHARS;
+ }
+ while (--repeat > 0);
+
+ repeat = 1;
+ continue;
+ }
+
+ if (class)
+ {
+ bytes = (sljit_u8*) (cc + 1);
+ cc += 1 + 32 / sizeof(pcre_uchar);
+
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPOSSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSQUERY:
+ max_chars = scan_prefix(common, cc + 1, chars, max_chars, rec_count);
+ if (max_chars == 0)
+ return consumed;
+ break;
+
+ default:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ repeat = GET2(cc, 1);
+ if (repeat <= 0)
+ return consumed;
+ break;
+ }
do
{
- chars[0] = mask;
- chars[1] = mask;
- bytes[0] = 255;
+ if (bytes[31] & 0x80)
+ chars[0] = 255;
+ else if (chars[0] != 255)
+ {
+ bytes_end = bytes + 32;
+ chr = 0;
+ do
+ {
+ byte = *bytes++;
+ SLJIT_ASSERT((chr & 0x7) == 0);
+ if (byte == 0)
+ chr += 8;
+ else
+ {
+ do
+ {
+ if ((byte & 0x1) != 0)
+ add_prefix_char(chr, chars);
+ byte >>= 1;
+ chr++;
+ }
+ while (byte != 0);
+ chr = (chr + 7) & ~7;
+ }
+ }
+ while (chars[0] != 255 && bytes < bytes_end);
+ bytes = bytes_end - 32;
+ }
consumed++;
if (--max_chars == 0)
return consumed;
- chars += 2;
- bytes += MAX_N_BYTES;
+ chars += MAX_DIFF_CHARS;
}
while (--repeat > 0);
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPOSSTAR:
+ return consumed;
+
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSQUERY:
+ cc++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ if (GET2(cc, 1) != GET2(cc, 1 + IMM2_SIZE))
+ return consumed;
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+ }
+
repeat = 1;
continue;
}
}
}
else
+ {
caseless = FALSE;
+ othercase[0] = 0; /* Stops compiler warning - PH */
+ }
len_save = len;
cc_save = cc;
do
{
chr = *cc;
-#ifdef COMPILE_PCRE32
- if (SLJIT_UNLIKELY(chr == NOTACHAR))
- return consumed;
-#endif
- add_prefix_byte((pcre_uint8)chr, bytes);
+ add_prefix_char(*cc, chars);
- mask = 0;
if (caseless)
- {
- add_prefix_byte((pcre_uint8)*oc, bytes);
- mask = *cc ^ *oc;
- chr |= mask;
- }
-
-#ifdef COMPILE_PCRE32
- if (chars[0] == NOTACHAR && chars[1] == 0)
-#else
- if (chars[0] == NOTACHAR)
-#endif
- {
- chars[0] = chr;
- chars[1] = mask;
- }
- else
- {
- mask |= chars[0] ^ chr;
- chr |= mask;
- chars[0] = chr;
- chars[1] |= mask;
- }
+ add_prefix_char(*oc, chars);
len--;
consumed++;
if (--max_chars == 0)
return consumed;
- chars += 2;
- bytes += MAX_N_BYTES;
+ chars += MAX_DIFF_CHARS;
cc++;
oc++;
}
}
}
-static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common, BOOL firstline)
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND)
+
+static sljit_s32 character_to_int32(pcre_uchar chr)
+{
+sljit_s32 value = (sljit_s32)chr;
+#if defined COMPILE_PCRE8
+#define SSE2_COMPARE_TYPE_INDEX 0
+return (value << 24) | (value << 16) | (value << 8) | value;
+#elif defined COMPILE_PCRE16
+#define SSE2_COMPARE_TYPE_INDEX 1
+return (value << 16) | value;
+#elif defined COMPILE_PCRE32
+#define SSE2_COMPARE_TYPE_INDEX 2
+return value;
+#else
+#error "Unsupported unit width"
+#endif
+}
+
+static SLJIT_INLINE void fast_forward_first_char2_sse2(compiler_common *common, pcre_uchar char1, pcre_uchar char2)
{
DEFINE_COMPILER;
struct sljit_label *start;
-struct sljit_jump *quit;
-pcre_uint32 chars[MAX_N_CHARS * 2];
-pcre_uint8 bytes[MAX_N_CHARS * MAX_N_BYTES];
-pcre_uint8 ones[MAX_N_CHARS];
-int offsets[3];
-pcre_uint32 mask;
-pcre_uint8 *byte_set, *byte_set_end;
-int i, max, from;
-int range_right = -1, range_len = 3 - 1;
-sljit_ub *update_table = NULL;
-BOOL in_range;
-pcre_uint32 rec_count;
+struct sljit_jump *quit[3];
+struct sljit_jump *nomatch;
+sljit_u8 instruction[8];
+sljit_s32 tmp1_ind = sljit_get_register_index(TMP1);
+sljit_s32 tmp2_ind = sljit_get_register_index(TMP2);
+sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR);
+BOOL load_twice = FALSE;
+pcre_uchar bit;
+
+bit = char1 ^ char2;
+if (!is_powerof2(bit))
+ bit = 0;
-for (i = 0; i < MAX_N_CHARS; i++)
+if ((char1 != char2) && bit == 0)
+ load_twice = TRUE;
+
+quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
+
+SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1);
+
+/* MOVD xmm, r/m32 */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6e;
+instruction[3] = 0xc0 | (2 << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char1 != char2)
{
- chars[i << 1] = NOTACHAR;
- chars[(i << 1) + 1] = 0;
- bytes[i * MAX_N_BYTES] = 0;
- }
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
-rec_count = 10000;
-max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS, &rec_count);
+ /* MOVD xmm, r/m32 */
+ instruction[3] = 0xc0 | (3 << 3) | tmp1_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
-if (max <= 1)
- return FALSE;
+/* PSHUFD xmm1, xmm2/m128, imm8 */
+instruction[2] = 0x70;
+instruction[3] = 0xc0 | (2 << 3) | 2;
+instruction[4] = 0;
+sljit_emit_op_custom(compiler, instruction, 5);
-for (i = 0; i < max; i++)
+if (char1 != char2)
{
- mask = chars[(i << 1) + 1];
- ones[i] = ones_in_half_byte[mask & 0xf];
- mask >>= 4;
- while (mask != 0)
- {
- ones[i] += ones_in_half_byte[mask & 0xf];
- mask >>= 4;
- }
+ /* PSHUFD xmm1, xmm2/m128, imm8 */
+ instruction[3] = 0xc0 | (3 << 3) | 3;
+ instruction[4] = 0;
+ sljit_emit_op_custom(compiler, instruction, 5);
}
-in_range = FALSE;
-from = 0; /* Prevent compiler "uninitialized" warning */
-for (i = 0; i <= max; i++)
+OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+
+/* MOVDQA xmm1, xmm2/m128 */
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+
+if (str_ptr_ind < 8)
{
- if (in_range && (i - from) > range_len && (bytes[(i - 1) * MAX_N_BYTES] <= 4))
- {
- range_len = i - from;
- range_right = i - 1;
- }
+ instruction[2] = 0x6f;
+ instruction[3] = (0 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
- if (i < max && bytes[i * MAX_N_BYTES] < 255)
+ if (load_twice)
{
- if (!in_range)
- {
- in_range = TRUE;
- from = i;
- }
+ instruction[3] = (1 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
}
- else if (in_range)
- in_range = FALSE;
}
-
-if (range_right >= 0)
+else
{
- update_table = (sljit_ub *)allocate_read_only_data(common, 256);
- if (update_table == NULL)
- return TRUE;
- memset(update_table, IN_UCHARS(range_len), 256);
+ instruction[1] = 0x41;
+ instruction[2] = 0x0f;
+ instruction[3] = 0x6f;
+ instruction[4] = (0 << 3) | (str_ptr_ind & 0x7);
+ sljit_emit_op_custom(compiler, instruction, 5);
- for (i = 0; i < range_len; i++)
+ if (load_twice)
{
- byte_set = bytes + ((range_right - i) * MAX_N_BYTES);
- SLJIT_ASSERT(byte_set[0] > 0 && byte_set[0] < 255);
- byte_set_end = byte_set + byte_set[0];
- byte_set++;
- while (byte_set <= byte_set_end)
- {
- if (update_table[*byte_set] > IN_UCHARS(i))
- update_table[*byte_set] = IN_UCHARS(i);
- byte_set++;
- }
+ instruction[4] = (1 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 5);
}
+ instruction[1] = 0x0f;
}
-offsets[0] = -1;
-/* Scan forward. */
-for (i = 0; i < max; i++)
- if (ones[i] <= 2) {
- offsets[0] = i;
- break;
+#else
+
+instruction[2] = 0x6f;
+instruction[3] = (0 << 3) | str_ptr_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (load_twice)
+ {
+ instruction[3] = (1 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
}
-if (offsets[0] < 0 && range_right < 0)
- return FALSE;
+#endif
-if (offsets[0] >= 0)
+if (bit != 0)
{
- /* Scan backward. */
- offsets[1] = -1;
- for (i = max - 1; i > offsets[0]; i--)
- if (ones[i] <= 2 && i != range_right)
- {
- offsets[1] = i;
- break;
- }
+ /* POR xmm1, xmm2/m128 */
+ instruction[2] = 0xeb;
+ instruction[3] = 0xc0 | (0 << 3) | 3;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
- /* This case is handled better by fast_forward_first_char. */
- if (offsets[1] == -1 && offsets[0] == 0 && range_right < 0)
- return FALSE;
+/* PCMPEQB/W/D xmm1, xmm2/m128 */
+instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+instruction[3] = 0xc0 | (0 << 3) | 2;
+sljit_emit_op_custom(compiler, instruction, 4);
- offsets[2] = -1;
- /* We only search for a middle character if there is no range check. */
- if (offsets[1] >= 0 && range_right == -1)
- {
- /* Scan from middle. */
- for (i = (offsets[0] + offsets[1]) / 2 + 1; i < offsets[1]; i++)
- if (ones[i] <= 2)
- {
- offsets[2] = i;
- break;
- }
+if (load_twice)
+ {
+ instruction[3] = 0xc0 | (1 << 3) | 3;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
- if (offsets[2] == -1)
- {
- for (i = (offsets[0] + offsets[1]) / 2; i > offsets[0]; i--)
- if (ones[i] <= 2)
- {
- offsets[2] = i;
- break;
- }
- }
- }
+/* PMOVMSKB reg, xmm */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
- SLJIT_ASSERT(offsets[1] == -1 || (offsets[0] < offsets[1]));
- SLJIT_ASSERT(offsets[2] == -1 || (offsets[0] < offsets[2] && offsets[1] > offsets[2]));
+if (load_twice)
+ {
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP2, 0);
+ instruction[3] = 0xc0 | (tmp2_ind << 3) | 1;
+ sljit_emit_op_custom(compiler, instruction, 4);
- chars[0] = chars[offsets[0] << 1];
- chars[1] = chars[(offsets[0] << 1) + 1];
- if (offsets[2] >= 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP1(SLJIT_MOV, TMP2, 0, RETURN_ADDR, 0);
+ }
+
+OP2(SLJIT_ASHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+sljit_set_current_flags(compiler, SLJIT_SET_Z);
+
+nomatch = JUMP(SLJIT_ZERO);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+quit[1] = JUMP(SLJIT_JUMP);
+
+JUMPHERE(nomatch);
+
+start = LABEL();
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+quit[2] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+/* Second part (aligned) */
+
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+
+/* MOVDQA xmm1, xmm2/m128 */
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+
+if (str_ptr_ind < 8)
+ {
+ instruction[2] = 0x6f;
+ instruction[3] = (0 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+
+ if (load_twice)
+ {
+ instruction[3] = (1 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+ }
+else
+ {
+ instruction[1] = 0x41;
+ instruction[2] = 0x0f;
+ instruction[3] = 0x6f;
+ instruction[4] = (0 << 3) | (str_ptr_ind & 0x7);
+ sljit_emit_op_custom(compiler, instruction, 5);
+
+ if (load_twice)
+ {
+ instruction[4] = (1 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 5);
+ }
+ instruction[1] = 0x0f;
+ }
+
+#else
+
+instruction[2] = 0x6f;
+instruction[3] = (0 << 3) | str_ptr_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (load_twice)
+ {
+ instruction[3] = (1 << 3) | str_ptr_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+#endif
+
+if (bit != 0)
+ {
+ /* POR xmm1, xmm2/m128 */
+ instruction[2] = 0xeb;
+ instruction[3] = 0xc0 | (0 << 3) | 3;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+/* PCMPEQB/W/D xmm1, xmm2/m128 */
+instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+instruction[3] = 0xc0 | (0 << 3) | 2;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (load_twice)
+ {
+ instruction[3] = 0xc0 | (1 << 3) | 3;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+/* PMOVMSKB reg, xmm */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (load_twice)
+ {
+ instruction[3] = 0xc0 | (tmp2_ind << 3) | 1;
+ sljit_emit_op_custom(compiler, instruction, 4);
+
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ }
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+sljit_set_current_flags(compiler, SLJIT_SET_Z);
+
+JUMPTO(SLJIT_ZERO, start);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+start = LABEL();
+SET_LABEL(quit[0], start);
+SET_LABEL(quit[1], start);
+SET_LABEL(quit[2], start);
+}
+
+#undef SSE2_COMPARE_TYPE_INDEX
+
+#endif
+
+static void fast_forward_first_char2(compiler_common *common, pcre_uchar char1, pcre_uchar char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *quit;
+struct sljit_jump *found;
+pcre_uchar mask;
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+struct sljit_label *utf_start = NULL;
+struct sljit_jump *utf_quit = NULL;
+#endif
+BOOL has_match_end = (common->match_end_ptr != 0);
+
+if (offset > 0)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+
+if (has_match_end)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+
+ OP2(SLJIT_ADD, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, SLJIT_IMM, IN_UCHARS(offset + 1));
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP3, 0);
+ sljit_emit_cmov(compiler, SLJIT_GREATER, STR_END, TMP3, 0);
+ }
+
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+if (common->utf && offset > 0)
+ utf_start = LABEL();
+#endif
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND)
+
+/* SSE2 accelerated first character search. */
+
+if (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+ {
+ fast_forward_first_char2_sse2(common, char1, char2);
+
+ SLJIT_ASSERT(common->mode == JIT_COMPILE || offset == 0);
+ if (common->mode == JIT_COMPILE)
+ {
+ /* In complete mode, we don't need to run a match when STR_PTR == STR_END. */
+ SLJIT_ASSERT(common->forced_quit_label == NULL);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
+ add_jump(compiler, &common->forced_quit, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+ if (common->utf && offset > 0)
+ {
+ SLJIT_ASSERT(common->mode == JIT_COMPILE);
+
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+#if defined COMPILE_PCRE8
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start);
+#elif defined COMPILE_PCRE16
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start);
+#else
+#error "Unknown code width"
+#endif
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+#endif
+
+ if (offset > 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+ }
+ else
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+ if (has_match_end)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ sljit_emit_cmov(compiler, SLJIT_GREATER_EQUAL, STR_PTR, TMP1, 0);
+ }
+ else
+ sljit_emit_cmov(compiler, SLJIT_GREATER_EQUAL, STR_PTR, STR_END, 0);
+ }
+
+ if (has_match_end)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+ return;
+ }
+
+#endif
+
+quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+start = LABEL();
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+
+if (char1 == char2)
+ found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1);
+else
+ {
+ mask = char1 ^ char2;
+ if (is_powerof2(mask))
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask);
+ found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask);
+ }
+ else
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char1);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char2);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+ found = JUMP(SLJIT_NOT_ZERO);
+ }
+ }
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, start);
+
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+if (common->utf && offset > 0)
+ utf_quit = JUMP(SLJIT_JUMP);
+#endif
+
+JUMPHERE(found);
+
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+if (common->utf && offset > 0)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+#if defined COMPILE_PCRE8
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start);
+#elif defined COMPILE_PCRE16
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start);
+#else
+#error "Unknown code width"
+#endif
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPHERE(utf_quit);
+ }
+#endif
+
+JUMPHERE(quit);
+
+if (has_match_end)
+ {
+ quit = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ if (offset > 0)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+ JUMPHERE(quit);
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+ }
+
+if (offset > 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+}
+
+static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *quit;
+struct sljit_jump *match;
+/* bytes[0] represent the number of characters between 0
+and MAX_N_BYTES - 1, 255 represents any character. */
+pcre_uchar chars[MAX_N_CHARS * MAX_DIFF_CHARS];
+sljit_s32 offset;
+pcre_uchar mask;
+pcre_uchar *char_set, *char_set_end;
+int i, max, from;
+int range_right = -1, range_len;
+sljit_u8 *update_table = NULL;
+BOOL in_range;
+sljit_u32 rec_count;
+
+for (i = 0; i < MAX_N_CHARS; i++)
+ chars[i * MAX_DIFF_CHARS] = 0;
+
+rec_count = 10000;
+max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count);
+
+if (max < 1)
+ return FALSE;
+
+in_range = FALSE;
+/* Prevent compiler "uninitialized" warning */
+from = 0;
+range_len = 4 /* minimum length */ - 1;
+for (i = 0; i <= max; i++)
+ {
+ if (in_range && (i - from) > range_len && (chars[(i - 1) * MAX_DIFF_CHARS] < 255))
{
- chars[2] = chars[offsets[2] << 1];
- chars[3] = chars[(offsets[2] << 1) + 1];
+ range_len = i - from;
+ range_right = i - 1;
}
- if (offsets[1] >= 0)
+
+ if (i < max && chars[i * MAX_DIFF_CHARS] < 255)
{
- chars[4] = chars[offsets[1] << 1];
- chars[5] = chars[(offsets[1] << 1) + 1];
+ SLJIT_ASSERT(chars[i * MAX_DIFF_CHARS] > 0);
+ if (!in_range)
+ {
+ in_range = TRUE;
+ from = i;
+ }
}
+ else
+ in_range = FALSE;
}
+if (range_right >= 0)
+ {
+ update_table = (sljit_u8 *)allocate_read_only_data(common, 256);
+ if (update_table == NULL)
+ return TRUE;
+ memset(update_table, IN_UCHARS(range_len), 256);
+
+ for (i = 0; i < range_len; i++)
+ {
+ char_set = chars + ((range_right - i) * MAX_DIFF_CHARS);
+ SLJIT_ASSERT(char_set[0] > 0 && char_set[0] < 255);
+ char_set_end = char_set + char_set[0];
+ char_set++;
+ while (char_set <= char_set_end)
+ {
+ if (update_table[(*char_set) & 0xff] > IN_UCHARS(i))
+ update_table[(*char_set) & 0xff] = IN_UCHARS(i);
+ char_set++;
+ }
+ }
+ }
+
+offset = -1;
+/* Scan forward. */
+for (i = 0; i < max; i++)
+ {
+ if (offset == -1)
+ {
+ if (chars[i * MAX_DIFF_CHARS] <= 2)
+ offset = i;
+ }
+ else if (chars[offset * MAX_DIFF_CHARS] == 2 && chars[i * MAX_DIFF_CHARS] <= 2)
+ {
+ if (chars[i * MAX_DIFF_CHARS] == 1)
+ offset = i;
+ else
+ {
+ mask = chars[offset * MAX_DIFF_CHARS + 1] ^ chars[offset * MAX_DIFF_CHARS + 2];
+ if (!is_powerof2(mask))
+ {
+ mask = chars[i * MAX_DIFF_CHARS + 1] ^ chars[i * MAX_DIFF_CHARS + 2];
+ if (is_powerof2(mask))
+ offset = i;
+ }
+ }
+ }
+ }
+
+if (range_right < 0)
+ {
+ if (offset < 0)
+ return FALSE;
+ SLJIT_ASSERT(chars[offset * MAX_DIFF_CHARS] >= 1 && chars[offset * MAX_DIFF_CHARS] <= 2);
+ /* Works regardless the value is 1 or 2. */
+ mask = chars[offset * MAX_DIFF_CHARS + chars[offset * MAX_DIFF_CHARS]];
+ fast_forward_first_char2(common, chars[offset * MAX_DIFF_CHARS + 1], mask, offset);
+ return TRUE;
+ }
+
+if (range_right == offset)
+ offset = -1;
+
+SLJIT_ASSERT(offset == -1 || (chars[offset * MAX_DIFF_CHARS] >= 1 && chars[offset * MAX_DIFF_CHARS] <= 2));
+
max -= 1;
-if (firstline)
+SLJIT_ASSERT(max > 0);
+if (common->match_end_ptr != 0)
{
- SLJIT_ASSERT(common->first_line_end != 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->first_line_end);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
quit = CMP(SLJIT_LESS_EQUAL, STR_END, 0, TMP1, 0);
else
OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+SLJIT_ASSERT(range_right >= 0);
+
#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
-if (range_right >= 0)
- OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table);
+OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table);
#endif
start = LABEL();
quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
-SLJIT_ASSERT(range_right >= 0 || offsets[0] >= 0);
-
-if (range_right >= 0)
- {
#if defined COMPILE_PCRE8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right));
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right));
#else
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1);
#endif
#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0);
#else
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table);
#endif
- OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
- CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start);
- }
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start);
-if (offsets[0] >= 0)
+if (offset >= 0)
{
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offsets[0]));
- if (offsets[1] >= 0)
- OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offsets[1]));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offset));
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
- if (chars[1] != 0)
- OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, chars[1]);
- CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[0], start);
- if (offsets[2] >= 0)
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offsets[2] - 1));
-
- if (offsets[1] >= 0)
+ if (chars[offset * MAX_DIFF_CHARS] == 1)
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1], start);
+ else
{
- if (chars[5] != 0)
- OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, chars[5]);
- CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, chars[4], start);
+ mask = chars[offset * MAX_DIFF_CHARS + 1] ^ chars[offset * MAX_DIFF_CHARS + 2];
+ if (is_powerof2(mask))
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1] | mask, start);
+ }
+ else
+ {
+ match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1]);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 2], start);
+ JUMPHERE(match);
+ }
}
+ }
- if (offsets[2] >= 0)
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+if (common->utf && offset != 0)
+ {
+ if (offset < 0)
{
- if (chars[3] != 0)
- OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, chars[3]);
- CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[2], start);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
}
- OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ else
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+#if defined COMPILE_PCRE8
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, start);
+#elif defined COMPILE_PCRE16
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, start);
+#else
+#error "Unknown code width"
+#endif
+ if (offset < 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
}
+#endif
+
+if (offset >= 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
JUMPHERE(quit);
-if (firstline)
+if (common->match_end_ptr != 0)
{
if (range_right >= 0)
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->first_line_end);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
if (range_right >= 0)
{
}
#undef MAX_N_CHARS
-#undef MAX_N_BYTES
+#undef MAX_DIFF_CHARS
-static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, pcre_uchar first_char, BOOL caseless, BOOL firstline)
+static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, pcre_uchar first_char, BOOL caseless)
{
-DEFINE_COMPILER;
-struct sljit_label *start;
-struct sljit_jump *quit;
-struct sljit_jump *found;
-pcre_uchar oc, bit;
-
-if (firstline)
- {
- SLJIT_ASSERT(common->first_line_end != 0);
- OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
- OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->first_line_end);
- }
-
-start = LABEL();
-quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
-OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+pcre_uchar oc;
oc = first_char;
if (caseless)
{
oc = TABLE_GET(first_char, common->fcc, first_char);
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
+#if defined SUPPORT_UCP && !defined COMPILE_PCRE8
if (first_char > 127 && common->utf)
oc = UCD_OTHERCASE(first_char);
#endif
}
-if (first_char == oc)
- found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, first_char);
-else
- {
- bit = first_char ^ oc;
- if (is_powerof2(bit))
- {
- OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, bit);
- found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, first_char | bit);
- }
- else
- {
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, first_char);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, oc);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- found = JUMP(SLJIT_NOT_ZERO);
- }
- }
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-JUMPTO(SLJIT_JUMP, start);
-JUMPHERE(found);
-JUMPHERE(quit);
-
-if (firstline)
- OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+fast_forward_first_char2(common, first_char, oc, 0);
}
-static SLJIT_INLINE void fast_forward_newline(compiler_common *common, BOOL firstline)
+static SLJIT_INLINE void fast_forward_newline(compiler_common *common)
{
DEFINE_COMPILER;
struct sljit_label *loop;
struct sljit_jump *notfoundnl;
jump_list *newline = NULL;
-if (firstline)
+if (common->match_end_ptr != 0)
{
- SLJIT_ASSERT(common->first_line_end != 0);
OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
- OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->first_line_end);
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
}
if (common->nltype == NLTYPE_FIXED && common->newline > 255)
firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2));
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER_EQUAL);
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
JUMPHERE(firstchar);
JUMPHERE(lastchar);
- if (firstline)
+ if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
return;
}
JUMPHERE(foundcr);
notfoundnl = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
JUMPHERE(lastchar);
JUMPHERE(firstchar);
-if (firstline)
+if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
}
-static BOOL check_class_ranges(compiler_common *common, const pcre_uint8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks);
+static BOOL check_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks);
-static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common, pcre_uint8 *start_bits, BOOL firstline)
+static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common, const sljit_u8 *start_bits)
{
DEFINE_COMPILER;
struct sljit_label *start;
struct sljit_jump *jump;
#endif
-if (firstline)
+if (common->match_end_ptr != 0)
{
- SLJIT_ASSERT(common->first_line_end != 0);
OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0);
- OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->first_line_end);
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
}
start = LABEL();
#endif
OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits);
OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
found = JUMP(SLJIT_NOT_ZERO);
}
if (common->utf)
{
CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
}
#elif defined COMPILE_PCRE16
{
CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800, start);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
}
set_jumps(matches, LABEL());
JUMPHERE(quit);
-if (firstline)
+if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0);
}
struct sljit_jump *found;
struct sljit_jump *foundoc = NULL;
struct sljit_jump *notfound;
-pcre_uint32 oc, bit;
+sljit_u32 oc, bit;
SLJIT_ASSERT(common->req_char_ptr != 0);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr);
struct sljit_label *mainloop;
sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
-OP1(SLJIT_MOV, TMP1, 0, STACK_TOP, 0);
-GET_LOCAL_BASE(TMP3, 0, 0);
+OP1(SLJIT_MOV, TMP3, 0, STACK_TOP, 0);
+GET_LOCAL_BASE(TMP1, 0, 0);
/* Drop frames until we reach STACK_TOP. */
mainloop = LABEL();
-OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), 0);
-OP2(SLJIT_SUB | SLJIT_SET_S, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0);
-jump = JUMP(SLJIT_SIG_LESS_EQUAL);
-
-OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP3, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_sw));
-OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(TMP1), 2 * sizeof(sljit_sw));
-OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -sizeof(sljit_sw));
+jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -2 * sizeof(sljit_sw));
+OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(STACK_TOP), -3 * sizeof(sljit_sw));
+OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
JUMPTO(SLJIT_JUMP, mainloop);
JUMPHERE(jump);
-jump = JUMP(SLJIT_SIG_LESS);
-/* End of dropping frames. */
+jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0);
+/* End of reverting values. */
+OP1(SLJIT_MOV, STACK_TOP, 0, TMP3, 0);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
JUMPHERE(jump);
OP1(SLJIT_NEG, TMP2, 0, TMP2, 0);
-OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP3, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_sw));
-OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -2 * sizeof(sljit_sw));
+OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
JUMPTO(SLJIT_JUMP, mainloop);
}
jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
JUMPHERE(jump);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0);
}
if (common->utf)
jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
#endif /* COMPILE_PCRE8 */
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0);
jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
JUMPHERE(jump);
}
else
if (common->utf)
jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
#endif
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes);
OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */);
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
#ifndef COMPILE_PCRE8
}
set_jumps(skipread_list, LABEL());
-OP2(SLJIT_XOR | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+OP2(SLJIT_XOR | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
}
-static BOOL check_class_ranges(compiler_common *common, const pcre_uint8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+static BOOL check_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
{
+/* May destroy TMP1. */
DEFINE_COMPILER;
int ranges[MAX_RANGE_SIZE];
-pcre_uint8 bit, cbit, all;
+sljit_u8 bit, cbit, all;
int i, byte, length = 0;
bit = bits[0] & 0x1;
return TRUE;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return FALSE;
}
}
sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
-OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
-OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
-OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
+OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
#ifdef COMPILE_PCRE8
if (common->utf)
{
#endif
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
#ifdef COMPILE_PCRE8
}
#endif
#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */
-OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
-OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09);
-OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
-OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
-OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
-OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
+OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0);
#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
#ifdef COMPILE_PCRE8
if (common->utf)
{
#endif
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000);
#ifdef COMPILE_PCRE8
}
#endif
#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */
-OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
-OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
-OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
-OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
+OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
#ifdef COMPILE_PCRE8
if (common->utf)
{
#endif
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
#ifdef COMPILE_PCRE8
}
#endif
#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */
-OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1));
OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
-OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
JUMPTO(SLJIT_NOT_ZERO, label);
JUMPHERE(jump);
#ifndef COMPILE_PCRE8
jump = CMP(SLJIT_GREATER, CHAR1, 0, SLJIT_IMM, 255);
#endif
-OP1(SLJIT_MOV_UB, CHAR1, 0, SLJIT_MEM2(LCC_TABLE, CHAR1), 0);
+OP1(SLJIT_MOV_U8, CHAR1, 0, SLJIT_MEM2(LCC_TABLE, CHAR1), 0);
#ifndef COMPILE_PCRE8
JUMPHERE(jump);
jump = CMP(SLJIT_GREATER, CHAR2, 0, SLJIT_IMM, 255);
#endif
-OP1(SLJIT_MOV_UB, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0);
+OP1(SLJIT_MOV_U8, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0);
#ifndef COMPILE_PCRE8
JUMPHERE(jump);
#endif
jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
-OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
JUMPTO(SLJIT_NOT_ZERO, label);
JUMPHERE(jump);
static const pcre_uchar * SLJIT_CALL do_utf_caselesscmp(pcre_uchar *src1, jit_arguments *args, pcre_uchar *end1)
{
/* This function would be ineffective to do in JIT level. */
-pcre_uint32 c1, c2;
+sljit_u32 c1, c2;
const pcre_uchar *src2 = args->uchar_ptr;
const pcre_uchar *end2 = args->end;
const ucd_record *ur;
-const pcre_uint32 *pp;
+const sljit_u32 *pp;
while (src1 < end1)
{
#if defined COMPILE_PCRE8
#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
if (context->length >= 4)
- OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
else if (context->length >= 2)
- OP1(SLJIT_MOV_UH, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
else
#endif
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
#elif defined COMPILE_PCRE16
#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
if (context->length >= 4)
- OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
else
#endif
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
#endif
{
if (context->length >= 4)
- OP1(SLJIT_MOV_SI, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_S32, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
else if (context->length >= 2)
- OP1(SLJIT_MOV_UH, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_U16, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
#if defined COMPILE_PCRE8
else if (context->length >= 1)
- OP1(SLJIT_MOV_UB, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ OP1(SLJIT_MOV_U8, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
#endif /* COMPILE_PCRE8 */
context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
#endif
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
context->ucharptr = 0;
} \
charoffset = (value);
+static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks, BOOL check_str_ptr);
+
static void compile_xclass_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks)
{
DEFINE_COMPILER;
#ifdef SUPPORT_UCP
BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE;
BOOL charsaved = FALSE;
-int typereg = TMP1, scriptreg = TMP1;
-const pcre_uint32 *other_cases;
+int typereg = TMP1;
+const sljit_u32 *other_cases;
sljit_uw typeoffset;
#endif
switch(*cc)
{
case PT_ANY:
+ /* Any either accepts everything or ignored. */
+ if (cc[-1] == XCL_PROP)
+ {
+ compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE);
+ if (list == backtracks)
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ return;
+ }
break;
case PT_LAMP:
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
cc += 2;
}
#endif
}
+SLJIT_ASSERT(compares > 0);
/* We are not necessary in utf mode even in 8 bit mode. */
cc = ccbegin;
-detect_partial_match(common, backtracks);
read_char_range(common, min, max, (cc[-1] & XCL_NOT) != 0);
if ((cc[-1] & XCL_HASPROP) == 0)
if ((cc[-1] & XCL_MAP) != 0)
{
jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
- if (!check_class_ranges(common, (const pcre_uint8 *)cc, (((const pcre_uint8 *)cc)[31] & 0x80) != 0, TRUE, &found))
+ if (!check_class_ranges(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found))
{
OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
add_jump(compiler, &found, JUMP(SLJIT_NOT_ZERO));
}
}
else if ((cc[-1] & XCL_MAP) != 0)
{
- OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
#ifdef SUPPORT_UCP
charsaved = TRUE;
#endif
- if (!check_class_ranges(common, (const pcre_uint8 *)cc, FALSE, TRUE, list))
+ if (!check_class_ranges(common, (const sljit_u8 *)cc, FALSE, TRUE, list))
{
#ifdef COMPILE_PCRE8
jump = NULL;
OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO));
#ifdef COMPILE_PCRE8
JUMPHERE(jump);
}
- OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
+ OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
cc += 32 / sizeof(pcre_uchar);
}
#ifdef SUPPORT_UCP
-/* Simple register allocation. TMP1 is preferred if possible. */
if (needstype || needsscript)
{
if (needschar && !charsaved)
- OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
- add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
- if (needschar)
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+
+#ifdef COMPILE_PCRE32
+ if (!common->utf)
+ {
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10ffff + 1);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+ JUMPHERE(jump);
+ }
+#endif
+
+ OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
+ OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+
+ /* Before anything else, we deal with scripts. */
+ if (needsscript)
{
- if (needstype)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script));
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
+
+ ccbegin = cc;
+
+ while (*cc != XCL_END)
{
- OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
- typereg = RETURN_ADDR;
+ if (*cc == XCL_SINGLE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ }
+ else if (*cc == XCL_RANGE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ GETCHARINCTEST(c, cc);
+ }
+ else
+ {
+ SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+ cc++;
+ if (*cc == PT_SC)
+ {
+ compares--;
+ invertcmp = (compares == 0 && list != backtracks);
+ if (cc[-1] == XCL_NOTPROP)
+ invertcmp ^= 0x1;
+ jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (int)cc[1]);
+ add_jump(compiler, compares > 0 ? list : backtracks, jump);
+ }
+ cc += 2;
+ }
}
- if (needsscript)
- scriptreg = TMP3;
- OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
+ cc = ccbegin;
}
- else if (needstype && needsscript)
- scriptreg = TMP3;
- /* In all other cases only one of them was specified, and that can goes to TMP1. */
- if (needsscript)
+ if (needschar)
{
- if (scriptreg == TMP1)
+ OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+ }
+
+ if (needstype)
+ {
+ if (!needschar)
{
- OP1(SLJIT_MOV, scriptreg, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script));
- OP1(SLJIT_MOV_UB, scriptreg, 0, SLJIT_MEM2(scriptreg, TMP2), 3);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
}
else
{
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3);
- OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script));
- OP1(SLJIT_MOV_UB, scriptreg, 0, SLJIT_MEM1(TMP2), 0);
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+ typereg = RETURN_ADDR;
}
}
}
if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
{
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
- OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, numberofcmps == 0 ? SLJIT_UNUSED : TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
numberofcmps++;
}
else if (numberofcmps > 0)
{
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
numberofcmps = 0;
}
if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
{
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
- OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, numberofcmps == 0 ? SLJIT_UNUSED : TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
numberofcmps++;
}
else if (numberofcmps > 0)
{
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
numberofcmps = 0;
}
#ifdef SUPPORT_UCP
else
{
+ SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
if (*cc == XCL_NOTPROP)
invertcmp ^= 0x1;
cc++;
switch(*cc)
{
case PT_ANY:
- if (list != backtracks)
- {
- if ((cc[-1] == XCL_NOTPROP && compares > 0) || (cc[-1] == XCL_PROP && compares == 0))
- continue;
- }
- else if (cc[-1] == XCL_NOTPROP)
- continue;
- jump = JUMP(SLJIT_JUMP);
+ if (!invertcmp)
+ jump = JUMP(SLJIT_JUMP);
break;
case PT_LAMP:
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
break;
case PT_SC:
- jump = CMP(SLJIT_EQUAL ^ invertcmp, scriptreg, 0, SLJIT_IMM, (int)cc[1]);
+ compares++;
+ /* Do nothing. */
break;
case PT_SPACE:
case PT_PXSPACE:
SET_CHAR_OFFSET(9);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
SET_TYPE_OFFSET(ucp_Zl);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
case PT_WORD:
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset));
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
/* Fall through. */
case PT_ALNUM:
SET_TYPE_OFFSET(ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
- OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, (*cc == PT_ALNUM) ? SLJIT_UNUSED : TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+ OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
SET_TYPE_OFFSET(ucp_Nd);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset);
OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
}
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
other_cases += 2;
}
else if (is_powerof2(other_cases[2] ^ other_cases[1]))
OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset);
OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
}
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset));
- OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_E : 0), TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset));
+ OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL);
other_cases += 3;
}
else
{
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
}
while (*other_cases != NOTACHAR)
{
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
- OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_E : 0), TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
+ OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL);
}
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
case PT_UCNC:
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset));
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset));
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset));
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset));
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset));
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
SET_CHAR_OFFSET(0xa0);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset));
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset));
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
SET_CHAR_OFFSET(0);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_GREATER_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_GREATER_EQUAL);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
case PT_PXGRAPH:
/* C and Z groups are the farthest two groups. */
SET_TYPE_OFFSET(ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
/* In case of ucp_Cf, we overwrite the result. */
SET_CHAR_OFFSET(0x2066);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
JUMPHERE(jump);
jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
case PT_PXPRINT:
/* C and Z groups are the farthest two groups. */
SET_TYPE_OFFSET(ucp_Ll);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll);
- OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_NOT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll);
+ OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL);
jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
/* In case of ucp_Cf, we overwrite the result. */
SET_CHAR_OFFSET(0x2066);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ JUMPHERE(jump);
+ jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
+ break;
+
+ case PT_PXPUNCT:
+ SET_TYPE_OFFSET(ucp_Sc);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(0);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f);
+ OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_TYPE_OFFSET(ucp_Pc);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ cc += 2;
+ }
+#endif
+
+ if (jump != NULL)
+ add_jump(compiler, compares > 0 ? list : backtracks, jump);
+ }
+
+if (found != NULL)
+ set_jumps(found, LABEL());
+}
+
+#undef SET_TYPE_OFFSET
+#undef SET_CHAR_OFFSET
+
+#endif
+
+static pcre_uchar *compile_simple_assertion_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+int length;
+struct sljit_jump *jump[4];
+#ifdef SUPPORT_UTF
+struct sljit_label *label;
+#endif /* SUPPORT_UTF */
+
+switch(type)
+ {
+ case OP_SOD:
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
+ return cc;
+
+ case OP_SOM:
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
+ return cc;
+
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ return cc;
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
- OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
+ case OP_EODN:
+ /* Requires rather complex checks. */
+ jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (common->mode == JIT_COMPILE)
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
+ else
+ {
+ jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_EQUAL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL));
+ check_partial(common, TRUE);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(jump[1]);
+ }
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+ }
+ else if (common->nltype == NLTYPE_FIXED)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
+ }
+ else
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
+ jump[2] = JUMP(SLJIT_GREATER);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL) /* LESS */);
+ /* Equal. */
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+
+ JUMPHERE(jump[1]);
+ if (common->nltype == NLTYPE_ANYCRLF)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, STR_END, 0));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+ }
+ else
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0);
+ read_char_range(common, common->nlmin, common->nlmax, TRUE);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+ add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+ }
+ JUMPHERE(jump[2]);
+ JUMPHERE(jump[3]);
+ }
+ JUMPHERE(jump[0]);
+ check_partial(common, FALSE);
+ return cc;
+
+ case OP_EOD:
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ check_partial(common, FALSE);
+ return cc;
+
+ case OP_DOLL:
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+
+ if (!common->endonly)
+ compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks);
+ else
+ {
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ check_partial(common, FALSE);
+ }
+ return cc;
+
+ case OP_DOLLM:
+ jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ check_partial(common, FALSE);
+ jump[0] = JUMP(SLJIT_JUMP);
+ JUMPHERE(jump[1]);
+
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (common->mode == JIT_COMPILE)
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0));
+ else
+ {
+ jump[1] = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
+ /* STR_PTR = STR_END - IN_UCHARS(1) */
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ check_partial(common, TRUE);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(jump[1]);
+ }
+
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+ }
+ else
+ {
+ peek_char(common, common->nlmax);
+ check_newlinechar(common, common->nltype, backtracks, FALSE);
+ }
+ JUMPHERE(jump[0]);
+ return cc;
- JUMPHERE(jump);
- jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
- break;
+ case OP_CIRC:
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ return cc;
- case PT_PXPUNCT:
- SET_TYPE_OFFSET(ucp_Sc);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
+ case OP_CIRCM:
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+ jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ jump[0] = JUMP(SLJIT_JUMP);
+ JUMPHERE(jump[1]);
- SET_CHAR_OFFSET(0);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f);
- OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, TMP1, 0));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+ }
+ else
+ {
+ skip_char_back(common);
+ read_char_range(common, common->nlmin, common->nlmax, TRUE);
+ check_newlinechar(common, common->nltype, backtracks, FALSE);
+ }
+ JUMPHERE(jump[0]);
+ return cc;
- SET_TYPE_OFFSET(ucp_Pc);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL);
- jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
- break;
- }
- cc += 2;
+ case OP_REVERSE:
+ length = GET(cc, 0);
+ if (length == 0)
+ return cc + LINK_SIZE;
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+#ifdef SUPPORT_UTF
+ if (common->utf)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, length);
+ label = LABEL();
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP3, 0));
+ skip_char_back(common);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
}
+ else
#endif
-
- if (jump != NULL)
- add_jump(compiler, compares > 0 ? list : backtracks, jump);
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP1, 0));
+ }
+ check_start_used_ptr(common);
+ return cc + LINK_SIZE;
}
-
-if (found != NULL)
- set_jumps(found, LABEL());
+SLJIT_UNREACHABLE();
+return cc;
}
-#undef SET_TYPE_OFFSET
-#undef SET_CHAR_OFFSET
-
-#endif
-
-static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks)
+static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks, BOOL check_str_ptr)
{
DEFINE_COMPILER;
int length;
unsigned int c, oc, bit;
compare_context context;
-struct sljit_jump *jump[4];
+struct sljit_jump *jump[3];
jump_list *end_list;
#ifdef SUPPORT_UTF
struct sljit_label *label;
switch(type)
{
- case OP_SOD:
- OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
- return cc;
-
- case OP_SOM:
- OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
- return cc;
-
- case OP_NOT_WORD_BOUNDARY:
- case OP_WORD_BOUNDARY:
- add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL));
- add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO));
- return cc;
-
case OP_NOT_DIGIT:
case OP_DIGIT:
/* Digits are usually 0-9, so it is worth to optimize them. */
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && is_char7_bitset((const pcre_uint8*)common->ctypes - cbit_length + cbit_digit, FALSE))
+ if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
read_char7_type(common, type == OP_NOT_DIGIT);
else
#endif
read_char8_type(common, type == OP_NOT_DIGIT);
/* Flip the starting bit in the negative case. */
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit);
add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_ZERO : SLJIT_NOT_ZERO));
return cc;
case OP_NOT_WHITESPACE:
case OP_WHITESPACE:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && is_char7_bitset((const pcre_uint8*)common->ctypes - cbit_length + cbit_space, FALSE))
+ if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE))
read_char7_type(common, type == OP_NOT_WHITESPACE);
else
#endif
read_char8_type(common, type == OP_NOT_WHITESPACE);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space);
add_jump(compiler, backtracks, JUMP(type == OP_WHITESPACE ? SLJIT_ZERO : SLJIT_NOT_ZERO));
return cc;
case OP_NOT_WORDCHAR:
case OP_WORDCHAR:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && is_char7_bitset((const pcre_uint8*)common->ctypes - cbit_length + cbit_word, FALSE))
+ if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE))
read_char7_type(common, type == OP_NOT_WORDCHAR);
else
#endif
read_char8_type(common, type == OP_NOT_WORDCHAR);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word);
add_jump(compiler, backtracks, JUMP(type == OP_WORDCHAR ? SLJIT_ZERO : SLJIT_NOT_ZERO));
return cc;
case OP_ANY:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
read_char_range(common, common->nlmin, common->nlmax, TRUE);
if (common->nltype == NLTYPE_FIXED && common->newline > 255)
{
return cc;
case OP_ALLANY:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
#ifdef SUPPORT_UTF
if (common->utf)
{
#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
#if defined COMPILE_PCRE8
jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
#elif defined COMPILE_PCRE16
jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
#endif
return cc;
case OP_ANYBYTE:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
return cc;
propdata[2] = cc[0];
propdata[3] = cc[1];
propdata[4] = XCL_END;
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
compile_xclass_matchingpath(common, propdata, backtracks);
return cc + 2;
#endif
#endif
case OP_ANYNL:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
read_char_range(common, common->bsr_nlmin, common->bsr_nlmax, FALSE);
- jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
- /* We don't need to handle soft partial matching case. */
- end_list = NULL;
- if (common->mode != JIT_PARTIAL_HARD_COMPILE)
- add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
- else
- check_str_end(common, &end_list);
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
- jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
- OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
- jump[2] = JUMP(SLJIT_JUMP);
- JUMPHERE(jump[0]);
- check_newlinechar(common, common->bsr_nltype, backtracks, FALSE);
- set_jumps(end_list, LABEL());
- JUMPHERE(jump[1]);
- JUMPHERE(jump[2]);
- return cc;
-
- case OP_NOT_HSPACE:
- case OP_HSPACE:
- detect_partial_match(common, backtracks);
- read_char_range(common, 0x9, 0x3000, type == OP_NOT_HSPACE);
- add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
- add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
- return cc;
-
- case OP_NOT_VSPACE:
- case OP_VSPACE:
- detect_partial_match(common, backtracks);
- read_char_range(common, 0xa, 0x2029, type == OP_NOT_VSPACE);
- add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
- add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
- return cc;
-
-#ifdef SUPPORT_UCP
- case OP_EXTUNI:
- detect_partial_match(common, backtracks);
- read_char(common);
- add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop));
- /* Optimize register allocation: use a real register. */
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
- OP1(SLJIT_MOV_UB, STACK_TOP, 0, SLJIT_MEM2(TMP1, TMP2), 3);
-
- label = LABEL();
- jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
- OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
- read_char(common);
- add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop));
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM2(TMP1, TMP2), 3);
-
- OP2(SLJIT_SHL, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2);
- OP1(SLJIT_MOV_UI, TMP1, 0, SLJIT_MEM1(STACK_TOP), (sljit_sw)PRIV(ucp_gbtable));
- OP1(SLJIT_MOV, STACK_TOP, 0, TMP2, 0);
- OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
- JUMPTO(SLJIT_NOT_ZERO, label);
-
- OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
- JUMPHERE(jump[0]);
- OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
-
- if (common->mode == JIT_PARTIAL_HARD_COMPILE)
- {
- jump[0] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
- /* Since we successfully read a char above, partial matching must occure. */
- check_partial(common, TRUE);
- JUMPHERE(jump[0]);
- }
- return cc;
-#endif
-
- case OP_EODN:
- /* Requires rather complex checks. */
- jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
- if (common->nltype == NLTYPE_FIXED && common->newline > 255)
- {
- OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
- if (common->mode == JIT_COMPILE)
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
- else
- {
- jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0);
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_NOT_EQUAL);
- add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL));
- check_partial(common, TRUE);
- add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
- JUMPHERE(jump[1]);
- }
- OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
- }
- else if (common->nltype == NLTYPE_FIXED)
- {
- OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
- }
- else
- {
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
- jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
- OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
- jump[2] = JUMP(SLJIT_GREATER);
- add_jump(compiler, backtracks, JUMP(SLJIT_LESS));
- /* Equal. */
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
- jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
- add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
-
- JUMPHERE(jump[1]);
- if (common->nltype == NLTYPE_ANYCRLF)
- {
- OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
- add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, STR_END, 0));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
- }
- else
- {
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0);
- read_char_range(common, common->nlmin, common->nlmax, TRUE);
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
- add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
- add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
- }
- JUMPHERE(jump[2]);
- JUMPHERE(jump[3]);
- }
- JUMPHERE(jump[0]);
- check_partial(common, FALSE);
- return cc;
-
- case OP_EOD:
- add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
- check_partial(common, FALSE);
- return cc;
-
- case OP_CIRC:
- OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
- add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
- return cc;
-
- case OP_CIRCM:
- OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
- jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0);
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
- jump[0] = JUMP(SLJIT_JUMP);
- JUMPHERE(jump[1]);
-
- add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
- if (common->nltype == NLTYPE_FIXED && common->newline > 255)
- {
- OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
- add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, TMP1, 0));
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
- OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
- }
+ jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+ /* We don't need to handle soft partial matching case. */
+ end_list = NULL;
+ if (common->mode != JIT_PARTIAL_HARD_COMPILE)
+ add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
else
- {
- skip_char_back(common);
- read_char_range(common, common->nlmin, common->nlmax, TRUE);
- check_newlinechar(common, common->nltype, backtracks, FALSE);
- }
+ check_str_end(common, &end_list);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ jump[2] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[0]);
+ check_newlinechar(common, common->bsr_nltype, backtracks, FALSE);
+ set_jumps(end_list, LABEL());
+ JUMPHERE(jump[1]);
+ JUMPHERE(jump[2]);
return cc;
- case OP_DOLL:
- OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char_range(common, 0x9, 0x3000, type == OP_NOT_HSPACE);
+ add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ return cc;
- if (!common->endonly)
- compile_char1_matchingpath(common, OP_EODN, cc, backtracks);
- else
- {
- add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
- check_partial(common, FALSE);
- }
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char_range(common, 0xa, 0x2029, type == OP_NOT_VSPACE);
+ add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
return cc;
- case OP_DOLLM:
- jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
- OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
- check_partial(common, FALSE);
- jump[0] = JUMP(SLJIT_JUMP);
- JUMPHERE(jump[1]);
+#ifdef SUPPORT_UCP
+ case OP_EXTUNI:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char(common);
+ add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop));
+ /* Optimize register allocation: use a real register. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
+ OP1(SLJIT_MOV_U8, STACK_TOP, 0, SLJIT_MEM2(TMP1, TMP2), 3);
- if (common->nltype == NLTYPE_FIXED && common->newline > 255)
- {
- OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
- OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
- if (common->mode == JIT_COMPILE)
- add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0));
- else
- {
- jump[1] = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
- /* STR_PTR = STR_END - IN_UCHARS(1) */
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
- check_partial(common, TRUE);
- add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
- JUMPHERE(jump[1]);
- }
+ label = LABEL();
+ jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+ read_char(common);
+ add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop));
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM2(TMP1, TMP2), 3);
- OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
- }
- else
+ OP2(SLJIT_SHL, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2);
+ OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(STACK_TOP), (sljit_sw)PRIV(ucp_gbtable));
+ OP1(SLJIT_MOV, STACK_TOP, 0, TMP2, 0);
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+ JUMPHERE(jump[0]);
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+ if (common->mode == JIT_PARTIAL_HARD_COMPILE)
{
- peek_char(common, common->nlmax);
- check_newlinechar(common, common->nltype, backtracks, FALSE);
+ jump[0] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+ /* Since we successfully read a char above, partial matching must occure. */
+ check_partial(common, TRUE);
+ JUMPHERE(jump[0]);
}
- JUMPHERE(jump[0]);
return cc;
+#endif
case OP_CHAR:
case OP_CHARI:
#ifdef SUPPORT_UTF
if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc);
#endif
- if (common->mode == JIT_COMPILE && (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0))
+ if (common->mode == JIT_COMPILE && check_str_ptr
+ && (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0))
{
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
return byte_sequence_compare(common, type == OP_CHARI, cc, &context, backtracks);
}
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
#ifdef SUPPORT_UTF
if (common->utf)
{
case OP_NOT:
case OP_NOTI:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
length = 1;
#ifdef SUPPORT_UTF
if (common->utf)
c = *cc;
if (c < 128)
{
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
if (type == OP_NOT || !char_has_othercase(common, cc))
add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
else
case OP_CLASS:
case OP_NCLASS:
- detect_partial_match(common, backtracks);
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- bit = (common->utf && is_char7_bitset((const pcre_uint8 *)cc, type == OP_NCLASS)) ? 127 : 255;
+ bit = (common->utf && is_char7_bitset((const sljit_u8 *)cc, type == OP_NCLASS)) ? 127 : 255;
read_char_range(common, 0, bit, type == OP_NCLASS);
#else
read_char_range(common, 0, 255, type == OP_NCLASS);
#endif
- if (check_class_ranges(common, (const pcre_uint8 *)cc, type == OP_NCLASS, FALSE, backtracks))
+ if (check_class_ranges(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks))
return cc + 32 / sizeof(pcre_uchar);
#if defined SUPPORT_UTF && defined COMPILE_PCRE8
OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
- OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
- OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
if (jump[0] != NULL)
JUMPHERE(jump[0]);
#endif
-
return cc + 32 / sizeof(pcre_uchar);
#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
case OP_XCLASS:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
compile_xclass_matchingpath(common, cc + LINK_SIZE, backtracks);
return cc + GET(cc, 0) - 1;
#endif
-
- case OP_REVERSE:
- length = GET(cc, 0);
- if (length == 0)
- return cc + LINK_SIZE;
- OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-#ifdef SUPPORT_UTF
- if (common->utf)
- {
- OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, length);
- label = LABEL();
- add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP3, 0));
- skip_char_back(common);
- OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, label);
- }
- else
-#endif
- {
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
- OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
- add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP1, 0));
- }
- check_start_used_ptr(common);
- return cc + LINK_SIZE;
}
-SLJIT_ASSERT_STOP();
+SLJIT_UNREACHABLE();
return cc;
}
}
/* A non-fixed length character will be checked if length == 0. */
-return compile_char1_matchingpath(common, *cc, cc + 1, backtracks);
+return compile_char1_matchingpath(common, *cc, cc + 1, backtracks, TRUE);
}
/* Forward definitions. */
#endif /* SUPPORT_UTF && SUPPORT_UCP */
{
if (ref)
- OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
else
- OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0);
if (withchecks)
jump = JUMP(SLJIT_ZERO);
int min = 0, max = 0;
BOOL minimize;
-PUSH_BACKTRACK(sizeof(iterator_backtrack), cc, NULL);
+PUSH_BACKTRACK(sizeof(ref_iterator_backtrack), cc, NULL);
if (ref)
offset = GET2(cc, 1) << 1;
cc += 1 + IMM2_SIZE + 1 + 2 * IMM2_SIZE;
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
/* Temporary release of STR_PTR. */
- OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
/* Handles both invalid and empty cases. Since the minimum repeat,
is zero the invalid case is basically the same as an empty case. */
if (ref)
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
}
/* Restore if not zero length. */
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
}
else
{
}
JUMPHERE(zerolength);
- BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL();
+ BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
count_match(common);
return cc;
}
}
-BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL();
+BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
if (max > 0)
add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max));
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
- CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(iterator_backtrack)->matchingpath);
+ CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(ref_iterator_backtrack)->matchingpath);
}
else if (max > 0)
OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
(((int)sizeof(PUBL(callout_block)) + 7) & ~7)
#define CALLOUT_ARG_OFFSET(arg) \
- (-CALLOUT_ARG_SIZE + SLJIT_OFFSETOF(PUBL(callout_block), arg))
+ SLJIT_OFFSETOF(PUBL(callout_block), arg)
static SLJIT_INLINE pcre_uchar *compile_callout_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
{
SLJIT_ASSERT(common->capture_last_ptr != 0);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, cc[1]);
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0);
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, cc[1]);
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0);
/* These pointer sized fields temporarly stores internal variables. */
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr));
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 2));
-OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 2 + LINK_SIZE));
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 2));
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 2 + LINK_SIZE));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0);
/* Needed to save important temporary registers. */
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
-OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_TOP, 0, SLJIT_IMM, CALLOUT_ARG_SIZE);
+/* SLJIT_R0 = arguments */
+OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0);
GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START);
sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout));
-OP1(SLJIT_MOV_SI, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0);
+OP1(SLJIT_MOV_S32, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0);
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
free_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw));
/* Check return value. */
-OP2(SLJIT_SUB | SLJIT_SET_S, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER));
if (common->forced_quit_label == NULL)
- add_jump(compiler, &common->forced_quit, JUMP(SLJIT_SIG_LESS));
+ add_jump(compiler, &common->forced_quit, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */);
else
- JUMPTO(SLJIT_SIG_LESS, common->forced_quit_label);
+ JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->forced_quit_label);
return cc + 2 + 2 * LINK_SIZE;
}
#undef CALLOUT_ARG_SIZE
#undef CALLOUT_ARG_OFFSET
+static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(pcre_uchar *cc)
+{
+while (TRUE)
+ {
+ switch (*cc)
+ {
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_CALLOUT:
+ case OP_ALT:
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+
+ case OP_KET:
+ return FALSE;
+
+ default:
+ return TRUE;
+ }
+ }
+}
+
static pcre_uchar *compile_assert_matchingpath(compiler_common *common, pcre_uchar *cc, assert_backtrack *backtrack, BOOL conditional)
{
DEFINE_COMPILER;
if (framesize < 0)
{
- extrasize = needs_control_head ? 2 : 1;
+ extrasize = 1;
+ if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE))
+ extrasize = 0;
+
+ if (needs_control_head)
+ extrasize++;
+
if (framesize == no_frame)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
- allocate_stack(common, extrasize);
+
+ if (extrasize > 0)
+ allocate_stack(common, extrasize);
+
if (needs_control_head)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
if (needs_control_head)
{
+ SLJIT_ASSERT(extrasize == 2);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
}
{
extrasize = needs_control_head ? 3 : 2;
allocate_stack(common, framesize + extrasize);
+
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
+ OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
if (needs_control_head)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
if (needs_control_head)
{
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
}
else
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+
init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE);
}
altbacktrack.top = NULL;
altbacktrack.topbacktracks = NULL;
- if (*ccbegin == OP_ALT)
+ if (*ccbegin == OP_ALT && extrasize > 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
altbacktrack.cc = ccbegin;
{
if (framesize == no_frame)
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- else
+ else if (extrasize > 0)
free_stack(common, extrasize);
+
if (needs_control_head)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
}
else
{
if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional)
{
/* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
- OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
if (needs_control_head)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
}
else
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
if (needs_control_head)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), (framesize + 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2));
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
}
}
{
/* We know that STR_PTR was stored on the top of the stack. */
if (conditional)
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? sizeof(sljit_sw) : 0);
+ {
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1));
+ }
else if (bra == OP_BRAZERO)
{
if (framesize < 0)
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize));
else
{
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw));
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (framesize + extrasize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
}
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
else if (framesize >= 0)
{
/* For OP_BRA and OP_BRAMINZERO. */
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
}
}
add_jump(compiler, found, JUMP(SLJIT_JUMP));
set_jumps(common->positive_assert_quit, LABEL());
SLJIT_ASSERT(framesize != no_stack);
if (framesize < 0)
- OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw));
else
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
}
JUMPHERE(jump);
}
if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
{
/* Assert is failed. */
- if (conditional || bra == OP_BRAZERO)
+ if ((conditional && extrasize > 0) || bra == OP_BRAZERO)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
if (framesize < 0)
free_stack(common, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
- else
+ else if (extrasize > 0)
free_stack(common, extrasize);
}
else
if (framesize < 0)
{
/* We know that STR_PTR was stored on the top of the stack. */
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw));
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize));
+
/* Keep the STR_PTR on the top of the stack. */
if (bra == OP_BRAZERO)
{
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
if (extrasize == 2)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
}
else if (bra == OP_BRAMINZERO)
{
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
}
if (bra == OP_BRA)
{
/* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
- OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 2) * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1));
}
else
{
/* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
- OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw));
if (extrasize == 2)
{
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
}
set_jumps(backtrack->common.topbacktracks, LABEL());
}
/* AssertNot is successful. */
if (framesize < 0)
{
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
if (bra != OP_BRA)
{
if (extrasize == 2)
free_stack(common, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
- else
+ else if (extrasize > 0)
free_stack(common, extrasize);
}
else
stacksize = needs_control_head ? 1 : 0;
if (ket != OP_KET || has_alternatives)
stacksize++;
- free_stack(common, stacksize);
+
+ if (stacksize > 0)
+ free_stack(common, stacksize);
}
if (needs_control_head)
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? sizeof(sljit_sw) : 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? STACK(-2) : STACK(-1));
/* TMP2 which is set here used by OP_KETRMAX below. */
if (ket == OP_KETRMAX)
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
else if (ket == OP_KETRMIN)
{
/* Move the STR_PTR to the private_data_ptr. */
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
}
}
else
{
stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1;
- OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw));
if (needs_control_head)
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
if (ket == OP_KETRMAX)
{
{
/* Except when the whole stack frame must be saved. */
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (BACKTRACK_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_sw));
+ braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-BACKTRACK_AS(bracket_backtrack)->u.framesize - 2));
}
JUMPHERE(skip);
}
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame)
- OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw));
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0);
}
else if (ket == OP_KETRMAX || has_alternatives)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+ OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
stacksize = needs_control_head ? 1 : 0;
if (ket != OP_KET || has_alternatives)
slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size;
OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
- OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
slot += common->name_entry_size;
i--;
while (i-- > 0)
{
OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
- OP2(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, STR_PTR, 0);
+ OP2(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, STR_PTR, 0);
slot += common->name_entry_size;
}
OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
{
if (has_alternatives)
BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, rmax_label);
/* Drop STR_PTR for greedy plus quantifier. */
if (opcode != OP_ONCE)
if (repeat_type == OP_EXACT)
{
count_match(common);
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, rmax_label);
}
else if (repeat_type == OP_UPTO)
cc += GET(cc, 1);
cc += 1 + LINK_SIZE;
-/* Temporarily encoding the needs_control_head in framesize. */
if (opcode == OP_ONCE)
+ {
+ /* We temporarily encode the needs_control_head in the lowest bit.
+ Note: on the target architectures of SLJIT the ((x << 1) >> 1) returns
+ the same value for small signed numbers (including negative numbers). */
BACKTRACK_AS(bracket_backtrack)->u.framesize = (BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0);
+ }
return cc + repeat_length;
}
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
if (needs_control_head)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
- OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, -STACK(stacksize - 1));
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
stack = 0;
if (!zero)
{
if (offset != 0)
{
- OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw));
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
else
{
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- OP2(SLJIT_ADD, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
if (opcode == OP_SBRAPOS)
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw));
- OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw), STR_PTR, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2));
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(-framesize - 2), STR_PTR, 0);
}
/* Even if the match is empty, we need to reset the control head. */
else
{
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2));
}
}
if (framesize < 0)
add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0));
else /* TMP2 is set to [private_data_ptr] above. */
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), (stacksize - 1) * sizeof(sljit_sw), SLJIT_IMM, 0));
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0));
}
/* None of them matched. */
return cc + 1 + LINK_SIZE;
}
-static SLJIT_INLINE pcre_uchar *get_iterator_parameters(compiler_common *common, pcre_uchar *cc, pcre_uchar *opcode, pcre_uchar *type, int *max, int *min, pcre_uchar **end)
+static SLJIT_INLINE pcre_uchar *get_iterator_parameters(compiler_common *common, pcre_uchar *cc, pcre_uchar *opcode, pcre_uchar *type, sljit_u32 *max, sljit_u32 *exact, pcre_uchar **end)
{
int class_len;
*opcode = *cc;
+*exact = 0;
+
if (*opcode >= OP_STAR && *opcode <= OP_POSUPTO)
{
cc++;
{
cc++;
*opcode -= OP_TYPESTAR - OP_STAR;
- *type = 0;
+ *type = OP_END;
}
else
{
cc++;
class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(pcre_uchar))) : GET(cc, 0);
*opcode = cc[class_len - 1];
+
if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY)
{
*opcode -= OP_CRSTAR - OP_STAR;
- if (end != NULL)
- *end = cc + class_len;
+ *end = cc + class_len;
+
+ if (*opcode == OP_PLUS || *opcode == OP_MINPLUS)
+ {
+ *exact = 1;
+ *opcode -= OP_PLUS - OP_STAR;
+ }
}
else if (*opcode >= OP_CRPOSSTAR && *opcode <= OP_CRPOSQUERY)
{
*opcode -= OP_CRPOSSTAR - OP_POSSTAR;
- if (end != NULL)
- *end = cc + class_len;
+ *end = cc + class_len;
+
+ if (*opcode == OP_POSPLUS)
+ {
+ *exact = 1;
+ *opcode = OP_POSSTAR;
+ }
}
else
{
SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE || *opcode == OP_CRPOSRANGE);
*max = GET2(cc, (class_len + IMM2_SIZE));
- *min = GET2(cc, class_len);
+ *exact = GET2(cc, class_len);
- if (*min == 0)
+ if (*max == 0)
{
- SLJIT_ASSERT(*max != 0);
- *opcode = (*opcode == OP_CRRANGE) ? OP_UPTO : (*opcode == OP_CRMINRANGE ? OP_MINUPTO : OP_POSUPTO);
+ if (*opcode == OP_CRPOSRANGE)
+ *opcode = OP_POSSTAR;
+ else
+ *opcode -= OP_CRRANGE - OP_STAR;
}
- if (*max == *min)
- *opcode = OP_EXACT;
-
- if (end != NULL)
- *end = cc + class_len + 2 * IMM2_SIZE;
+ else
+ {
+ *max -= *exact;
+ if (*max == 0)
+ *opcode = OP_EXACT;
+ else if (*max == 1)
+ {
+ if (*opcode == OP_CRPOSRANGE)
+ *opcode = OP_POSQUERY;
+ else
+ *opcode -= OP_CRRANGE - OP_QUERY;
+ }
+ else
+ {
+ if (*opcode == OP_CRPOSRANGE)
+ *opcode = OP_POSUPTO;
+ else
+ *opcode -= OP_CRRANGE - OP_UPTO;
+ }
+ }
+ *end = cc + class_len + 2 * IMM2_SIZE;
}
return cc;
}
-if (*opcode == OP_UPTO || *opcode == OP_MINUPTO || *opcode == OP_EXACT || *opcode == OP_POSUPTO)
+switch(*opcode)
{
+ case OP_EXACT:
+ *exact = GET2(cc, 0);
+ cc += IMM2_SIZE;
+ break;
+
+ case OP_PLUS:
+ case OP_MINPLUS:
+ *exact = 1;
+ *opcode -= OP_PLUS - OP_STAR;
+ break;
+
+ case OP_POSPLUS:
+ *exact = 1;
+ *opcode = OP_POSSTAR;
+ break;
+
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
*max = GET2(cc, 0);
cc += IMM2_SIZE;
+ break;
}
-if (*type == 0)
+if (*type == OP_END)
{
*type = *cc;
- if (end != NULL)
- *end = next_opcode(common, cc);
+ *end = next_opcode(common, cc);
cc++;
return cc;
}
-if (end != NULL)
- {
- *end = cc + 1;
+*end = cc + 1;
#ifdef SUPPORT_UTF
- if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc);
+if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc);
#endif
- }
return cc;
}
static pcre_uchar *compile_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
-{
-DEFINE_COMPILER;
-backtrack_common *backtrack;
-pcre_uchar opcode;
-pcre_uchar type;
-int max = -1, min = -1;
-pcre_uchar *end;
-jump_list *nomatch = NULL;
-struct sljit_jump *jump = NULL;
-struct sljit_label *label;
-int private_data_ptr = PRIVATE_DATA(cc);
-int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
-int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
-int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
-int tmp_base, tmp_offset;
-
-PUSH_BACKTRACK(sizeof(iterator_backtrack), cc, NULL);
-
-cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &min, &end);
-
-switch(type)
- {
- case OP_NOT_DIGIT:
- case OP_DIGIT:
- case OP_NOT_WHITESPACE:
- case OP_WHITESPACE:
- case OP_NOT_WORDCHAR:
- case OP_WORDCHAR:
- case OP_ANY:
- case OP_ALLANY:
- case OP_ANYBYTE:
- case OP_ANYNL:
- case OP_NOT_HSPACE:
- case OP_HSPACE:
- case OP_NOT_VSPACE:
- case OP_VSPACE:
- case OP_CHAR:
- case OP_CHARI:
- case OP_NOT:
- case OP_NOTI:
- case OP_CLASS:
- case OP_NCLASS:
- tmp_base = TMP3;
- tmp_offset = 0;
- break;
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+pcre_uchar opcode;
+pcre_uchar type;
+sljit_u32 max = 0, exact;
+BOOL fast_fail;
+sljit_s32 fast_str_ptr;
+BOOL charpos_enabled;
+pcre_uchar charpos_char;
+unsigned int charpos_othercasebit;
+pcre_uchar *end;
+jump_list *no_match = NULL;
+jump_list *no_char1_match = NULL;
+struct sljit_jump *jump = NULL;
+struct sljit_label *label;
+int private_data_ptr = PRIVATE_DATA(cc);
+int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
+int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
+int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
+int tmp_base, tmp_offset;
- default:
- SLJIT_ASSERT_STOP();
- /* Fall through. */
+PUSH_BACKTRACK(sizeof(char_iterator_backtrack), cc, NULL);
- case OP_EXTUNI:
- case OP_XCLASS:
- case OP_NOTPROP:
- case OP_PROP:
+fast_str_ptr = PRIVATE_DATA(cc + 1);
+fast_fail = TRUE;
+
+SLJIT_ASSERT(common->fast_forward_bc_ptr == NULL || fast_str_ptr == 0 || cc == common->fast_forward_bc_ptr);
+
+if (cc == common->fast_forward_bc_ptr)
+ fast_fail = FALSE;
+else if (common->fast_fail_start_ptr == 0)
+ fast_str_ptr = 0;
+
+SLJIT_ASSERT(common->fast_forward_bc_ptr != NULL || fast_str_ptr == 0
+ || (fast_str_ptr >= common->fast_fail_start_ptr && fast_str_ptr <= common->fast_fail_end_ptr));
+
+cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
+
+if (type != OP_EXTUNI)
+ {
+ tmp_base = TMP3;
+ tmp_offset = 0;
+ }
+else
+ {
tmp_base = SLJIT_MEM1(SLJIT_SP);
tmp_offset = POSSESSIVE0;
- break;
}
+if (fast_fail && fast_str_ptr != 0)
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), fast_str_ptr));
+
+/* Handle fixed part first. */
+if (exact > 1)
+ {
+ SLJIT_ASSERT(fast_str_ptr == 0);
+ if (common->mode == JIT_COMPILE
+#ifdef SUPPORT_UTF
+ && !common->utf
+#endif
+ )
+ {
+ OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact));
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0));
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ }
+else if (exact == 1)
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+
switch(opcode)
{
case OP_STAR:
- case OP_PLUS:
case OP_UPTO:
- case OP_CRRANGE:
+ SLJIT_ASSERT(fast_str_ptr == 0 || opcode == OP_STAR);
+
if (type == OP_ANYNL || type == OP_EXTUNI)
{
SLJIT_ASSERT(private_data_ptr == 0);
- if (opcode == OP_STAR || opcode == OP_UPTO)
- {
- allocate_stack(common, 2);
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
- }
- else
- {
- allocate_stack(common, 1);
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
- }
+ SLJIT_ASSERT(fast_str_ptr == 0);
+
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
- if (opcode == OP_UPTO || opcode == OP_CRRANGE)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, 0);
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, max);
label = LABEL();
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
- if (opcode == OP_UPTO || opcode == OP_CRRANGE)
+ compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
+ if (opcode == OP_UPTO)
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
- OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
- if (opcode == OP_CRRANGE && min > 0)
- CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, label);
- if (opcode == OP_UPTO || (opcode == OP_CRRANGE && max > 0))
- jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ jump = JUMP(SLJIT_ZERO);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
}
}
else
{
- if (opcode == OP_PLUS)
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
- if (private_data_ptr == 0)
- allocate_stack(common, 2);
- OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- if (opcode <= OP_PLUS)
+ charpos_enabled = FALSE;
+ charpos_char = 0;
+ charpos_othercasebit = 0;
+
+ if ((type != OP_CHAR && type != OP_CHARI) && (*end == OP_CHAR || *end == OP_CHARI))
+ {
+ charpos_enabled = TRUE;
+#ifdef SUPPORT_UTF
+ charpos_enabled = !common->utf || !HAS_EXTRALEN(end[1]);
+#endif
+ if (charpos_enabled && *end == OP_CHARI && char_has_othercase(common, end + 1))
+ {
+ charpos_othercasebit = char_get_othercase_bit(common, end + 1);
+ if (charpos_othercasebit == 0)
+ charpos_enabled = FALSE;
+ }
+
+ if (charpos_enabled)
+ {
+ charpos_char = end[1];
+ /* Consumpe the OP_CHAR opcode. */
+ end += 2;
+#if defined COMPILE_PCRE8
+ SLJIT_ASSERT((charpos_othercasebit >> 8) == 0);
+#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+ SLJIT_ASSERT((charpos_othercasebit >> 9) == 0);
+ if ((charpos_othercasebit & 0x100) != 0)
+ charpos_othercasebit = (charpos_othercasebit & 0xff) << 8;
+#endif
+ if (charpos_othercasebit != 0)
+ charpos_char |= charpos_othercasebit;
+
+ BACKTRACK_AS(char_iterator_backtrack)->u.charpos.enabled = TRUE;
+ BACKTRACK_AS(char_iterator_backtrack)->u.charpos.chr = charpos_char;
+ BACKTRACK_AS(char_iterator_backtrack)->u.charpos.othercasebit = charpos_othercasebit;
+ }
+ }
+
+ if (charpos_enabled)
+ {
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max + 1);
+
+ /* Search the first instance of charpos_char. */
+ jump = JUMP(SLJIT_JUMP);
+ label = LABEL();
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO));
+ }
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ JUMPHERE(jump);
+
+ detect_partial_match(common, &backtrack->topbacktracks);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (charpos_othercasebit != 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label);
+
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
- else
- OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, 1);
- label = LABEL();
- compile_char1_matchingpath(common, type, cc, &nomatch);
- OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- if (opcode <= OP_PLUS)
- JUMPTO(SLJIT_JUMP, label);
- else if (opcode == OP_CRRANGE && max == 0)
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
+ }
+
+ /* Search the last instance of charpos_char. */
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, FALSE);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ detect_partial_match(common, &no_match);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (charpos_othercasebit != 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
+ if (opcode == OP_STAR)
+ {
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ }
+ else
+ {
+ jump = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+ JUMPTO(SLJIT_JUMP, label);
+
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ }
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+ else if (common->utf)
{
- OP2(SLJIT_ADD, base, offset1, base, offset1, SLJIT_IMM, 1);
- JUMPTO(SLJIT_JUMP, label);
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+ JUMPTO(SLJIT_JUMP, label);
+
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
}
+#endif
else
{
- OP1(SLJIT_MOV, TMP1, 0, base, offset1);
- OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
- OP1(SLJIT_MOV, base, offset1, TMP1, 0);
- CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, max + 1, label);
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+
+ OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+ label = LABEL();
+ detect_partial_match(common, &no_match);
+ compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+ else
+ JUMPTO(SLJIT_JUMP, label);
+
+ set_jumps(no_char1_match, LABEL());
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
}
- set_jumps(nomatch, LABEL());
- if (opcode == OP_CRRANGE)
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS, base, offset1, SLJIT_IMM, min + 1));
- OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
}
- BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL();
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
break;
case OP_MINSTAR:
- case OP_MINPLUS:
- if (opcode == OP_MINPLUS)
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
if (private_data_ptr == 0)
allocate_stack(common, 1);
OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL();
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
break;
case OP_MINUPTO:
- case OP_CRMINRANGE:
+ SLJIT_ASSERT(fast_str_ptr == 0);
if (private_data_ptr == 0)
allocate_stack(common, 2);
OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, 1);
- if (opcode == OP_CRMINRANGE)
- add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
- BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL();
+ OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, max + 1);
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
break;
case OP_QUERY:
case OP_MINQUERY:
+ SLJIT_ASSERT(fast_str_ptr == 0);
if (private_data_ptr == 0)
allocate_stack(common, 1);
OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
if (opcode == OP_QUERY)
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
- BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL();
+ compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
break;
case OP_EXACT:
- OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
- label = LABEL();
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
- OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, label);
break;
case OP_POSSTAR:
- case OP_POSPLUS:
- case OP_POSUPTO:
- if (opcode == OP_POSPLUS)
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
- if (opcode == OP_POSUPTO)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, SLJIT_IMM, max);
- OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
- label = LABEL();
- compile_char1_matchingpath(common, type, cc, &nomatch);
- OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
- if (opcode != OP_POSUPTO)
- JUMPTO(SLJIT_JUMP, label);
- else
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+ if (common->utf)
{
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, label);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, label);
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ break;
}
- set_jumps(nomatch, LABEL());
- OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
- break;
-
- case OP_POSQUERY:
- OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
- compile_char1_matchingpath(common, type, cc, &nomatch);
- OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
- set_jumps(nomatch, LABEL());
- OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
+#endif
+ label = LABEL();
+ detect_partial_match(common, &no_match);
+ compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+ JUMPTO(SLJIT_JUMP, label);
+ set_jumps(no_char1_match, LABEL());
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_match, LABEL());
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
break;
- case OP_CRPOSRANGE:
- /* Combination of OP_EXACT and OP_POSSTAR or OP_POSUPTO */
- OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, min);
+ case OP_POSUPTO:
+ SLJIT_ASSERT(fast_str_ptr == 0);
+#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+ if (common->utf)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+ break;
+ }
+#endif
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
label = LABEL();
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks);
- OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ detect_partial_match(common, &no_match);
+ compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, label);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_char1_match, LABEL());
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_match, LABEL());
+ break;
- if (max != 0)
- {
- SLJIT_ASSERT(max - min > 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, SLJIT_IMM, max - min);
- }
+ case OP_POSQUERY:
+ SLJIT_ASSERT(fast_str_ptr == 0);
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
- label = LABEL();
- compile_char1_matchingpath(common, type, cc, &nomatch);
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
- if (max == 0)
- JUMPTO(SLJIT_JUMP, label);
- else
- {
- OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, label);
- }
- set_jumps(nomatch, LABEL());
+ set_jumps(no_match, LABEL());
OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
else
CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
+OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
-OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
+OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
if (common->accept_label == NULL)
add_jump(compiler, &common->accept, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
else
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
allocate_stack(common, size);
if (size > 3)
- OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw));
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw));
else
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start);
case OP_SOM:
case OP_NOT_WORD_BOUNDARY:
case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_REVERSE:
+ cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ break;
+
case OP_NOT_DIGIT:
case OP_DIGIT:
case OP_NOT_WHITESPACE:
case OP_NOT_VSPACE:
case OP_VSPACE:
case OP_EXTUNI:
- case OP_EODN:
- case OP_EOD:
- case OP_CIRC:
- case OP_CIRCM:
- case OP_DOLL:
- case OP_DOLLM:
case OP_NOT:
case OP_NOTI:
- case OP_REVERSE:
- cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
break;
case OP_SET_SOM:
if (common->mode == JIT_COMPILE)
cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
else
- cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
break;
case OP_STAR:
if (cc[1 + (32 / sizeof(pcre_uchar))] >= OP_CRSTAR && cc[1 + (32 / sizeof(pcre_uchar))] <= OP_CRPOSRANGE)
cc = compile_iterator_matchingpath(common, cc, parent);
else
- cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
break;
#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE)
cc = compile_iterator_matchingpath(common, cc, parent);
else
- cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
break;
#endif
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return;
}
if (cc == NULL)
pcre_uchar *cc = current->cc;
pcre_uchar opcode;
pcre_uchar type;
-int max = -1, min = -1;
+sljit_u32 max = 0, exact;
struct sljit_label *label = NULL;
struct sljit_jump *jump = NULL;
jump_list *jumplist = NULL;
+pcre_uchar *end;
int private_data_ptr = PRIVATE_DATA(cc);
int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
-cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &min, NULL);
+cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
switch(opcode)
{
case OP_STAR:
- case OP_PLUS:
case OP_UPTO:
- case OP_CRRANGE:
if (type == OP_ANYNL || type == OP_EXTUNI)
{
SLJIT_ASSERT(private_data_ptr == 0);
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL());
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
free_stack(common, 1);
- CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath);
}
else
{
- if (opcode == OP_UPTO)
- min = 0;
- if (opcode <= OP_PLUS)
+ if (CURRENT_AS(char_iterator_backtrack)->u.charpos.enabled)
{
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
- jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, base, offset1);
+ OP1(SLJIT_MOV, TMP2, 0, base, offset1);
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+ label = LABEL();
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ if (CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit != 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.chr, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ skip_char_back(common);
+ CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP2, 0, label);
}
else
{
- OP1(SLJIT_MOV, TMP1, 0, base, offset1);
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
- jump = CMP(SLJIT_LESS_EQUAL, TMP1, 0, SLJIT_IMM, min + 1);
- OP2(SLJIT_SUB, base, offset1, TMP1, 0, SLJIT_IMM, 1);
+ jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, base, offset1);
+ skip_char_back(common);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
}
- skip_char_back(common);
- OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath);
- if (opcode == OP_CRRANGE)
- set_jumps(current->topbacktracks, LABEL());
JUMPHERE(jump);
if (private_data_ptr == 0)
free_stack(common, 2);
- if (opcode == OP_PLUS)
- set_jumps(current->topbacktracks, LABEL());
}
break;
case OP_MINSTAR:
- case OP_MINPLUS:
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
- compile_char1_matchingpath(common, type, cc, &jumplist);
+ compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
set_jumps(jumplist, LABEL());
if (private_data_ptr == 0)
free_stack(common, 1);
- if (opcode == OP_MINPLUS)
- set_jumps(current->topbacktracks, LABEL());
break;
case OP_MINUPTO:
- case OP_CRMINRANGE:
- if (opcode == OP_CRMINRANGE)
- {
- label = LABEL();
- set_jumps(current->topbacktracks, label);
- }
+ OP1(SLJIT_MOV, TMP1, 0, base, offset1);
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
- compile_char1_matchingpath(common, type, cc, &jumplist);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ add_jump(compiler, &jumplist, JUMP(SLJIT_ZERO));
- OP1(SLJIT_MOV, TMP1, 0, base, offset1);
- OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
- OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, base, offset1, TMP1, 0);
-
- if (opcode == OP_CRMINRANGE)
- CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min + 1, label);
-
- if (opcode == OP_CRMINRANGE && max == 0)
- JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath);
- else
- CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, max + 2, CURRENT_AS(iterator_backtrack)->matchingpath);
+ compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
set_jumps(jumplist, LABEL());
if (private_data_ptr == 0)
case OP_QUERY:
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
- CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath);
jump = JUMP(SLJIT_JUMP);
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL());
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
- JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
JUMPHERE(jump);
if (private_data_ptr == 0)
free_stack(common, 1);
OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
jump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
- compile_char1_matchingpath(common, type, cc, &jumplist);
- JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath);
+ compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
set_jumps(jumplist, LABEL());
JUMPHERE(jump);
if (private_data_ptr == 0)
break;
case OP_EXACT:
- case OP_POSPLUS:
- case OP_CRPOSRANGE:
- set_jumps(current->topbacktracks, LABEL());
- break;
-
case OP_POSSTAR:
case OP_POSQUERY:
case OP_POSUPTO:
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
+
+set_jumps(current->topbacktracks, LABEL());
}
static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
set_jumps(current->topbacktracks, LABEL());
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
free_stack(common, 1);
- CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
return;
}
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
-CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath);
+CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
set_jumps(current->topbacktracks, LABEL());
free_stack(common, ref ? 2 : 3);
}
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_backtrack)->framesize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(assert_backtrack)->framesize - 1));
set_jumps(current->topbacktracks, LABEL());
}
if (bra == OP_BRAZERO)
{
/* We know there is enough place on the stack. */
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath);
JUMPHERE(brajump);
else
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (CURRENT_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_sw), CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 2), CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
}
/* Drop STR_PTR for non-greedy plus quantifier. */
if (opcode != OP_ONCE)
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-assert->framesize - 1));
}
cond = JUMP(SLJIT_JUMP);
set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL());
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-assert->framesize - 1));
}
JUMPHERE(cond);
}
/* The STR_PTR must be released. */
stacksize++;
}
- free_stack(common, stacksize);
+
+ if (stacksize > 0)
+ free_stack(common, stacksize);
JUMPHERE(once);
/* Restore previous private_data_ptr */
if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracket_backtrack)->u.framesize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 1));
else if (ket == OP_KETRMIN)
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
JUMPHERE(jump);
}
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracketpos_backtrack)->framesize * sizeof(sljit_sw));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracketpos_backtrack)->framesize - 1));
}
static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current)
jump = JUMP(SLJIT_JUMP);
loop = LABEL();
- OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), -(int)sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
JUMPHERE(jump);
- CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), -(int)(2 * sizeof(sljit_sw)), TMP1, 0, loop);
- CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), -(int)(3 * sizeof(sljit_sw)), TMP2, 0, loop);
+ CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, loop);
+ CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0, loop);
add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP));
return;
}
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
current = current->prev;
set_jumps(common->currententry->calls, common->currententry->entry);
sljit_emit_fast_enter(compiler, TMP2, 0);
-allocate_stack(common, private_data_size + framesize + alternativesize);
count_match(common);
+allocate_stack(common, private_data_size + framesize + alternativesize);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(private_data_size + framesize + alternativesize - 1), TMP2, 0);
-copy_private_data(common, ccbegin, ccend, TRUE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head);
+copy_private_data(common, ccbegin, ccend, TRUE, framesize + alternativesize, private_data_size + framesize + alternativesize, needs_control_head);
if (needs_control_head)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0);
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
if (needs_frame)
{
- OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw));
- add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw));
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw));
}
OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0);
common->quit = NULL;
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
if (needs_frame)
{
- OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw));
- add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw));
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw));
}
OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 1);
JUMPHERE(jump);
if (common->quit != NULL)
set_jumps(common->quit, LABEL());
-copy_private_data(common, ccbegin, ccend, FALSE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head);
+copy_private_data(common, ccbegin, ccend, FALSE, framesize + alternativesize, private_data_size + framesize + alternativesize, needs_control_head);
free_stack(common, private_data_size + framesize + alternativesize);
if (needs_control_head)
{
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), 2 * sizeof(sljit_sw));
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_sw));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-3));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, TMP1, 0);
OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0);
}
else
{
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_sw));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, TMP2, 0);
}
-sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), 0);
+sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), STACK(-1));
}
#undef COMPILE_BACKTRACKINGPATH
backtrack_common rootbacktrack;
compiler_common common_data;
compiler_common *common = &common_data;
-const pcre_uint8 *tables = re->tables;
+const sljit_u8 *tables = re->tables;
pcre_study_data *study;
int private_data_size;
pcre_uchar *ccend;
/* Calculate the local space size on the stack. */
common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw);
-common->optimized_cbracket = (pcre_uint8 *)SLJIT_MALLOC(re->top_bracket + 1, compiler->allocator_data);
+common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, compiler->allocator_data);
if (!common->optimized_cbracket)
return;
#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1
common->hit_start = common->ovector_start;
common->ovector_start += 2 * sizeof(sljit_sw);
}
- else
- {
- SLJIT_ASSERT(mode == JIT_PARTIAL_HARD_COMPILE);
- common->needs_start_ptr = TRUE;
- }
}
if ((re->options & PCRE_FIRSTLINE) != 0)
{
- common->first_line_end = common->ovector_start;
+ common->match_end_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
}
#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
common->control_head_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
}
-if (common->needs_start_ptr && common->has_set_som)
+if (common->has_set_som)
{
/* Saving the real start pointer is necessary. */
common->start_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
}
-else
- common->needs_start_ptr = FALSE;
/* Aligning ovector to even number of sljit words. */
if ((common->ovector_start & sizeof(sljit_sw)) != 0)
common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw);
total_length = ccend - common->start;
-common->private_data_ptrs = (sljit_si *)SLJIT_MALLOC(total_length * (sizeof(sljit_si) + (common->has_then ? 1 : 0)), compiler->allocator_data);
+common->private_data_ptrs = (sljit_s32 *)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), compiler->allocator_data);
if (!common->private_data_ptrs)
{
SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
return;
}
-memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_si));
+memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
set_private_data_ptrs(common, &private_data_size, ccend);
+if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0)
+ {
+ if (!detect_fast_forward_skip(common, &private_data_size) && !common->has_skip_in_assert_back)
+ detect_fast_fail(common, common->start, &private_data_size, 4);
+ }
+
+SLJIT_ASSERT(common->fast_fail_start_ptr <= common->fast_fail_end_ptr);
+
if (private_data_size > SLJIT_MAX_LOCAL_SIZE)
{
SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
if (common->has_then)
{
- common->then_offsets = (pcre_uint8 *)(common->private_data_ptrs + total_length);
+ common->then_offsets = (sljit_u8 *)(common->private_data_ptrs + total_length);
memset(common->then_offsets, 0, total_length);
set_then_offsets(common, common->start, NULL);
}
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
-OP1(SLJIT_MOV_UI, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match));
+OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, base));
OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit));
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0);
+if (common->fast_fail_start_ptr < common->fast_fail_end_ptr)
+ reset_fast_fail(common);
+
if (mode == JIT_PARTIAL_SOFT_COMPILE)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
if (common->mark_ptr != 0)
/* Main part of the matching */
if ((re->options & PCRE_ANCHORED) == 0)
{
- mainloop_label = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0, (re->options & PCRE_FIRSTLINE) != 0);
+ mainloop_label = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0);
continue_match_label = LABEL();
/* Forward search if possible. */
if ((re->options & PCRE_NO_START_OPTIMIZE) == 0)
{
- if (mode == JIT_COMPILE && fast_forward_first_n_chars(common, (re->options & PCRE_FIRSTLINE) != 0))
+ if (mode == JIT_COMPILE && fast_forward_first_n_chars(common))
;
else if ((re->flags & PCRE_FIRSTSET) != 0)
- fast_forward_first_char(common, (pcre_uchar)re->first_char, (re->flags & PCRE_FCH_CASELESS) != 0, (re->options & PCRE_FIRSTLINE) != 0);
+ fast_forward_first_char(common, (pcre_uchar)re->first_char, (re->flags & PCRE_FCH_CASELESS) != 0);
else if ((re->flags & PCRE_STARTLINE) != 0)
- fast_forward_newline(common, (re->options & PCRE_FIRSTLINE) != 0);
+ fast_forward_newline(common);
else if (study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)
- fast_forward_start_bits(common, study->start_bits, (re->options & PCRE_FIRSTLINE) != 0);
+ fast_forward_start_bits(common, study->start_bits);
}
}
else
OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH);
if (common->capture_last_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, -1);
+if (common->fast_forward_bc_ptr != NULL)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), PRIVATE_DATA(common->fast_forward_bc_ptr + 1), STR_PTR, 0);
-if (common->needs_start_ptr)
- {
- SLJIT_ASSERT(common->start_ptr != OVECTOR(0));
+if (common->start_ptr != OVECTOR(0))
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_ptr, STR_PTR, 0);
- }
-else
- SLJIT_ASSERT(common->start_ptr == OVECTOR(0));
/* Copy the beginning of the string. */
if (mode == JIT_PARTIAL_SOFT_COMPILE)
/* Check we have remaining characters. */
if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_FIRSTLINE) != 0)
{
- SLJIT_ASSERT(common->first_line_end != 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->first_line_end);
+ SLJIT_ASSERT(common->match_end_ptr != 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
}
-OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP),
+ (common->fast_forward_bc_ptr != NULL) ? (PRIVATE_DATA(common->fast_forward_bc_ptr + 1)) : common->start_ptr);
if ((re->options & PCRE_ANCHORED) == 0)
{
/* There cannot be more newlines here. */
}
else
- {
- if ((re->options & PCRE_FIRSTLINE) == 0)
- CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, mainloop_label);
- else
- CMPTO(SLJIT_LESS, STR_PTR, 0, TMP1, 0, mainloop_label);
- }
+ CMPTO(SLJIT_LESS, STR_PTR, 0, ((re->options & PCRE_FIRSTLINE) == 0) ? STR_END : TMP1, 0, mainloop_label);
}
/* No more remaining characters. */
{
JUMPHERE(empty_match);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_backtrack_label);
- OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_found_label);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label);
JUMPTO(SLJIT_JUMP, empty_match_backtrack_label);
}
+common->fast_forward_bc_ptr = NULL;
+common->fast_fail_start_ptr = 0;
+common->fast_fail_end_ptr = 0;
common->currententry = common->entries;
common->local_exit = TRUE;
quit_label = common->quit_label;
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top), STACK_TOP, 0);
-OP2(SLJIT_ADD, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE);
+OP2(SLJIT_SUB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE);
sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
jump = CMP(SLJIT_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
void *executable_func;
jit_function call_executable_func;
} convert_executable_func;
-pcre_uint8 local_space[MACHINE_STACK_SIZE];
+sljit_u8 local_space[MACHINE_STACK_SIZE];
struct sljit_stack local_stack;
-local_stack.top = (sljit_sw)&local_space;
-local_stack.base = local_stack.top;
-local_stack.limit = local_stack.base + MACHINE_STACK_SIZE;
-local_stack.max_limit = local_stack.limit;
+local_stack.max_limit = local_space;
+local_stack.limit = local_space;
+local_stack.base = local_space + MACHINE_STACK_SIZE;
+local_stack.top = local_space + MACHINE_STACK_SIZE;
arguments->stack = &local_stack;
convert_executable_func.executable_func = executable_func;
return convert_executable_func.call_executable_func(arguments);
arguments.end = subject + length;
arguments.mark_ptr = NULL;
/* JIT decreases this value less frequently than the interpreter. */
-arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (pcre_uint32)(extra_data->match_limit);
+arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (sljit_u32)(extra_data->match_limit);
if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match)
arguments.limit_match = functions->limit_match;
arguments.notbol = (options & PCRE_NOTBOL) != 0;
arguments.end = subject_ptr + length;
arguments.mark_ptr = NULL;
/* JIT decreases this value less frequently than the interpreter. */
-arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (pcre_uint32)(extra_data->match_limit);
+arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (sljit_u32)(extra_data->match_limit);
if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match)
arguments.limit_match = functions->limit_match;
arguments.notbol = (options & PCRE_NOTBOL) != 0;
#ifndef DFTABLES
+# ifdef HAVE_CONFIG_H
# include "config.h"
+# endif
# include "pcre_internal.h"
#endif
http://unicode.org/unicode/reports/tr18/. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
/* This file contains a private PCRE function that converts an ordinal
character value into a UTF8 string. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#define COMPILE_PCRE8
#ifndef PCRE_INCLUDED
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
/* For pcretest program. */
#define PRIV(name) name
shared by different users. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
supporting functions. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
for (c = 0; c < 16; c++) start_bits[c] |= map[c];
for (c = 128; c < 256; c++)
{
- if ((map[c/8] && (1 << (c&7))) != 0)
+ if ((map[c/8] & (1 << (c&7))) != 0)
{
int d = (c >> 6) | 0xc0; /* Set bit for this starter */
start_bits[d/8] |= (1 << (d&7)); /* and then skip on to the */
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
clashes with the library. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
(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),
#ifndef PCRE_INCLUDED
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
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):
strings. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
string that identifies the PCRE version that is in use. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
class. It is used by both pcre_exec() and pcre_def_exec(). */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include "pcre_internal.h"
and semantics are as close as possible to those of the Perl 5 language.
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
functions. */
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
/* Ensure that the PCREPOSIX_EXP_xxx macros are set appropriately for
REG_BADPAT, /* group name must start with a non-digit */
/* 85 */
REG_BADPAT, /* parentheses too deeply nested (stack check) */
- REG_BADPAT /* missing digits in \x{} or \o{} */
+ REG_BADPAT, /* missing digits in \x{} or \o{} */
+ REG_BADPAT /* pattern too complicated */
};
/* Table of texts corresponding to POSIX error codes */
if ((eflags & REG_STARTEND) != 0)
{
+ if (pmatch == NULL) return REG_INVARG;
so = pmatch[0].rm_so;
eo = pmatch[0].rm_eo;
}
{
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;
/*
* 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:
/* --------------------------------------------------------------------- */
/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
- define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMMOVE, and NULL. */
+ define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */
#ifndef SLJIT_STD_MACROS_DEFINED
/* Disabled by default. */
#define SLJIT_STD_MACROS_DEFINED 0
/* Executable code allocation:
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
- define both SLJIT_MALLOC_EXEC and SLJIT_FREE_EXEC. */
+ define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
/* Enabled by default. */
#define SLJIT_EXECUTABLE_ALLOCATOR 1
+
+/* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses
+ an allocator which does not set writable and executable
+ permission flags at the same time. The trade-of is increased
+ memory consumption and disabled dynamic code modifications. */
+#ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR
+/* Disabled by default. */
+#define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0
+#endif
+
#endif
/* Force cdecl calling convention even if a better calling
/*
* 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:
SLJIT defines the following architecture dependent types and macros:
Types:
- sljit_sb, sljit_ub : signed and unsigned 8 bit byte
- sljit_sh, sljit_uh : signed and unsigned 16 bit half-word (short) type
- sljit_si, sljit_ui : signed and unsigned 32 bit integer type
- sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
- sljit_p : unsgined pointer value (usually the same as sljit_uw, but
- some 64 bit ABIs may use 32 bit pointers)
- sljit_s : single precision floating point value
- sljit_d : double precision floating point value
+ sljit_s8, sljit_u8 : signed and unsigned 8 bit integer type
+ sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type
+ sljit_s32, sljit_u32 : signed and unsigned 32 bit integer type
+ sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
+ sljit_p : unsgined pointer value (usually the same as sljit_uw, but
+ some 64 bit ABIs may use 32 bit pointers)
+ sljit_f32 : 32 bit single precision floating point value
+ sljit_f64 : 64 bit double precision floating point value
Macros for feature detection (boolean):
SLJIT_32BIT_ARCHITECTURE : 32 bit architecture
SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
- SLJIT_DOUBLE_SHIFT : the shift required to apply when accessing
- a double precision floating point array by index
- SLJIT_SINGLE_SHIFT : the shift required to apply when accessing
- a single precision floating point array by index
+ SLJIT_F32_SHIFT : the shift required to apply when accessing
+ a single precision floating point array by index
+ SLJIT_F64_SHIFT : the shift required to apply when accessing
+ a double precision floating point array by index
SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
/* 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.
#define SLJIT_FREE(ptr, allocator_data) free(ptr)
#endif
-#ifndef SLJIT_MEMMOVE
-#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len)
+#ifndef SLJIT_MEMCPY
+#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
#endif
#ifndef SLJIT_ZEROMEM
#endif
#endif /* !SLJIT_INLINE */
-#ifndef SLJIT_CONST
-/* Const variables. */
-#define SLJIT_CONST const
-#endif
-
#ifndef SLJIT_UNUSED_ARG
/* Unused arguments. */
#define SLJIT_UNUSED_ARG(arg) (void)arg
/* Instruction cache flush. */
/****************************/
+#if (!defined SLJIT_CACHE_FLUSH && defined __has_builtin)
+#if __has_builtin(__builtin___clear_cache)
+
+#define SLJIT_CACHE_FLUSH(from, to) \
+ __builtin___clear_cache((char*)from, (char*)to)
+
+#endif /* __has_builtin(__builtin___clear_cache) */
+#endif /* (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) */
+
#ifndef SLJIT_CACHE_FLUSH
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
#define SLJIT_CACHE_FLUSH(from, to) \
sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
-#elif defined __ANDROID__
+#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
-/* Android lacks __clear_cache; instead, cacheflush should be used. */
+/* 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) \
- cacheflush((long)(from), (long)(to), 0)
+ __builtin___clear_cache((char*)from, (char*)to)
-#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+#elif defined __ANDROID__
+
+/* Android lacks __clear_cache; instead, cacheflush should be used. */
-/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
#define SLJIT_CACHE_FLUSH(from, to) \
- ppc_cache_flush((from), (to))
+ cacheflush((long)(from), (long)(to), 0)
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
#define SLJIT_CACHE_FLUSH(from, to) \
sparc_cache_flush((from), (to))
+#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
#else
#endif /* !SLJIT_CACHE_FLUSH */
/******************************************************/
-/* Byte/half/int/word/single/double type definitions. */
+/* Integer and floating point type definitions. */
/******************************************************/
/* 8 bit byte type. */
-typedef unsigned char sljit_ub;
-typedef signed char sljit_sb;
+typedef unsigned char sljit_u8;
+typedef signed char sljit_s8;
/* 16 bit half-word type. */
-typedef unsigned short int sljit_uh;
-typedef signed short int sljit_sh;
+typedef unsigned short int sljit_u16;
+typedef signed short int sljit_s16;
/* 32 bit integer type. */
-typedef unsigned int sljit_ui;
-typedef signed int sljit_si;
+typedef unsigned int sljit_u32;
+typedef signed int sljit_s32;
/* Machine word type. Enough for storing a pointer.
32 bit for 32 bit machines.
typedef sljit_uw sljit_p;
/* Floating point types. */
-typedef float sljit_s;
-typedef double sljit_d;
+typedef float sljit_f32;
+typedef double sljit_f64;
/* Shift for pointer sized data. */
#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT
/* Shift for double precision sized data. */
-#define SLJIT_DOUBLE_SHIFT 3
-#define SLJIT_SINGLE_SHIFT 2
+#define SLJIT_F32_SHIFT 2
+#define SLJIT_F64_SHIFT 3
#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)
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
#define SLJIT_MALLOC_EXEC(size) sljit_malloc_exec(size)
#define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr)
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
+#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
+#else
+#define SLJIT_EXEC_OFFSET(ptr) 0
+#endif
+
#endif
/**********************************************/
#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)
#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))
#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
#include <stdio.h>
-#endif /* !SLJIT_ASSERT || !SLJIT_ASSERT_STOP */
+#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */
/* Feel free to redefine these two macros. */
#ifndef SLJIT_ASSERT
#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 */
/*
* 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:
return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
}
-static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size)
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
{
SLJIT_UNUSED_ARG(size);
VirtualFree(chunk, 0, MEM_RELEASE);
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{
- void* retval;
+ void *retval;
#ifdef MAP_ANON
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
return (retval != MAP_FAILED) ? retval : NULL;
}
-static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size)
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
{
munmap(chunk, size);
}
};
#define AS_BLOCK_HEADER(base, offset) \
- ((struct block_header*)(((sljit_ub*)base) + offset))
+ ((struct block_header*)(((sljit_u8*)base) + offset))
#define AS_FREE_BLOCK(base, offset) \
- ((struct free_block*)(((sljit_ub*)base) + offset))
-#define MEM_START(base) ((void*)(((sljit_ub*)base) + sizeof(struct block_header)))
+ ((struct free_block*)(((sljit_u8*)base) + offset))
+#define MEM_START(base) ((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
static struct free_block* free_blocks;
free_block->size = size;
free_block->next = free_blocks;
- free_block->prev = 0;
+ free_block->prev = NULL;
if (free_blocks)
free_blocks->prev = free_block;
free_blocks = free_block;
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;
/*
* 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:
#include "sljitLir.h"
+#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 */
+
#define CHECK_ERROR() \
do { \
if (SLJIT_UNLIKELY(compiler->error)) \
#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+#define VARIABLE_FLAG_SHIFT (10)
+#define VARIABLE_FLAG_MASK (0x3f << VARIABLE_FLAG_SHIFT)
+#define GET_FLAG_TYPE(op) ((op) >> VARIABLE_FLAG_SHIFT)
+
#define GET_OPCODE(op) \
- ((op) & ~(SLJIT_INT_OP | SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))
+ ((op) & ~(SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK))
-#define GET_FLAGS(op) \
- ((op) & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C))
+#define HAS_FLAGS(op) \
+ ((op) & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))
#define GET_ALL_FLAGS(op) \
- ((op) & (SLJIT_INT_OP | SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))
+ ((op) & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK))
#define TYPE_CAST_NEEDED(op) \
- (((op) >= SLJIT_MOV_UB && (op) <= SLJIT_MOV_SH) || ((op) >= SLJIT_MOVU_UB && (op) <= SLJIT_MOVU_SH))
+ (((op) >= SLJIT_MOV_U8 && (op) <= SLJIT_MOV_S16) || ((op) >= SLJIT_MOVU_U8 && (op) <= SLJIT_MOVU_S16))
#define BUF_SIZE 4096
#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+#include "sljitProtExecAllocator.c"
+#else
#include "sljitExecAllocator.c"
#endif
+#endif
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr) + (exec_offset))
+#else
+#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr))
+#endif
+
/* Argument checking features. */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
return 1; \
} while (0)
-#define CHECK_RETURN_TYPE sljit_si
+#define CHECK_RETURN_TYPE sljit_s32
#define CHECK_RETURN_OK return 0
#define CHECK(x) \
/* Public functions */
/* --------------------------------------------------------------------- */
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
#define SLJIT_NEEDS_COMPILER_INIT 1
-static sljit_si compiler_initialized = 0;
+static sljit_s32 compiler_initialized = 0;
/* A thread safe initialization. */
static void init_compiler(void);
#endif
SLJIT_ZEROMEM(compiler, sizeof(struct sljit_compiler));
SLJIT_COMPILE_ASSERT(
- sizeof(sljit_sb) == 1 && sizeof(sljit_ub) == 1
- && sizeof(sljit_sh) == 2 && sizeof(sljit_uh) == 2
- && sizeof(sljit_si) == 4 && sizeof(sljit_ui) == 4
+ sizeof(sljit_s8) == 1 && sizeof(sljit_u8) == 1
+ && sizeof(sljit_s16) == 2 && sizeof(sljit_u16) == 2
+ && sizeof(sljit_s32) == 4 && sizeof(sljit_u32) == 4
&& (sizeof(sljit_p) == 4 || sizeof(sljit_p) == 8)
&& sizeof(sljit_p) <= sizeof(sljit_sw)
&& (sizeof(sljit_sw) == 4 || sizeof(sljit_sw) == 8)
&& (sizeof(sljit_uw) == 4 || sizeof(sljit_uw) == 8),
invalid_integer_types);
- SLJIT_COMPILE_ASSERT(SLJIT_INT_OP == SLJIT_SINGLE_OP,
+ SLJIT_COMPILE_ASSERT(SLJIT_I32_OP == SLJIT_F32_OP,
int_op_and_single_op_must_be_the_same);
- SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_SINGLE_OP,
+ SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_F32_OP,
rewritable_jump_and_single_op_must_not_be_the_same);
+ SLJIT_COMPILE_ASSERT(!(SLJIT_EQUAL & 0x1) && !(SLJIT_LESS & 0x1) && !(SLJIT_EQUAL_F64 & 0x1) && !(SLJIT_JUMP & 0x1),
+ conditional_flags_must_be_even_numbers);
/* Only the non-zero members must be set. */
compiler->error = SLJIT_SUCCESS;
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
compiler->cpool = (sljit_uw*)SLJIT_MALLOC(CPOOL_SIZE * sizeof(sljit_uw)
- + CPOOL_SIZE * sizeof(sljit_ub), allocator_data);
+ + CPOOL_SIZE * sizeof(sljit_u8), allocator_data);
if (!compiler->cpool) {
SLJIT_FREE(compiler->buf, allocator_data);
SLJIT_FREE(compiler->abuf, allocator_data);
SLJIT_FREE(compiler, allocator_data);
return NULL;
}
- compiler->cpool_unique = (sljit_ub*)(compiler->cpool + CPOOL_SIZE);
+ compiler->cpool_unique = (sljit_u8*)(compiler->cpool + CPOOL_SIZE);
compiler->cpool_diff = 0xffffffff;
#endif
}
}
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
+{
+ SLJIT_UNUSED_ARG(compiler);
+ SLJIT_UNUSED_ARG(current_flags);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_I32_OP | SLJIT_SET_Z)) == 0) {
+ compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_I32_OP | SLJIT_SET_Z));
+ }
+#endif
+}
+
/* --------------------------------------------------------------------- */
/* Private functions */
/* --------------------------------------------------------------------- */
static void* ensure_buf(struct sljit_compiler *compiler, sljit_uw size)
{
- sljit_ub *ret;
+ sljit_u8 *ret;
struct sljit_memory_fragment *new_frag;
SLJIT_ASSERT(size <= 256);
static void* ensure_abuf(struct sljit_compiler *compiler, sljit_uw size)
{
- sljit_ub *ret;
+ sljit_u8 *ret;
struct sljit_memory_fragment *new_frag;
SLJIT_ASSERT(size <= 256);
return new_frag->memory;
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size)
{
CHECK_ERROR_PTR();
}
static SLJIT_INLINE void set_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
SLJIT_UNUSED_ARG(args);
SLJIT_UNUSED_ARG(local_size);
}
static SLJIT_INLINE void set_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
SLJIT_UNUSED_ARG(args);
SLJIT_UNUSED_ARG(local_size);
compiler->last_label = label;
}
-static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_si flags)
+static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_s32 flags)
{
jump->next = NULL;
jump->flags = flags;
(((exp) & SLJIT_MEM) && (((exp) & REG_MASK) == reg || OFFS_REG(exp) == reg))
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
-#define FUNCTION_CHECK_OP() \
- CHECK_ARGUMENT(!GET_FLAGS(op) || !(op & SLJIT_KEEP_FLAGS)); \
- switch (GET_OPCODE(op)) { \
- case SLJIT_NOT: \
- case SLJIT_CLZ: \
- case SLJIT_AND: \
- case SLJIT_OR: \
- case SLJIT_XOR: \
- case SLJIT_SHL: \
- case SLJIT_LSHR: \
- case SLJIT_ASHR: \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C))); \
- break; \
- case SLJIT_NEG: \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))); \
- break; \
- case SLJIT_MUL: \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))); \
- break; \
- case SLJIT_ADD: \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_U | SLJIT_SET_S))); \
- break; \
- case SLJIT_SUB: \
- break; \
- case SLJIT_ADDC: \
- case SLJIT_SUBC: \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O))); \
- break; \
- case SLJIT_BREAKPOINT: \
- case SLJIT_NOP: \
- case SLJIT_LUMUL: \
- case SLJIT_LSMUL: \
- case SLJIT_MOV: \
- case SLJIT_MOV_UI: \
- case SLJIT_MOV_P: \
- case SLJIT_MOVU: \
- case SLJIT_MOVU_UI: \
- case SLJIT_MOVU_P: \
- /* Nothing allowed */ \
- CHECK_ARGUMENT(!(op & (SLJIT_INT_OP | SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \
- break; \
- default: \
- /* Only SLJIT_INT_OP or SLJIT_SINGLE_OP is allowed. */ \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \
- break; \
- }
-
-#define FUNCTION_CHECK_FOP() \
- CHECK_ARGUMENT(!GET_FLAGS(op) || !(op & SLJIT_KEEP_FLAGS)); \
- switch (GET_OPCODE(op)) { \
- case SLJIT_DCMP: \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \
- CHECK_ARGUMENT((op & (SLJIT_SET_E | SLJIT_SET_S))); \
- break; \
- default: \
- /* Only SLJIT_INT_OP or SLJIT_SINGLE_OP is allowed. */ \
- CHECK_ARGUMENT(!(op & (SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \
- break; \
- }
#define FUNCTION_CHECK_IS_REG(r) \
(((r) >= SLJIT_R0 && (r) < (SLJIT_R0 + compiler->scratches)) || \
CHECK_NOT_VIRTUAL_REGISTER(OFFS_REG(p)); \
CHECK_ARGUMENT(!((i) & ~0x3)); \
} \
- CHECK_ARGUMENT(!((p) & ~(SLJIT_MEM | SLJIT_IMM | REG_MASK | OFFS_REG_MASK))); \
+ CHECK_ARGUMENT(!((p) & ~(SLJIT_MEM | REG_MASK | OFFS_REG_MASK))); \
}
-#define FUNCTION_CHECK_DST(p, i) \
+#define FUNCTION_CHECK_DST(p, i, unused) \
CHECK_ARGUMENT(compiler->scratches != -1 && compiler->saveds != -1); \
- if (FUNCTION_CHECK_IS_REG_OR_UNUSED(p)) \
+ if (FUNCTION_CHECK_IS_REG(p) || ((unused) && (p) == SLJIT_UNUSED)) \
CHECK_ARGUMENT((i) == 0); \
else if ((p) == (SLJIT_MEM1(SLJIT_SP))) \
CHECK_ARGUMENT((i) >= 0 && (i) < compiler->logical_local_size); \
CHECK_NOT_VIRTUAL_REGISTER(OFFS_REG(p)); \
CHECK_ARGUMENT(!((i) & ~0x3)); \
} \
- CHECK_ARGUMENT(!((p) & ~(SLJIT_MEM | SLJIT_IMM | REG_MASK | OFFS_REG_MASK))); \
+ CHECK_ARGUMENT(!((p) & ~(SLJIT_MEM | REG_MASK | OFFS_REG_MASK))); \
}
#define FUNCTION_FCHECK(p, i) \
CHECK_NOT_VIRTUAL_REGISTER(OFFS_REG(p)); \
CHECK_ARGUMENT(((p) & OFFS_REG_MASK) != TO_OFFS_REG(SLJIT_SP) && !(i & ~0x3)); \
} \
- CHECK_ARGUMENT(!((p) & ~(SLJIT_MEM | SLJIT_IMM | REG_MASK | OFFS_REG_MASK))); \
- }
-
-#define FUNCTION_CHECK_OP1() \
- if (GET_OPCODE(op) >= SLJIT_MOVU && GET_OPCODE(op) <= SLJIT_MOVU_P) { \
- CHECK_ARGUMENT(!(src & SLJIT_MEM) || (src & REG_MASK) != SLJIT_SP); \
- CHECK_ARGUMENT(!(dst & SLJIT_MEM) || (dst & REG_MASK) != SLJIT_SP); \
- if ((src & SLJIT_MEM) && (src & REG_MASK)) \
- CHECK_ARGUMENT((dst & REG_MASK) != (src & REG_MASK) && OFFS_REG(dst) != (src & REG_MASK)); \
+ CHECK_ARGUMENT(!((p) & ~(SLJIT_MEM | REG_MASK | OFFS_REG_MASK))); \
}
#endif /* SLJIT_ARGUMENT_CHECKS */
do { \
if ((r) < (SLJIT_R0 + compiler->scratches)) \
fprintf(compiler->verbose, "r%d", (r) - SLJIT_R0); \
- else \
+ else if ((r) != SLJIT_SP) \
fprintf(compiler->verbose, "s%d", SLJIT_NUMBER_OF_REGISTERS - (r)); \
+ else \
+ fprintf(compiler->verbose, "sp"); \
} while (0)
#define sljit_verbose_param(compiler, p, i) \
fprintf(compiler->verbose, "fs%d", SLJIT_NUMBER_OF_FLOAT_REGISTERS - (p)); \
}
-static SLJIT_CONST char* op0_names[] = {
- (char*)"breakpoint", (char*)"nop", (char*)"lumul", (char*)"lsmul",
- (char*)"udivmod", (char*)"sdivmod", (char*)"udivi", (char*)"sdivi"
+static const char* op0_names[] = {
+ (char*)"breakpoint", (char*)"nop", (char*)"lmul.uw", (char*)"lmul.sw",
+ (char*)"divmod.u", (char*)"divmod.s", (char*)"div.u", (char*)"div.s"
};
-static SLJIT_CONST char* op1_names[] = {
- (char*)"mov", (char*)"mov_ub", (char*)"mov_sb", (char*)"mov_uh",
- (char*)"mov_sh", (char*)"mov_ui", (char*)"mov_si", (char*)"mov_p",
- (char*)"movu", (char*)"movu_ub", (char*)"movu_sb", (char*)"movu_uh",
- (char*)"movu_sh", (char*)"movu_ui", (char*)"movu_si", (char*)"movu_p",
+static const char* op1_names[] = {
+ (char*)"", (char*)".u8", (char*)".s8", (char*)".u16",
+ (char*)".s16", (char*)".u32", (char*)".s32", (char*)".p",
+ (char*)"", (char*)".u8", (char*)".s8", (char*)".u16",
+ (char*)".s16", (char*)".u32", (char*)".s32", (char*)".p",
(char*)"not", (char*)"neg", (char*)"clz",
};
-static SLJIT_CONST char* op2_names[] = {
+static const char* op2_names[] = {
(char*)"add", (char*)"addc", (char*)"sub", (char*)"subc",
(char*)"mul", (char*)"and", (char*)"or", (char*)"xor",
(char*)"shl", (char*)"lshr", (char*)"ashr",
};
-static SLJIT_CONST char* fop1_names[] = {
+static const char* fop1_names[] = {
(char*)"mov", (char*)"conv", (char*)"conv", (char*)"conv",
(char*)"conv", (char*)"conv", (char*)"cmp", (char*)"neg",
(char*)"abs",
};
-static SLJIT_CONST char* fop2_names[] = {
+static const char* fop2_names[] = {
(char*)"add", (char*)"sub", (char*)"mul", (char*)"div"
};
-#define JUMP_PREFIX(type) \
- ((type & 0xff) <= SLJIT_MUL_NOT_OVERFLOW ? ((type & SLJIT_INT_OP) ? "i_" : "") \
- : ((type & 0xff) <= SLJIT_D_ORDERED ? ((type & SLJIT_SINGLE_OP) ? "s_" : "d_") : ""))
+#define JUMP_POSTFIX(type) \
+ ((type & 0xff) <= SLJIT_MUL_NOT_OVERFLOW ? ((type & SLJIT_I32_OP) ? "32" : "") \
+ : ((type & 0xff) <= SLJIT_ORDERED_F64 ? ((type & SLJIT_F32_OP) ? ".f32" : ".f64") : ""))
static char* jump_names[] = {
(char*)"equal", (char*)"not_equal",
(char*)"sig_greater", (char*)"sig_less_equal",
(char*)"overflow", (char*)"not_overflow",
(char*)"mul_overflow", (char*)"mul_not_overflow",
+ (char*)"carry", (char*)"",
(char*)"equal", (char*)"not_equal",
(char*)"less", (char*)"greater_equal",
(char*)"greater", (char*)"less_equal",
}
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
SLJIT_UNUSED_ARG(compiler);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(!(options & ~SLJIT_DOUBLE_ALIGNMENT));
+ CHECK_ARGUMENT(!(options & ~SLJIT_F64_ALIGNMENT));
CHECK_ARGUMENT(args >= 0 && args <= 3);
CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS);
CHECK_ARGUMENT(saveds >= 0 && saveds <= SLJIT_NUMBER_OF_REGISTERS);
CHECK_ARGUMENT(fsaveds >= 0 && fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
CHECK_ARGUMENT(fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
CHECK_ARGUMENT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose))
}
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- if (SLJIT_UNLIKELY(compiler->skip_checks)) {
- compiler->skip_checks = 0;
- CHECK_RETURN_OK;
- }
-
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(!(options & ~SLJIT_DOUBLE_ALIGNMENT));
+ CHECK_ARGUMENT(!(options & ~SLJIT_F64_ALIGNMENT));
CHECK_ARGUMENT(args >= 0 && args <= 3);
CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS);
CHECK_ARGUMENT(saveds >= 0 && saveds <= SLJIT_NUMBER_OF_REGISTERS);
CHECK_ARGUMENT(fsaveds >= 0 && fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
CHECK_ARGUMENT(fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
CHECK_ARGUMENT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose))
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(compiler->scratches >= 0);
}
else
CHECK_ARGUMENT(src == 0 && srcw == 0);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
if (op == SLJIT_UNUSED)
fprintf(compiler->verbose, " return\n");
else {
- fprintf(compiler->verbose, " return.%s ", op1_names[op - SLJIT_OP1_BASE]);
+ fprintf(compiler->verbose, " return%s ", op1_names[op - SLJIT_OP1_BASE]);
sljit_verbose_param(compiler, src, srcw);
fprintf(compiler->verbose, "\n");
}
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- FUNCTION_CHECK_DST(dst, dstw);
+ FUNCTION_CHECK_DST(dst, dstw, 0);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
FUNCTION_CHECK_SRC(src, srcw);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LSMUL)
- || ((op & ~SLJIT_INT_OP) >= SLJIT_UDIVMOD && (op & ~SLJIT_INT_OP) <= SLJIT_SDIVI));
- CHECK_ARGUMENT(op < SLJIT_LUMUL || compiler->scratches >= 2);
+ CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LMUL_SW)
+ || ((op & ~SLJIT_I32_OP) >= SLJIT_DIVMOD_UW && (op & ~SLJIT_I32_OP) <= SLJIT_DIV_SW));
+ CHECK_ARGUMENT(op < SLJIT_LMUL_UW || compiler->scratches >= 2);
+ if (op >= SLJIT_LMUL_UW)
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose))
- fprintf(compiler->verbose, " %s%s\n", !(op & SLJIT_INT_OP) ? "" : "i", op0_names[GET_OPCODE(op) - SLJIT_OP0_BASE]);
+ {
+ fprintf(compiler->verbose, " %s", op0_names[GET_OPCODE(op) - SLJIT_OP0_BASE]);
+ if (GET_OPCODE(op) >= SLJIT_DIVMOD_UW) {
+ fprintf(compiler->verbose, (op & SLJIT_I32_OP) ? "32" : "w");
+ }
+ fprintf(compiler->verbose, "\n");
+ }
#endif
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_CLZ);
- FUNCTION_CHECK_OP();
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_NOT:
+ /* Only SLJIT_I32_OP and SLJIT_SET_Z are allowed. */
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
+ break;
+ case SLJIT_NEG:
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+ || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
+ break;
+ case SLJIT_MOV:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_P:
+ case SLJIT_MOVU:
+ case SLJIT_MOVU_U32:
+ case SLJIT_MOVU_P:
+ /* Nothing allowed */
+ CHECK_ARGUMENT(!(op & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+ break;
+ default:
+ /* Only SLJIT_I32_OP is allowed. */
+ CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+ break;
+ }
+
+ FUNCTION_CHECK_DST(dst, dstw, 1);
FUNCTION_CHECK_SRC(src, srcw);
- FUNCTION_CHECK_DST(dst, dstw);
- FUNCTION_CHECK_OP1();
+
+ if (GET_OPCODE(op) >= SLJIT_NOT)
+ compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
+ else if (GET_OPCODE(op) >= SLJIT_MOVU) {
+ CHECK_ARGUMENT(!(src & SLJIT_MEM) || (src & REG_MASK) != SLJIT_SP);
+ CHECK_ARGUMENT(!(dst & SLJIT_MEM) || (dst & REG_MASK) != SLJIT_SP);
+ if ((src & REG_MASK) != SLJIT_UNUSED) {
+ CHECK_ARGUMENT((src & REG_MASK) != (dst & REG_MASK) && (src & REG_MASK) != OFFS_REG(dst));
+ CHECK_ARGUMENT((src & OFFS_REG_MASK) == SLJIT_UNUSED || srcw == 0);
+ }
+ if ((dst & REG_MASK) != SLJIT_UNUSED) {
+ CHECK_ARGUMENT((dst & REG_MASK) != OFFS_REG(src));
+ CHECK_ARGUMENT((dst & OFFS_REG_MASK) == SLJIT_UNUSED || dstw == 0);
+ }
+ compiler->last_flags = 0;
+ }
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " %s%s%s%s%s%s%s%s ", !(op & SLJIT_INT_OP) ? "" : "i", op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE],
- !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_SET_U) ? "" : ".u", !(op & SLJIT_SET_S) ? "" : ".s",
- !(op & SLJIT_SET_O) ? "" : ".o", !(op & SLJIT_SET_C) ? "" : ".c", !(op & SLJIT_KEEP_FLAGS) ? "" : ".k");
+ if (GET_OPCODE(op) <= SLJIT_MOVU_P)
+ {
+ fprintf(compiler->verbose, " mov%s%s%s ", (GET_OPCODE(op) >= SLJIT_MOVU) ? "u" : "",
+ !(op & SLJIT_I32_OP) ? "" : "32", (op != SLJIT_MOV32 && op != SLJIT_MOVU32) ? op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE] : "");
+ }
+ else
+ {
+ fprintf(compiler->verbose, " %s%s%s%s%s ", op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE], !(op & SLJIT_I32_OP) ? "" : "32",
+ !(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".",
+ !(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]);
+ }
+
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
sljit_verbose_param(compiler, src, srcw);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(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)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD && GET_OPCODE(op) <= SLJIT_ASHR);
- FUNCTION_CHECK_OP();
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_AND:
+ case SLJIT_OR:
+ case SLJIT_XOR:
+ case SLJIT_SHL:
+ case SLJIT_LSHR:
+ case SLJIT_ASHR:
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
+ break;
+ case SLJIT_MUL:
+ CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+ || GET_FLAG_TYPE(op) == SLJIT_MUL_OVERFLOW);
+ break;
+ case SLJIT_ADD:
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+ || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)
+ || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
+ break;
+ case SLJIT_SUB:
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+ || (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_OVERFLOW)
+ || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY));
+ break;
+ case SLJIT_ADDC:
+ case SLJIT_SUBC:
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+ || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY));
+ CHECK_ARGUMENT((compiler->last_flags & 0xff) == GET_FLAG_TYPE(SLJIT_SET_CARRY));
+ CHECK_ARGUMENT((op & SLJIT_I32_OP) == (compiler->last_flags & SLJIT_I32_OP));
+ break;
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+
+ FUNCTION_CHECK_DST(dst, dstw, 1);
FUNCTION_CHECK_SRC(src1, src1w);
FUNCTION_CHECK_SRC(src2, src2w);
- FUNCTION_CHECK_DST(dst, dstw);
+ compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " %s%s%s%s%s%s%s%s ", !(op & SLJIT_INT_OP) ? "" : "i", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE],
- !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_SET_U) ? "" : ".u", !(op & SLJIT_SET_S) ? "" : ".s",
- !(op & SLJIT_SET_O) ? "" : ".o", !(op & SLJIT_SET_C) ? "" : ".c", !(op & SLJIT_KEEP_FLAGS) ? "" : ".k");
+ fprintf(compiler->verbose, " %s%s%s%s%s ", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], !(op & SLJIT_I32_OP) ? "" : "32",
+ !(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".",
+ !(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]);
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
sljit_verbose_param(compiler, src1, src1w);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_si reg)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 reg)
{
SLJIT_UNUSED_ARG(reg);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_float_register_index(sljit_si reg)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_float_register_index(sljit_s32 reg)
{
SLJIT_UNUSED_ARG(reg);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
}
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+ void *instruction, sljit_s32 size)
{
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
int i;
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(instruction);
+
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
CHECK_ARGUMENT(size > 0 && size < 16);
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
CHECK_ARGUMENT(size == 4 && (((sljit_sw)instruction) & 0x3) == 0);
#endif
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " op_custom");
for (i = 0; i < size; i++)
- fprintf(compiler->verbose, " 0x%x", ((sljit_ub*)instruction)[i]);
+ fprintf(compiler->verbose, " 0x%x", ((sljit_u8*)instruction)[i]);
fprintf(compiler->verbose, "\n");
}
#endif
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_is_fpu_available());
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_DMOV && GET_OPCODE(op) <= SLJIT_DABS);
- FUNCTION_CHECK_FOP();
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV_F64 && GET_OPCODE(op) <= SLJIT_ABS_F64);
+ CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
FUNCTION_FCHECK(src, srcw);
FUNCTION_FCHECK(dst, dstw);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMS)
- fprintf(compiler->verbose, " %s%s ", fop1_names[SLJIT_CONVD_FROMS - SLJIT_FOP1_BASE],
- (op & SLJIT_SINGLE_OP) ? "s.fromd" : "d.froms");
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+ fprintf(compiler->verbose, " %s%s ", fop1_names[SLJIT_CONV_F64_FROM_F32 - SLJIT_FOP1_BASE],
+ (op & SLJIT_F32_OP) ? ".f32.from.f64" : ".f64.from.f32");
else
- fprintf(compiler->verbose, " %s%s ", (op & SLJIT_SINGLE_OP) ? "s" : "d",
- fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE]);
+ fprintf(compiler->verbose, " %s%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
+ (op & SLJIT_F32_OP) ? ".f32" : ".f64");
sljit_verbose_fparam(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
+#endif
+
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
CHECK_RETURN_OK;
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_is_fpu_available());
- CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_DCMP);
- FUNCTION_CHECK_FOP();
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_CMP_F64);
+ CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
+ CHECK_ARGUMENT((op & VARIABLE_FLAG_MASK)
+ || (GET_FLAG_TYPE(op) >= SLJIT_EQUAL_F64 && GET_FLAG_TYPE(op) <= SLJIT_ORDERED_F64));
FUNCTION_FCHECK(src1, src1w);
FUNCTION_FCHECK(src2, src2w);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " %s%s%s%s ", (op & SLJIT_SINGLE_OP) ? "s" : "d", fop1_names[SLJIT_DCMP - SLJIT_FOP1_BASE],
- (op & SLJIT_SET_E) ? ".e" : "", (op & SLJIT_SET_S) ? ".s" : "");
+ fprintf(compiler->verbose, " %s%s", fop1_names[SLJIT_CMP_F64 - SLJIT_FOP1_BASE], (op & SLJIT_F32_OP) ? ".f32" : ".f64");
+ if (op & VARIABLE_FLAG_MASK) {
+ fprintf(compiler->verbose, ".%s_f", jump_names[GET_FLAG_TYPE(op)]);
+ }
+ fprintf(compiler->verbose, " ");
sljit_verbose_fparam(compiler, src1, src1w);
fprintf(compiler->verbose, ", ");
sljit_verbose_fparam(compiler, src2, src2w);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_is_fpu_available());
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONVW_FROMD && GET_OPCODE(op) <= SLJIT_CONVI_FROMD);
- FUNCTION_CHECK_FOP();
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CONV_S32_FROM_F64);
+ CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
FUNCTION_FCHECK(src, srcw);
- FUNCTION_CHECK_DST(dst, dstw);
+ FUNCTION_CHECK_DST(dst, dstw, 0);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
- (GET_OPCODE(op) == SLJIT_CONVI_FROMD) ? "i" : "w",
- (op & SLJIT_SINGLE_OP) ? "s" : "d");
+ (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? ".s32" : ".sw",
+ (op & SLJIT_F32_OP) ? ".f32" : ".f64");
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
sljit_verbose_fparam(compiler, src, srcw);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_is_fpu_available());
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONVD_FROMW && GET_OPCODE(op) <= SLJIT_CONVD_FROMI);
- FUNCTION_CHECK_FOP();
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_F64_FROM_SW && GET_OPCODE(op) <= SLJIT_CONV_F64_FROM_S32);
+ CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
FUNCTION_CHECK_SRC(src, srcw);
FUNCTION_FCHECK(dst, dstw);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
- (op & SLJIT_SINGLE_OP) ? "s" : "d",
- (GET_OPCODE(op) == SLJIT_CONVD_FROMI) ? "i" : "w");
+ (op & SLJIT_F32_OP) ? ".f32" : ".f64",
+ (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? ".s32" : ".sw");
sljit_verbose_fparam(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
sljit_verbose_param(compiler, src, srcw);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_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)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_is_fpu_available());
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_DADD && GET_OPCODE(op) <= SLJIT_DDIV);
- FUNCTION_CHECK_FOP();
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD_F64 && GET_OPCODE(op) <= SLJIT_DIV_F64);
+ CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
FUNCTION_FCHECK(src1, src1w);
FUNCTION_FCHECK(src2, src2w);
FUNCTION_FCHECK(dst, dstw);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " %s%s ", (op & SLJIT_SINGLE_OP) ? "s" : "d", fop2_names[GET_OPCODE(op) - SLJIT_FOP2_BASE]);
+ fprintf(compiler->verbose, " %s%s ", fop2_names[GET_OPCODE(op) - SLJIT_FOP2_BASE], (op & SLJIT_F32_OP) ? ".f32" : ".f64");
sljit_verbose_fparam(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
sljit_verbose_fparam(compiler, src1, src1w);
{
SLJIT_UNUSED_ARG(compiler);
+ if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+ compiler->skip_checks = 0;
+ CHECK_RETURN_OK;
+ }
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ compiler->last_flags = 0;
+#endif
+
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose))
fprintf(compiler->verbose, "label:\n");
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_INT_OP)));
+ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_I32_OP)));
+ CHECK_ARGUMENT((type & 0xff) != GET_FLAG_TYPE(SLJIT_SET_CARRY) && (type & 0xff) != (GET_FLAG_TYPE(SLJIT_SET_CARRY) + 1));
CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_CALL3);
- CHECK_ARGUMENT((type & 0xff) < SLJIT_JUMP || !(type & SLJIT_INT_OP));
+ CHECK_ARGUMENT((type & 0xff) < SLJIT_JUMP || !(type & SLJIT_I32_OP));
CHECK_ARGUMENT((type & 0xff) <= SLJIT_CALL0 || ((type & 0xff) - SLJIT_CALL0) <= compiler->scratches);
+
+ if ((type & 0xff) < SLJIT_JUMP) {
+ if ((type & 0xff) <= SLJIT_NOT_ZERO)
+ CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+ else
+ CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
+ || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+ || ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+ CHECK_ARGUMENT((type & SLJIT_I32_OP) == (compiler->last_flags & SLJIT_I32_OP));
+ }
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose))
- fprintf(compiler->verbose, " jump%s.%s%s\n", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
- JUMP_PREFIX(type), jump_names[type & 0xff]);
+ fprintf(compiler->verbose, " jump%s %s%s\n", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
+ jump_names[type & 0xff], JUMP_POSTFIX(type));
#endif
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_INT_OP)));
+ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_I32_OP)));
CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_SIG_LESS_EQUAL);
FUNCTION_CHECK_SRC(src1, src1w);
FUNCTION_CHECK_SRC(src2, src2w);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " cmp%s.%s%s ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
- (type & SLJIT_INT_OP) ? "i_" : "", jump_names[type & 0xff]);
+ fprintf(compiler->verbose, " cmp%s %s%s, ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
+ jump_names[type & 0xff], (type & SLJIT_I32_OP) ? "32" : "");
sljit_verbose_param(compiler, src1, src1w);
fprintf(compiler->verbose, ", ");
sljit_verbose_param(compiler, src2, src2w);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_is_fpu_available());
- CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_SINGLE_OP)));
- CHECK_ARGUMENT((type & 0xff) >= SLJIT_D_EQUAL && (type & 0xff) <= SLJIT_D_ORDERED);
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_F32_OP)));
+ CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL_F64 && (type & 0xff) <= SLJIT_ORDERED_F64);
FUNCTION_FCHECK(src1, src1w);
FUNCTION_FCHECK(src2, src2w);
+ compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " fcmp%s.%s%s ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
- (type & SLJIT_SINGLE_OP) ? "s_" : "d_", jump_names[type & 0xff]);
+ fprintf(compiler->verbose, " fcmp%s %s%s, ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
+ jump_names[type & 0xff], (type & SLJIT_F32_OP) ? ".f32" : ".f64");
sljit_verbose_fparam(compiler, src1, src1w);
fprintf(compiler->verbose, ", ");
sljit_verbose_fparam(compiler, src2, src2w);
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ compiler->last_flags = 0;
+#endif
+
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
CHECK_RETURN_OK;
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 type)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_INT_OP)));
- CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_D_ORDERED);
- CHECK_ARGUMENT(op == SLJIT_MOV || GET_OPCODE(op) == SLJIT_MOV_UI || GET_OPCODE(op) == SLJIT_MOV_SI
+ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_I32_OP)));
+ CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_ORDERED_F64);
+ CHECK_ARGUMENT((type & 0xff) != GET_FLAG_TYPE(SLJIT_SET_CARRY) && (type & 0xff) != (GET_FLAG_TYPE(SLJIT_SET_CARRY) + 1));
+ CHECK_ARGUMENT(op == SLJIT_MOV || op == SLJIT_MOV32
|| (GET_OPCODE(op) >= SLJIT_AND && GET_OPCODE(op) <= SLJIT_XOR));
- CHECK_ARGUMENT((op & (SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_O | SLJIT_SET_C)) == 0);
- CHECK_ARGUMENT((op & (SLJIT_SET_E | SLJIT_KEEP_FLAGS)) != (SLJIT_SET_E | SLJIT_KEEP_FLAGS));
- if (GET_OPCODE(op) < SLJIT_ADD) {
- CHECK_ARGUMENT(src == SLJIT_UNUSED && srcw == 0);
- } else {
- CHECK_ARGUMENT(src == dst && srcw == dstw);
- }
- FUNCTION_CHECK_DST(dst, dstw);
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
+
+ if ((type & 0xff) <= SLJIT_NOT_ZERO)
+ CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+ else
+ CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
+ || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+ || ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+
+ FUNCTION_CHECK_DST(dst, dstw, 0);
+
+ if (GET_OPCODE(op) >= SLJIT_ADD)
+ compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " flags.%s%s%s%s ", !(op & SLJIT_INT_OP) ? "" : "i",
- GET_OPCODE(op) >= SLJIT_OP2_BASE ? op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE] : op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE],
- !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_KEEP_FLAGS) ? "" : ".k");
+ fprintf(compiler->verbose, " flags%s %s%s, ",
+ !(op & SLJIT_SET_Z) ? "" : ".z",
+ GET_OPCODE(op) < SLJIT_OP2_BASE ? "mov" : op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE],
+ GET_OPCODE(op) < SLJIT_OP2_BASE ? op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE] : ((op & SLJIT_I32_OP) ? "32" : ""));
sljit_verbose_param(compiler, dst, dstw);
- if (src != SLJIT_UNUSED) {
- fprintf(compiler->verbose, ", ");
- sljit_verbose_param(compiler, src, srcw);
- }
- fprintf(compiler->verbose, ", %s%s\n", JUMP_PREFIX(type), jump_names[type & 0xff]);
+ fprintf(compiler->verbose, ", %s%s\n", jump_names[type & 0xff], JUMP_POSTFIX(type));
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_I32_OP)));
+ CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_ORDERED_F64);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg & ~SLJIT_I32_OP));
+ if (src != SLJIT_IMM) {
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src));
+ }
+
+ if ((type & 0xff) <= SLJIT_NOT_ZERO)
+ CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+ else
+ CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
+ || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+ || ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " cmov%s %s%s, ",
+ !(dst_reg & SLJIT_I32_OP) ? "" : ".i",
+ jump_names[type & 0xff], JUMP_POSTFIX(type));
+ sljit_verbose_reg(compiler, dst_reg & ~SLJIT_I32_OP);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_param(compiler, src, srcw);
+ fprintf(compiler->verbose, "\n");
}
#endif
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
{
SLJIT_UNUSED_ARG(offset);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- FUNCTION_CHECK_DST(dst, dstw);
+ FUNCTION_CHECK_DST(dst, dstw, 0);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
SLJIT_UNUSED_ARG(init_value);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- FUNCTION_CHECK_DST(dst, dstw);
+ FUNCTION_CHECK_DST(dst, dstw, 0);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_VERBOSE */
#define SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw) \
- SLJIT_COMPILE_ASSERT(!(SLJIT_CONVW_FROMD & 0x1) && !(SLJIT_CONVD_FROMW & 0x1), \
+ SLJIT_COMPILE_ASSERT(!(SLJIT_CONV_SW_FROM_F64 & 0x1) && !(SLJIT_CONV_F64_FROM_SW & 0x1), \
invalid_float_opcodes); \
- if (GET_OPCODE(op) >= SLJIT_CONVW_FROMD && GET_OPCODE(op) <= SLJIT_DCMP) { \
- if (GET_OPCODE(op) == SLJIT_DCMP) { \
+ if (GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CMP_F64) { \
+ if (GET_OPCODE(op) == SLJIT_CMP_F64) { \
CHECK(check_sljit_emit_fop1_cmp(compiler, op, dst, dstw, src, srcw)); \
ADJUST_LOCAL_OFFSET(dst, dstw); \
ADJUST_LOCAL_OFFSET(src, srcw); \
return sljit_emit_fop1_cmp(compiler, op, dst, dstw, src, srcw); \
} \
- if ((GET_OPCODE(op) | 0x1) == SLJIT_CONVI_FROMD) { \
- CHECK(check_sljit_emit_fop1_convw_fromd(compiler, op, dst, dstw, src, srcw)); \
+ if ((GET_OPCODE(op) | 0x1) == SLJIT_CONV_S32_FROM_F64) { \
+ CHECK(check_sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw)); \
ADJUST_LOCAL_OFFSET(dst, dstw); \
ADJUST_LOCAL_OFFSET(src, srcw); \
- return sljit_emit_fop1_convw_fromd(compiler, op, dst, dstw, src, srcw); \
+ return sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw); \
} \
- CHECK(check_sljit_emit_fop1_convd_fromw(compiler, op, dst, dstw, src, srcw)); \
+ CHECK(check_sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw)); \
ADJUST_LOCAL_OFFSET(dst, dstw); \
ADJUST_LOCAL_OFFSET(src, srcw); \
- return sljit_emit_fop1_convd_fromw(compiler, op, dst, dstw, src, srcw); \
+ return sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw); \
} \
CHECK(check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw)); \
ADJUST_LOCAL_OFFSET(dst, dstw); \
ADJUST_LOCAL_OFFSET(src, srcw);
-static SLJIT_INLINE sljit_si emit_mov_before_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 emit_mov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
/* Return if don't need to do anything. */
if (op == SLJIT_UNUSED)
if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_P))
return SLJIT_SUCCESS;
#else
- if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_UI || op == SLJIT_MOV_SI || op == SLJIT_MOV_P))
+ if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_U32 || op == SLJIT_MOV_S32 || op == SLJIT_MOV_P))
return SLJIT_SUCCESS;
#endif
return sljit_emit_op1(compiler, op, SLJIT_RETURN_REG, 0, src, srcw);
}
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
+ || (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
+ || (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
+ || ((defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) && !(defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1))
+
+static SLJIT_INLINE sljit_s32 sljit_emit_cmov_generic(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ sljit_s32 op = (dst_reg & SLJIT_I32_OP) ? SLJIT_MOV32 : SLJIT_MOV;
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+ || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ compiler->skip_checks = 1;
+#endif
+ jump = sljit_emit_jump(compiler, type ^ 0x1);
+ FAIL_IF(!jump);
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+ || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ compiler->skip_checks = 1;
+#endif
+ FAIL_IF(sljit_emit_op1(compiler, op, dst_reg & ~SLJIT_I32_OP, 0, src, srcw));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+ || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ compiler->skip_checks = 1;
+#endif
+ label = sljit_emit_label(compiler);
+ FAIL_IF(!label);
+ sljit_set_label(jump, label);
+ return SLJIT_SUCCESS;
+}
+
+#endif
+
/* CPU description section */
#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
#if !(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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)
{
/* Default compare for most architectures. */
- sljit_si flags, tmp_src, condition;
+ sljit_s32 flags, tmp_src, condition;
sljit_sw tmp_srcw;
CHECK_ERROR_PTR();
condition = SLJIT_SIG_GREATER_EQUAL;
break;
}
- type = condition | (type & (SLJIT_INT_OP | SLJIT_REWRITABLE_JUMP));
+
+ type = condition | (type & (SLJIT_I32_OP | SLJIT_REWRITABLE_JUMP));
tmp_src = src1;
src1 = src2;
src2 = tmp_src;
}
if (condition <= SLJIT_NOT_ZERO)
- flags = SLJIT_SET_E;
- else if (condition <= SLJIT_LESS_EQUAL)
- flags = SLJIT_SET_U;
+ flags = SLJIT_SET_Z;
else
- flags = SLJIT_SET_S;
+ flags = condition << VARIABLE_FLAG_SHIFT;
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
- PTR_FAIL_IF(sljit_emit_op2(compiler, SLJIT_SUB | flags | (type & SLJIT_INT_OP),
+ PTR_FAIL_IF(sljit_emit_op2(compiler, SLJIT_SUB | flags | (type & SLJIT_I32_OP),
SLJIT_UNUSED, 0, src1, src1w, src2, src2w));
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
- return sljit_emit_jump(compiler, condition | (type & SLJIT_REWRITABLE_JUMP));
+ return sljit_emit_jump(compiler, condition | (type & (SLJIT_REWRITABLE_JUMP | SLJIT_I32_OP)));
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
-{
- sljit_si flags, condition;
+#endif
+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)
+{
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w));
- condition = type & 0xff;
- flags = (condition <= SLJIT_D_NOT_EQUAL) ? SLJIT_SET_E : SLJIT_SET_S;
- if (type & SLJIT_SINGLE_OP)
- flags |= SLJIT_SINGLE_OP;
-
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
- sljit_emit_fop1(compiler, SLJIT_DCMP | flags, src1, src1w, src2, src2w);
+ sljit_emit_fop1(compiler, SLJIT_CMP_F64 | ((type & 0xff) << VARIABLE_FLAG_SHIFT) | (type & SLJIT_I32_OP), src1, src1w, src2, src2w);
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
- return sljit_emit_jump(compiler, condition | (type & SLJIT_REWRITABLE_JUMP));
+ return sljit_emit_jump(compiler, type);
}
-#endif
-
#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
{
CHECK_ERROR();
CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
compiler->skip_checks = 1;
#endif
if (offset != 0)
- return sljit_emit_op2(compiler, SLJIT_ADD | SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
+ return sljit_emit_op2(compiler, SLJIT_ADD, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
return sljit_emit_op1(compiler, SLJIT_MOV, dst, dstw, SLJIT_SP, 0);
}
/* Empty function bodies for those machines, which are not (yet) supported. */
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "unsupported";
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data)
{
- SLJIT_ASSERT_STOP();
+ SLJIT_UNUSED_ARG(allocator_data);
+ SLJIT_UNREACHABLE();
return NULL;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler)
{
SLJIT_UNUSED_ARG(compiler);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler)
+{
+ SLJIT_UNUSED_ARG(compiler);
+ SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(size);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(verbose);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
#endif
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
{
SLJIT_UNUSED_ARG(compiler);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+ SLJIT_UNUSED_ARG(feature_type);
+ SLJIT_UNREACHABLE();
+ return 0;
+}
+
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code)
{
SLJIT_UNUSED_ARG(code);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(options);
SLJIT_UNUSED_ARG(fscratches);
SLJIT_UNUSED_ARG(fsaveds);
SLJIT_UNUSED_ARG(local_size);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(options);
SLJIT_UNUSED_ARG(fscratches);
SLJIT_UNUSED_ARG(fsaveds);
SLJIT_UNUSED_ARG(local_size);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(dst);
SLJIT_UNUSED_ARG(dstw);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(dstw);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(src1w);
SLJIT_UNUSED_ARG(src2);
SLJIT_UNUSED_ARG(src2w);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return reg;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(instruction);
SLJIT_UNUSED_ARG(size);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
{
- SLJIT_ASSERT_STOP();
- return 0;
+ SLJIT_UNUSED_ARG(compiler);
+ SLJIT_UNUSED_ARG(current_flags);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(dstw);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(src1w);
SLJIT_UNUSED_ARG(src2);
SLJIT_UNUSED_ARG(src2w);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
{
SLJIT_UNUSED_ARG(compiler);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(type);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(type);
SLJIT_UNUSED_ARG(src1w);
SLJIT_UNUSED_ARG(src2);
SLJIT_UNUSED_ARG(src2w);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(type);
SLJIT_UNUSED_ARG(src1w);
SLJIT_UNUSED_ARG(src2);
SLJIT_UNUSED_ARG(src2w);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
{
SLJIT_UNUSED_ARG(jump);
SLJIT_UNUSED_ARG(label);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target)
{
SLJIT_UNUSED_ARG(jump);
SLJIT_UNUSED_ARG(target);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(type);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(dst);
SLJIT_UNUSED_ARG(dstw);
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNREACHABLE();
+ return SLJIT_ERR_UNSUPPORTED;
+}
+
+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_UNUSED_ARG(compiler);
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(dst_reg);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNUSED_ARG(type);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(dst);
SLJIT_UNUSED_ARG(dstw);
SLJIT_UNUSED_ARG(offset);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw initval)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw initval)
{
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(dst);
SLJIT_UNUSED_ARG(dstw);
SLJIT_UNUSED_ARG(initval);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return NULL;
}
-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_UNUSED_ARG(addr);
- SLJIT_UNUSED_ARG(new_addr);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNUSED_ARG(new_target);
+ SLJIT_UNUSED_ARG(executable_offset);
+ SLJIT_UNREACHABLE();
}
-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_UNUSED_ARG(addr);
SLJIT_UNUSED_ARG(new_constant);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNUSED_ARG(executable_offset);
+ SLJIT_UNREACHABLE();
}
#endif
/*
* 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:
#define SLJIT_ERR_UNSUPPORTED 4
/* An ivalid argument is passed to any SLJIT function. */
#define SLJIT_ERR_BAD_ARGUMENT 5
+/* Dynamic code modification is not enabled. */
+#define SLJIT_ERR_DYN_CODE_MOD 6
/* --------------------------------------------------------------------- */
/* Registers */
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
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. */
/* Floating point registers */
/* --------------------------------------------------------------------- */
-/* Each floating point register can store a double or single precision
+/* Each floating point register can store a 32 or a 64 bit precision
value. The FR and FS register sets are overlap in the same way as R
and S register sets. See above. */
struct sljit_memory_fragment *next;
sljit_uw used_size;
/* Must be aligned to sljit_sw. */
- sljit_ub memory[1];
+ sljit_u8 memory[1];
};
struct sljit_label {
};
struct sljit_compiler {
- sljit_si error;
- sljit_si options;
+ sljit_s32 error;
+ sljit_s32 options;
struct sljit_label *labels;
struct sljit_jump *jumps;
struct sljit_memory_fragment *abuf;
/* Used scratch registers. */
- sljit_si scratches;
+ sljit_s32 scratches;
/* Used saved registers. */
- sljit_si saveds;
+ sljit_s32 saveds;
/* Used float scratch registers. */
- sljit_si fscratches;
+ sljit_s32 fscratches;
/* Used float saved registers. */
- sljit_si fsaveds;
+ sljit_s32 fsaveds;
/* Local stack size. */
- sljit_si local_size;
+ 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_si args;
+ sljit_s32 args;
+ sljit_s32 locals_offset;
+ sljit_s32 saveds_offset;
#endif
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- sljit_si mode32;
+ sljit_s32 mode32;
+#ifdef _WIN64
+ sljit_s32 locals_offset;
#endif
-
-#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
- sljit_si flags_saved;
#endif
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
/* Constant pool handling. */
sljit_uw *cpool;
- sljit_ub *cpool_unique;
+ sljit_u8 *cpool_unique;
sljit_uw cpool_diff;
sljit_uw cpool_fill;
/* Other members. */
#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_si cache_arg;
- sljit_sw cache_argw;
-#endif
-
-#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
- sljit_si cache_arg;
- sljit_sw cache_argw;
#endif
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
- sljit_si cache_arg;
+ sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif
#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
sljit_sw imm;
- sljit_si cache_arg;
+ sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif
#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
- sljit_si delay_slot;
- sljit_si cache_arg;
+ sljit_s32 delay_slot;
+ sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- sljit_si delay_slot;
- sljit_si cache_arg;
+ sljit_s32 delay_slot;
+ sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif
#if (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
- sljit_si cache_arg;
+ sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif
#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_si logical_local_size;
+ sljit_s32 logical_local_size;
#endif
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG) \
|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
- sljit_si skip_checks;
+ /* Trust arguments when the API function is called. */
+ sljit_s32 skip_checks;
#endif
};
error code. Thus there is no need for checking the error after every
call, it is enough to do it before the code is compiled. Removing
these checks increases the performance of the compiling process. */
-static SLJIT_INLINE sljit_si sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; }
+static SLJIT_INLINE sljit_s32 sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; }
/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED except
if an error was detected before. After the error code is set
indicate that there is no more memory (does not set the current error code
of the compiler to out-of-memory status).
*/
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_si size);
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size);
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
/* Passing NULL disables verbose. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose);
#endif
+/*
+ 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.
+*/
+
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler);
+
+/* Free executable code. */
+
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. */
*/
/* 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
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size);
/* The machine code has a context (which contains the local stack space size,
number of used registers, etc.) which initialized by sljit_emit_enter. Several
Note: every call of sljit_emit_enter and sljit_set_context overwrites
the previous context. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size);
/* Return from machine code. The op argument can be SLJIT_UNUSED which means the
function does not return with anything or any opcode between SLJIT_MOV and
is SLJIT_UNUSED, otherwise see below the description about source and
destination arguments. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src, sljit_sw srcw);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src, sljit_sw srcw);
/* Fast calling mechanism for utility functions (see SLJIT_FAST_CALL). All registers and
even the stack frame is passed to the callee. The return address is preserved in
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. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw);
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw);
/*
Source and destination values for arithmetical instructions
#define SLJIT_MEM2(r1, r2) (SLJIT_MEM | (r1) | ((r2) << 8))
#define SLJIT_IMM 0x40
-/* Set 32 bit operation mode (I) on 64 bit CPUs. The flag is totally ignored on
- 32 bit CPUs. If this flag is set for an arithmetic operation, it uses only the
- lower 32 bit of the input register(s), and set the CPU status flags according
- to the 32 bit result. The higher 32 bits are undefined for both the input and
- output. However, the CPU might not ignore those higher 32 bits, like MIPS, which
- expects it to be the sign extension of the lower 32 bit. All 32 bit operations
- are undefined, if this condition is not fulfilled. Therefore, when SLJIT_INT_OP
- is specified, all register arguments must be the result of other operations with
- the same SLJIT_INT_OP flag. In other words, although a register can hold either
- a 64 or 32 bit value, these values cannot be mixed. The only exceptions are
- SLJIT_IMOV and SLJIT_IMOVU (SLJIT_MOV_SI/SLJIT_MOVU_SI with SLJIT_INT_OP flag)
- which can convert any source argument to SLJIT_INT_OP compatible result. This
- conversion might be unnecessary on some CPUs like x86-64, since the upper 32
- bit is always ignored. In this case SLJIT is clever enough to not generate any
- instructions if the source and destination operands are the same registers.
- Affects sljit_emit_op0, sljit_emit_op1 and sljit_emit_op2. */
-#define SLJIT_INT_OP 0x100
-
-/* Single precision mode (SP). This flag is similar to SLJIT_INT_OP, just
- it applies to floating point registers (it is even the same bit). When
- this flag is passed, the CPU performs single precision floating point
- operations. Similar to SLJIT_INT_OP, all register arguments must be the
- result of other floating point operations with this flag. Affects
- sljit_emit_fop1, sljit_emit_fop2 and sljit_emit_fcmp. */
-#define SLJIT_SINGLE_OP 0x100
-
-/* 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. */
-
-/* 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: */
-
-/* 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. */
-
-/* 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
+/* 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
+
+/* 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.
+
+ This option is part of the instruction name, so there is no need to
+ manually set it. E.g:
+
+ SLJIT_MOV_F32 = (SLJIT_MOV_F64 | SLJIT_F32_OP)
+ */
+#define SLJIT_F32_OP SLJIT_I32_OP
+
+/* 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:
+
+ * 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
/* 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)
/* Flags: - (may destroy flags)
Unsigned multiplication of SLJIT_R0 and SLJIT_R1.
Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
-#define SLJIT_LUMUL (SLJIT_OP0_BASE + 2)
+#define SLJIT_LMUL_UW (SLJIT_OP0_BASE + 2)
/* Flags: - (may destroy flags)
Signed multiplication of SLJIT_R0 and SLJIT_R1.
Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
-#define SLJIT_LSMUL (SLJIT_OP0_BASE + 3)
-/* Flags: I - (may destroy flags)
+#define SLJIT_LMUL_SW (SLJIT_OP0_BASE + 3)
+/* 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_UDIVMOD (SLJIT_OP0_BASE + 4)
-#define SLJIT_IUDIVMOD (SLJIT_UDIVMOD | SLJIT_INT_OP)
-/* Flags: I - (may destroy flags)
+#define SLJIT_DIVMOD_UW (SLJIT_OP0_BASE + 4)
+#define SLJIT_DIVMOD_U32 (SLJIT_DIVMOD_UW | SLJIT_I32_OP)
+/* 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.
Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00),
the behaviour is undefined. */
-#define SLJIT_SDIVMOD (SLJIT_OP0_BASE + 5)
-#define SLJIT_ISDIVMOD (SLJIT_SDIVMOD | SLJIT_INT_OP)
-/* Flags: I - (may destroy flags)
+#define SLJIT_DIVMOD_SW (SLJIT_OP0_BASE + 5)
+#define SLJIT_DIVMOD_S32 (SLJIT_DIVMOD_SW | SLJIT_I32_OP)
+/* 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.
- Note: SLJIT_SDIV is single precision divide. */
-#define SLJIT_UDIVI (SLJIT_OP0_BASE + 6)
-#define SLJIT_IUDIVI (SLJIT_UDIVI | SLJIT_INT_OP)
-/* Flags: I - (may destroy flags)
+ 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: - (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.
Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00),
- the behaviour is undefined.
- Note: SLJIT_SDIV is single precision divide. */
-#define SLJIT_SDIVI (SLJIT_OP0_BASE + 7)
-#define SLJIT_ISDIVI (SLJIT_SDIVI | SLJIT_INT_OP)
+ the behaviour is undefined. */
+#define SLJIT_DIV_SW (SLJIT_OP0_BASE + 7)
+#define SLJIT_DIV_S32 (SLJIT_DIV_SW | SLJIT_I32_OP)
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op);
/* 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 */
-
-/* Flags: - (never set any flags) */
+/* The MOV instruction transfer data from source to destination.
+
+ 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) */
-#define SLJIT_MOV_UB (SLJIT_OP1_BASE + 1)
-#define SLJIT_IMOV_UB (SLJIT_MOV_UB | SLJIT_INT_OP)
-/* Flags: I - (never set any flags) */
-#define SLJIT_MOV_SB (SLJIT_OP1_BASE + 2)
-#define SLJIT_IMOV_SB (SLJIT_MOV_SB | SLJIT_INT_OP)
-/* Flags: I - (never set any flags) */
-#define SLJIT_MOV_UH (SLJIT_OP1_BASE + 3)
-#define SLJIT_IMOV_UH (SLJIT_MOV_UH | SLJIT_INT_OP)
-/* Flags: I - (never set any flags) */
-#define SLJIT_MOV_SH (SLJIT_OP1_BASE + 4)
-#define SLJIT_IMOV_SH (SLJIT_MOV_SH | SLJIT_INT_OP)
-/* Flags: I - (never set any flags)
- Note: see SLJIT_INT_OP for further details. */
-#define SLJIT_MOV_UI (SLJIT_OP1_BASE + 5)
-/* No SLJIT_INT_OP form, since it is the same as SLJIT_IMOV. */
-/* Flags: I - (never set any flags)
- Note: see SLJIT_INT_OP for further details. */
-#define SLJIT_MOV_SI (SLJIT_OP1_BASE + 6)
-#define SLJIT_IMOV (SLJIT_MOV_SI | SLJIT_INT_OP)
-/* Flags: - (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: - (does not modify flags) */
+#define SLJIT_MOV_S8 (SLJIT_OP1_BASE + 2)
+#define SLJIT_MOV32_S8 (SLJIT_MOV_S8 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_U16 (SLJIT_OP1_BASE + 3)
+#define SLJIT_MOV32_U16 (SLJIT_MOV_U16 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_S16 (SLJIT_OP1_BASE + 4)
+#define SLJIT_MOV32_S16 (SLJIT_MOV_S16 | SLJIT_I32_OP)
+/* 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: - (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: - (does not modify flags) */
+#define SLJIT_MOV32 (SLJIT_MOV_S32 | SLJIT_I32_OP)
+/* 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) */
-#define SLJIT_MOVU_UB (SLJIT_OP1_BASE + 9)
-#define SLJIT_IMOVU_UB (SLJIT_MOVU_UB | SLJIT_INT_OP)
-/* Flags: I - (never set any flags) */
-#define SLJIT_MOVU_SB (SLJIT_OP1_BASE + 10)
-#define SLJIT_IMOVU_SB (SLJIT_MOVU_SB | SLJIT_INT_OP)
-/* Flags: I - (never set any flags) */
-#define SLJIT_MOVU_UH (SLJIT_OP1_BASE + 11)
-#define SLJIT_IMOVU_UH (SLJIT_MOVU_UH | SLJIT_INT_OP)
-/* Flags: I - (never set any flags) */
-#define SLJIT_MOVU_SH (SLJIT_OP1_BASE + 12)
-#define SLJIT_IMOVU_SH (SLJIT_MOVU_SH | SLJIT_INT_OP)
-/* Flags: I - (never set any flags)
- Note: see SLJIT_INT_OP for further details. */
-#define SLJIT_MOVU_UI (SLJIT_OP1_BASE + 13)
-/* No SLJIT_INT_OP form, since it is the same as SLJIT_IMOVU. */
-/* Flags: I - (never set any flags)
- Note: see SLJIT_INT_OP for further details. */
-#define SLJIT_MOVU_SI (SLJIT_OP1_BASE + 14)
-#define SLJIT_IMOVU (SLJIT_MOVU_SI | SLJIT_INT_OP)
-/* Flags: - (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: - (may destroy flags) */
+#define SLJIT_MOVU_S8 (SLJIT_OP1_BASE + 10)
+#define SLJIT_MOVU32_S8 (SLJIT_MOVU_S8 | SLJIT_I32_OP)
+/* Flags: - (may destroy flags) */
+#define SLJIT_MOVU_U16 (SLJIT_OP1_BASE + 11)
+#define SLJIT_MOVU32_U16 (SLJIT_MOVU_U16 | SLJIT_I32_OP)
+/* Flags: - (may destroy flags) */
+#define SLJIT_MOVU_S16 (SLJIT_OP1_BASE + 12)
+#define SLJIT_MOVU32_S16 (SLJIT_MOVU_S16 | SLJIT_I32_OP)
+/* 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: - (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: - (may destroy flags) */
+#define SLJIT_MOVU32 (SLJIT_MOVU_S32 | SLJIT_I32_OP)
+/* 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_INOT (SLJIT_NOT | SLJIT_INT_OP)
-/* Flags: I | E | O | K */
+#define SLJIT_NOT32 (SLJIT_NOT | SLJIT_I32_OP)
+/* Flags: Z | OVERFLOW */
#define SLJIT_NEG (SLJIT_OP1_BASE + 17)
-#define SLJIT_INEG (SLJIT_NEG | SLJIT_INT_OP)
+#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_ICLZ (SLJIT_CLZ | SLJIT_INT_OP)
+#define SLJIT_CLZ32 (SLJIT_CLZ | SLJIT_I32_OP)
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw);
+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);
/* 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_IADD (SLJIT_ADD | SLJIT_INT_OP)
-/* Flags: I | C | K */
+#define SLJIT_ADD32 (SLJIT_ADD | SLJIT_I32_OP)
+/* Flags: CARRY */
#define SLJIT_ADDC (SLJIT_OP2_BASE + 1)
-#define SLJIT_IADDC (SLJIT_ADDC | SLJIT_INT_OP)
-/* Flags: I | E | U | S | O | C | K */
+#define SLJIT_ADDC32 (SLJIT_ADDC | SLJIT_I32_OP)
+/* 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_ISUB (SLJIT_SUB | SLJIT_INT_OP)
-/* Flags: I | C | K */
+#define SLJIT_SUB32 (SLJIT_SUB | SLJIT_I32_OP)
+/* Flags: CARRY */
#define SLJIT_SUBC (SLJIT_OP2_BASE + 3)
-#define SLJIT_ISUBC (SLJIT_SUBC | SLJIT_INT_OP)
+#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_IMUL (SLJIT_MUL | SLJIT_INT_OP)
-/* Flags: I | E | K */
+#define SLJIT_MUL32 (SLJIT_MUL | SLJIT_I32_OP)
+/* Flags: Z */
#define SLJIT_AND (SLJIT_OP2_BASE + 5)
-#define SLJIT_IAND (SLJIT_AND | SLJIT_INT_OP)
-/* Flags: I | E | K */
+#define SLJIT_AND32 (SLJIT_AND | SLJIT_I32_OP)
+/* Flags: Z */
#define SLJIT_OR (SLJIT_OP2_BASE + 6)
-#define SLJIT_IOR (SLJIT_OR | SLJIT_INT_OP)
-/* Flags: I | E | K */
+#define SLJIT_OR32 (SLJIT_OR | SLJIT_I32_OP)
+/* Flags: Z */
#define SLJIT_XOR (SLJIT_OP2_BASE + 7)
-#define SLJIT_IXOR (SLJIT_XOR | SLJIT_INT_OP)
-/* Flags: I | E | K
+#define SLJIT_XOR32 (SLJIT_XOR | SLJIT_I32_OP)
+/* 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_ISHL (SLJIT_SHL | SLJIT_INT_OP)
-/* Flags: I | E | K
+#define SLJIT_SHL32 (SLJIT_SHL | SLJIT_I32_OP)
+/* 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_ILSHR (SLJIT_LSHR | SLJIT_INT_OP)
-/* Flags: I | E | K
+#define SLJIT_LSHR32 (SLJIT_LSHR | SLJIT_I32_OP)
+/* 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_ASHR (SLJIT_OP2_BASE + 10)
-#define SLJIT_IASHR (SLJIT_ASHR | SLJIT_INT_OP)
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+#define SLJIT_ASHR32 (SLJIT_ASHR | SLJIT_I32_OP)
-/* Returns with non-zero if fpu is available. */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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);
/* Starting index of opcodes for sljit_emit_fop1. */
#define SLJIT_FOP1_BASE 128
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DMOV (SLJIT_FOP1_BASE + 0)
-#define SLJIT_SMOV (SLJIT_DMOV | SLJIT_SINGLE_OP)
+/* 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) */
-#define SLJIT_CONVD_FROMS (SLJIT_FOP1_BASE + 1)
-#define SLJIT_CONVS_FROMD (SLJIT_CONVD_FROMS | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_CONVW_FROMD (SLJIT_FOP1_BASE + 2)
-#define SLJIT_CONVW_FROMS (SLJIT_CONVW_FROMD | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_CONVI_FROMD (SLJIT_FOP1_BASE + 3)
-#define SLJIT_CONVI_FROMS (SLJIT_CONVI_FROMD | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_CONVD_FROMW (SLJIT_FOP1_BASE + 4)
-#define SLJIT_CONVS_FROMW (SLJIT_CONVD_FROMW | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_CONVD_FROMI (SLJIT_FOP1_BASE + 5)
-#define SLJIT_CONVS_FROMI (SLJIT_CONVD_FROMI | SLJIT_SINGLE_OP)
+/* 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: - (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: - (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: - (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: - (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_*) */
-#define SLJIT_DCMP (SLJIT_FOP1_BASE + 6)
-#define SLJIT_SCMP (SLJIT_DCMP | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DNEG (SLJIT_FOP1_BASE + 7)
-#define SLJIT_SNEG (SLJIT_DNEG | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DABS (SLJIT_FOP1_BASE + 8)
-#define SLJIT_SABS (SLJIT_DABS | SLJIT_SINGLE_OP)
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw);
+ 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: - (does not modify flags) */
+#define SLJIT_NEG_F64 (SLJIT_FOP1_BASE + 7)
+#define SLJIT_NEG_F32 (SLJIT_NEG_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_ABS_F64 (SLJIT_FOP1_BASE + 8)
+#define SLJIT_ABS_F32 (SLJIT_ABS_F64 | SLJIT_F32_OP)
+
+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);
/* Starting index of opcodes for sljit_emit_fop2. */
#define SLJIT_FOP2_BASE 160
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DADD (SLJIT_FOP2_BASE + 0)
-#define SLJIT_SADD (SLJIT_DADD | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DSUB (SLJIT_FOP2_BASE + 1)
-#define SLJIT_SSUB (SLJIT_DSUB | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DMUL (SLJIT_FOP2_BASE + 2)
-#define SLJIT_SMUL (SLJIT_DMUL | SLJIT_SINGLE_OP)
-/* Flags: SP - (never set any flags) */
-#define SLJIT_DDIV (SLJIT_FOP2_BASE + 3)
-#define SLJIT_SDIV (SLJIT_DDIV | SLJIT_SINGLE_OP)
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+/* Flags: - (does not modify flags) */
+#define SLJIT_ADD_F64 (SLJIT_FOP2_BASE + 0)
+#define SLJIT_ADD_F32 (SLJIT_ADD_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_SUB_F64 (SLJIT_FOP2_BASE + 1)
+#define SLJIT_SUB_F32 (SLJIT_SUB_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MUL_F64 (SLJIT_FOP2_BASE + 2)
+#define SLJIT_MUL_F32 (SLJIT_MUL_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_DIV_F64 (SLJIT_FOP2_BASE + 3)
+#define SLJIT_DIV_F32 (SLJIT_DIV_F64 | SLJIT_F32_OP)
+
+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);
/* Label and jump instructions. */
/* Integer comparison types. */
#define SLJIT_EQUAL 0
-#define SLJIT_I_EQUAL (SLJIT_EQUAL | SLJIT_INT_OP)
+#define SLJIT_EQUAL32 (SLJIT_EQUAL | SLJIT_I32_OP)
#define SLJIT_ZERO 0
-#define SLJIT_I_ZERO (SLJIT_ZERO | SLJIT_INT_OP)
+#define SLJIT_ZERO32 (SLJIT_ZERO | SLJIT_I32_OP)
#define SLJIT_NOT_EQUAL 1
-#define SLJIT_I_NOT_EQUAL (SLJIT_NOT_EQUAL | SLJIT_INT_OP)
+#define SLJIT_NOT_EQUAL32 (SLJIT_NOT_EQUAL | SLJIT_I32_OP)
#define SLJIT_NOT_ZERO 1
-#define SLJIT_I_NOT_ZERO (SLJIT_NOT_ZERO | SLJIT_INT_OP)
+#define SLJIT_NOT_ZERO32 (SLJIT_NOT_ZERO | SLJIT_I32_OP)
#define SLJIT_LESS 2
-#define SLJIT_I_LESS (SLJIT_LESS | SLJIT_INT_OP)
+#define SLJIT_LESS32 (SLJIT_LESS | SLJIT_I32_OP)
+#define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS)
#define SLJIT_GREATER_EQUAL 3
-#define SLJIT_I_GREATER_EQUAL (SLJIT_GREATER_EQUAL | SLJIT_INT_OP)
+#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_I_GREATER (SLJIT_GREATER | SLJIT_INT_OP)
+#define SLJIT_GREATER32 (SLJIT_GREATER | SLJIT_I32_OP)
+#define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER)
#define SLJIT_LESS_EQUAL 5
-#define SLJIT_I_LESS_EQUAL (SLJIT_LESS_EQUAL | SLJIT_INT_OP)
+#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_I_SIG_LESS (SLJIT_SIG_LESS | SLJIT_INT_OP)
+#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_I_SIG_GREATER_EQUAL (SLJIT_SIG_GREATER_EQUAL | SLJIT_INT_OP)
+#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_I_SIG_GREATER (SLJIT_SIG_GREATER | SLJIT_INT_OP)
+#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_I_SIG_LESS_EQUAL (SLJIT_SIG_LESS_EQUAL | SLJIT_INT_OP)
+#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_I_OVERFLOW (SLJIT_OVERFLOW | SLJIT_INT_OP)
+#define SLJIT_OVERFLOW32 (SLJIT_OVERFLOW | SLJIT_I32_OP)
+#define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW)
#define SLJIT_NOT_OVERFLOW 11
-#define SLJIT_I_NOT_OVERFLOW (SLJIT_NOT_OVERFLOW | SLJIT_INT_OP)
+#define SLJIT_NOT_OVERFLOW32 (SLJIT_NOT_OVERFLOW | SLJIT_I32_OP)
#define SLJIT_MUL_OVERFLOW 12
-#define SLJIT_I_MUL_OVERFLOW (SLJIT_MUL_OVERFLOW | SLJIT_INT_OP)
+#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_I_MUL_NOT_OVERFLOW (SLJIT_MUL_NOT_OVERFLOW | SLJIT_INT_OP)
+#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_D_EQUAL 14
-#define SLJIT_S_EQUAL (SLJIT_D_EQUAL | SLJIT_SINGLE_OP)
-#define SLJIT_D_NOT_EQUAL 15
-#define SLJIT_S_NOT_EQUAL (SLJIT_D_NOT_EQUAL | SLJIT_SINGLE_OP)
-#define SLJIT_D_LESS 16
-#define SLJIT_S_LESS (SLJIT_D_LESS | SLJIT_SINGLE_OP)
-#define SLJIT_D_GREATER_EQUAL 17
-#define SLJIT_S_GREATER_EQUAL (SLJIT_D_GREATER_EQUAL | SLJIT_SINGLE_OP)
-#define SLJIT_D_GREATER 18
-#define SLJIT_S_GREATER (SLJIT_D_GREATER | SLJIT_SINGLE_OP)
-#define SLJIT_D_LESS_EQUAL 19
-#define SLJIT_S_LESS_EQUAL (SLJIT_D_LESS_EQUAL | SLJIT_SINGLE_OP)
-#define SLJIT_D_UNORDERED 20
-#define SLJIT_S_UNORDERED (SLJIT_D_UNORDERED | SLJIT_SINGLE_OP)
-#define SLJIT_D_ORDERED 21
-#define SLJIT_S_ORDERED (SLJIT_D_ORDERED | SLJIT_SINGLE_OP)
+#define SLJIT_EQUAL_F64 16
+#define SLJIT_EQUAL_F32 (SLJIT_EQUAL_F64 | SLJIT_F32_OP)
+#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_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_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_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_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_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_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. */
/* 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. */
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type);
+
+ 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
an SLJIT_SUB operation (with SLJIT_UNUSED destination and setting
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. */
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+ 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);
/* Basic floating point comparison. In most architectures it is implemented as
an SLJIT_FCMP operation (setting appropriate flags) followed by a
sljit_emit_jump. However some architectures (i.e: MIPS) may employ
special optimizations here. It is suggested to use this comparison form
when appropriate.
- type must be between SLJIT_D_EQUAL and SLJIT_S_ORDERED
+ type must be between SLJIT_EQUAL_F64 and SLJIT_ORDERED_F32
type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
Flags: destroy flags.
Note: if either operand is NaN, the behaviour is undefined for
types up to SLJIT_S_LESS_EQUAL. */
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+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);
/* Set the destination of the jump to this label. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label);
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. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw);
+
+ 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_SI, SLJIT_MOV_UI:
+ 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). */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type);
+ 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 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) */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset);
+ 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) */
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value);
+ 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
are computed. Since these structures are freed by sljit_free_compiler, the
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
it is useful to know the type of the code generator. */
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void);
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void);
/* Portable helper function to get an offset of a member. */
#define SLJIT_OFFSETOF(base, member) ((sljit_sw)(&((base*)0x10)->member) - 0x10)
#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. */
-
-/* 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.
+/* 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.
+
+ 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. */
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);
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) */
#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 */
/* --------------------------------------------------------------------- */
Note: it returns with -1 for virtual registers (only on x86-32). */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg);
/* The following function is a helper function for sljit_emit_op_custom.
It returns with the real machine register index of any SLJIT_FLOAT register.
Note: the index is always an even number on ARM (except ARM-64), MIPS, and SPARC. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg);
/* Any instruction can be inserted into the instruction stream by
sljit_emit_op_custom. It has a similar purpose as inline assembly.
if size == 4, the instruction argument must be 4 byte aligned.
Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size);
-
-#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size);
-/* Returns with non-zero if sse2 is available. */
+/* Define the currently available CPU status flags. It is usually used after an
+ sljit_emit_op_custom call to define which flags are set. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_sse2_available(void);
-
-/* Returns with non-zero if cmov instruction is available. */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si 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_INT_OP to perform 32 bit arithmetic
- Flags: I - (never set any flags)
- */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_emit_cmov(struct sljit_compiler *compiler,
- sljit_si type,
- sljit_si dst_reg,
- sljit_si 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_ */
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
return "ARMv7" SLJIT_CPUINFO;
/* Last register + 1. */
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
-#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
-#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 5)
+#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 4)
#define TMP_FREG1 (0)
#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
#define ALIGN_INSTRUCTION(ptr) \
(sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1))
#define MAX_DIFFERENCE(max_diff) \
- (((max_diff) / (sljit_si)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1))
+ (((max_diff) / (sljit_s32)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1))
/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
- 0, 0, 1, 2, 11, 10, 9, 8, 7, 6, 5, 4, 13, 3, 12, 14, 15
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+ 0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 14, 12, 15
};
#define RM(rm) (reg_map[rm])
#define BLX 0xe12fff30
#define BX 0xe12fff10
#define CLZ 0xe16f0f10
+#define CMN_DP 0xb
#define CMP_DP 0xa
#define BKPT 0xe1200070
#define EOR_DP 0x1
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
-static sljit_si push_cpool(struct sljit_compiler *compiler)
+static sljit_s32 push_cpool(struct sljit_compiler *compiler)
{
/* Pushing the constant pool into the instruction stream. */
sljit_uw* inst;
sljit_uw* cpool_ptr;
sljit_uw* cpool_end;
- sljit_si i;
+ sljit_s32 i;
/* The label could point the address after the constant pool. */
if (compiler->last_label && compiler->last_label->size == compiler->size)
return SLJIT_SUCCESS;
}
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_uw inst)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst)
{
sljit_uw* ptr;
return SLJIT_SUCCESS;
}
-static sljit_si push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
+static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
{
sljit_uw* ptr;
sljit_uw cpool_index = CPOOL_SIZE;
sljit_uw* cpool_ptr;
sljit_uw* cpool_end;
- sljit_ub* cpool_unique_ptr;
+ sljit_u8* cpool_unique_ptr;
if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))
FAIL_IF(push_cpool(compiler));
return SLJIT_SUCCESS;
}
-static sljit_si push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
+static sljit_s32 push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
{
sljit_uw* ptr;
if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE))
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si prepare_blx(struct sljit_compiler *compiler)
+static SLJIT_INLINE sljit_s32 prepare_blx(struct sljit_compiler *compiler)
{
/* Place for at least two instruction (doesn't matter whether the first has a literal). */
if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4088)))
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_blx(struct sljit_compiler *compiler)
+static SLJIT_INLINE sljit_s32 emit_blx(struct sljit_compiler *compiler)
{
/* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */
SLJIT_ASSERT(compiler->cpool_diff == CONST_POOL_EMPTY || compiler->size - compiler->cpool_diff < MAX_DIFFERENCE(4092));
- return push_inst(compiler, BLX | RM(TMP_REG1));
+ return push_inst(compiler, BLX | RM(TMP_REG2));
}
static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ptr, sljit_uw* const_pool, sljit_uw cpool_size)
/* Must be a load instruction with immediate offset. */
SLJIT_ASSERT(ind < cpool_size && !(*last_pc_patch & (1 << 25)) && (*last_pc_patch & (1 << 20)));
- if ((sljit_si)const_pool[ind] < 0) {
+ if ((sljit_s32)const_pool[ind] < 0) {
const_pool[ind] = counter;
ind = counter;
counter++;
/* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */
struct future_patch {
struct future_patch* next;
- sljit_si index;
- sljit_si value;
+ sljit_s32 index;
+ sljit_s32 value;
};
-static sljit_si resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)
+static sljit_s32 resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)
{
- sljit_si value;
+ sljit_s32 value;
struct future_patch *curr_patch, *prev_patch;
SLJIT_UNUSED_ARG(compiler);
/* Using the values generated by patch_pc_relative_loads. */
if (!*first_patch)
- value = (sljit_si)cpool_start_address[cpool_current_index];
+ value = (sljit_s32)cpool_start_address[cpool_current_index];
else {
curr_patch = *first_patch;
- prev_patch = 0;
+ prev_patch = NULL;
while (1) {
if (!curr_patch) {
- value = (sljit_si)cpool_start_address[cpool_current_index];
+ value = (sljit_s32)cpool_start_address[cpool_current_index];
break;
}
if ((sljit_uw)curr_patch->index == cpool_current_index) {
#else
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_uw inst)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst)
{
sljit_uw* ptr;
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_imm(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
+static SLJIT_INLINE sljit_s32 emit_imm(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
{
FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));
return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));
#endif
-static SLJIT_INLINE sljit_si detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code)
+static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code, sljit_sw executable_offset)
{
sljit_sw diff;
code_ptr--;
if (jump->flags & JUMP_ADDR)
- diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2));
+ diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset);
else {
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2));
}
#else
if (jump->flags & JUMP_ADDR)
- diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr);
+ diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr - executable_offset);
else {
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)code_ptr);
return 0;
}
-static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, sljit_si flush)
+static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache)
{
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- sljit_uw *ptr = (sljit_uw*)addr;
- sljit_uw *inst = (sljit_uw*)ptr[0];
+ sljit_uw *ptr = (sljit_uw *)jump_ptr;
+ sljit_uw *inst = (sljit_uw *)ptr[0];
sljit_uw mov_pc = ptr[1];
- sljit_si bl = (mov_pc & 0x0000f000) != RD(TMP_PC);
- sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2)) >> 2);
+ sljit_s32 bl = (mov_pc & 0x0000f000) != RD(TMP_PC);
+ sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2) - executable_offset) >> 2);
if (diff <= 0x7fffff && diff >= -0x800000) {
/* Turn to branch. */
if (!bl) {
inst[0] = (mov_pc & COND_MASK) | (B - CONDITIONAL) | (diff & 0xffffff);
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
} else {
inst[0] = (mov_pc & COND_MASK) | (BL - CONDITIONAL) | (diff & 0xffffff);
inst[1] = NOP;
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
}
if (*inst != mov_pc) {
inst[0] = mov_pc;
if (!bl) {
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
} else {
inst[1] = BLX | RM(TMP_REG1);
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
}
*ptr = new_addr;
}
#else
- sljit_uw *inst = (sljit_uw*)addr;
+ sljit_uw *inst = (sljit_uw*)jump_ptr;
SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);
inst[0] = MOVW | (inst[0] & 0xf000) | ((new_addr << 4) & 0xf0000) | (new_addr & 0xfff);
inst[1] = MOVT | (inst[1] & 0xf000) | ((new_addr >> 12) & 0xf0000) | ((new_addr >> 16) & 0xfff);
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
#endif
static sljit_uw get_imm(sljit_uw imm);
-static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw new_constant, sljit_si flush)
+static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_offset, sljit_sw new_constant, sljit_s32 flush_cache)
{
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
sljit_uw *ptr = (sljit_uw*)addr;
src2 = get_imm(new_constant);
if (src2) {
*inst = 0xe3a00000 | (ldr_literal & 0xf000) | src2;
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
return;
src2 = get_imm(~new_constant);
if (src2) {
*inst = 0xe3e00000 | (ldr_literal & 0xf000) | src2;
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
return;
if (*inst != ldr_literal) {
*inst = ldr_literal;
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
}
SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);
inst[0] = MOVW | (inst[0] & 0xf000) | ((new_constant << 4) & 0xf0000) | (new_constant & 0xfff);
inst[1] = MOVT | (inst[1] & 0xf000) | ((new_constant >> 12) & 0xf0000) | ((new_constant >> 16) & 0xfff);
- if (flush) {
+ if (flush_cache) {
+ inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
#endif
sljit_uw *buf_end;
sljit_uw size;
sljit_uw word_count;
+ sljit_sw executable_offset;
+ sljit_sw jump_addr;
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
sljit_uw cpool_size;
sljit_uw cpool_skip_alignment;
code_ptr = code;
word_count = 0;
+ executable_offset = SLJIT_EXEC_OFFSET(code);
label = compiler->labels;
jump = compiler->jumps;
const_ = compiler->consts;
if (label && label->size == 0) {
- label->addr = (sljit_uw)code;
- label->size = 0;
+ label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
label = label->next;
}
cpool_size = 0;
if (label && label->size == word_count) {
/* Points after the current instruction. */
- 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;
}
SLJIT_ASSERT(!const_ || const_->addr >= word_count);
if (jump && jump->addr == word_count) {
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- if (detect_jump_type(jump, code_ptr, code))
+ if (detect_jump_type(jump, code_ptr, code, executable_offset))
code_ptr--;
jump->addr = (sljit_uw)code_ptr;
#else
jump->addr = (sljit_uw)(code_ptr - 2);
- if (detect_jump_type(jump, code_ptr, code))
+ if (detect_jump_type(jump, code_ptr, code, executable_offset))
code_ptr -= 2;
#endif
jump = jump->next;
}
if (label && label->size == word_count) {
/* code_ptr can be affected above. */
- label->addr = (sljit_uw)(code_ptr + 1);
+ label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr + 1, executable_offset);
label->size = (code_ptr + 1) - code;
label = label->next;
}
jump = compiler->jumps;
while (jump) {
- buf_ptr = (sljit_uw*)jump->addr;
+ buf_ptr = (sljit_uw *)jump->addr;
if (jump->flags & PATCH_B) {
+ jump_addr = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset);
if (!(jump->flags & JUMP_ADDR)) {
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
- SLJIT_ASSERT(((sljit_sw)jump->u.label->addr - (sljit_sw)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_sw)jump->u.label->addr - (sljit_sw)(buf_ptr + 2)) >= -0x02000000);
- *buf_ptr |= (((sljit_sw)jump->u.label->addr - (sljit_sw)(buf_ptr + 2)) >> 2) & 0x00ffffff;
+ SLJIT_ASSERT(((sljit_sw)jump->u.label->addr - jump_addr) <= 0x01ffffff && ((sljit_sw)jump->u.label->addr - jump_addr) >= -0x02000000);
+ *buf_ptr |= (((sljit_sw)jump->u.label->addr - jump_addr) >> 2) & 0x00ffffff;
}
else {
- SLJIT_ASSERT(((sljit_sw)jump->u.target - (sljit_sw)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_sw)jump->u.target - (sljit_sw)(buf_ptr + 2)) >= -0x02000000);
- *buf_ptr |= (((sljit_sw)jump->u.target - (sljit_sw)(buf_ptr + 2)) >> 2) & 0x00ffffff;
+ SLJIT_ASSERT(((sljit_sw)jump->u.target - jump_addr) <= 0x01ffffff && ((sljit_sw)jump->u.target - jump_addr) >= -0x02000000);
+ *buf_ptr |= (((sljit_sw)jump->u.target - jump_addr) >> 2) & 0x00ffffff;
}
}
else if (jump->flags & SLJIT_REWRITABLE_JUMP) {
jump->addr = (sljit_uw)code_ptr;
code_ptr[0] = (sljit_uw)buf_ptr;
code_ptr[1] = *buf_ptr;
- inline_set_jump_addr((sljit_uw)code_ptr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+ inline_set_jump_addr((sljit_uw)code_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
code_ptr += 2;
#else
- inline_set_jump_addr((sljit_uw)buf_ptr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+ inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
#endif
}
else {
buf_ptr += 1;
*buf_ptr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
#else
- inline_set_jump_addr((sljit_uw)buf_ptr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+ inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
#endif
}
jump = jump->next;
else
buf_ptr += 1;
/* Set the value again (can be a simple constant). */
- inline_set_const((sljit_uw)code_ptr, *buf_ptr, 0);
+ inline_set_const((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
code_ptr += 2;
const_ = const_->next;
}
#endif
- SLJIT_ASSERT(code_ptr - code <= (sljit_si)size);
+ SLJIT_ASSERT(code_ptr - code <= (sljit_s32)size);
compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
compiler->executable_size = (code_ptr - code) * sizeof(sljit_uw);
+
+ code = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+ code_ptr = (sljit_uw *)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;
+ }
+}
+
/* --------------------------------------------------------------------- */
/* Entry, exit */
/* --------------------------------------------------------------------- */
+/* Creates an index in data_transfer_insts array. */
+#define WORD_DATA 0x00
+#define BYTE_DATA 0x01
+#define HALF_DATA 0x02
+#define PRELOAD_DATA 0x03
+#define SIGNED_DATA 0x04
+#define LOAD_DATA 0x08
+
/* emit_op inp_flags.
WRITE_BACK must be the first, since it is a flag. */
-#define WRITE_BACK 0x01
-#define ALLOW_IMM 0x02
-#define ALLOW_INV_IMM 0x04
+#define WRITE_BACK 0x10
+#define ALLOW_IMM 0x20
+#define ALLOW_INV_IMM 0x40
#define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM)
-#define ARG_TEST 0x08
-/* Creates an index in data_transfer_insts array. */
-#define WORD_DATA 0x00
-#define BYTE_DATA 0x10
-#define HALF_DATA 0x20
-#define SIGNED_DATA 0x40
-#define LOAD_DATA 0x80
+/* s/l - store/load (1 bit)
+ u/s - signed/unsigned (1 bit)
+ w/b/h/N - word/byte/half/NOT allowed (2 bit)
+ Storing signed and unsigned values are the same operations. */
+
+static const sljit_uw data_transfer_insts[16] = {
+/* s u w */ 0xe5000000 /* str */,
+/* s u b */ 0xe5400000 /* strb */,
+/* s u h */ 0xe10000b0 /* strh */,
+/* s u N */ 0x00000000 /* not allowed */,
+/* s s w */ 0xe5000000 /* str */,
+/* s s b */ 0xe5400000 /* strb */,
+/* s s h */ 0xe10000b0 /* strh */,
+/* s s N */ 0x00000000 /* not allowed */,
+
+/* l u w */ 0xe5100000 /* ldr */,
+/* l u b */ 0xe5500000 /* ldrb */,
+/* l u h */ 0xe11000b0 /* ldrh */,
+/* l u p */ 0xf5500000 /* preload data */,
+/* l s w */ 0xe5100000 /* ldr */,
+/* l s b */ 0xe11000d0 /* ldrsb */,
+/* l s h */ 0xe11000f0 /* ldrsh */,
+/* l s N */ 0x00000000 /* not allowed */,
+};
+
+#define EMIT_DATA_TRANSFER(type, add, wb, target_reg, base_reg, arg) \
+ (data_transfer_insts[(type) & 0xf] | ((add) << 23) | ((wb) << (21 - 4)) | RD(target_reg) | RN(base_reg) | (arg))
+
+/* Normal ldr/str instruction.
+ Type2: ldrsb, ldrh, ldrsh */
+#define IS_TYPE1_TRANSFER(type) \
+ (data_transfer_insts[(type) & 0xf] & 0x04000000)
+#define TYPE2_TRANSFER_IMM(imm) \
+ (((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))
/* Condition: AL. */
#define EMIT_DATA_PROCESS_INS(opcode, set_flags, dst, src1, src2) \
(0xe0000000 | ((opcode) << 21) | (set_flags) | RD(dst) | RN(src1) | (src2))
-static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si inp_flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w);
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si size, i, tmp;
+ sljit_s32 size, i, tmp;
sljit_uw push;
CHECK_ERROR();
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si size;
+ sljit_s32 size;
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si i, tmp;
+ sljit_s32 i, tmp;
sljit_uw pop;
CHECK_ERROR();
/* Operators */
/* --------------------------------------------------------------------- */
-/* s/l - store/load (1 bit)
- u/s - signed/unsigned (1 bit)
- w/b/h/N - word/byte/half/NOT allowed (2 bit)
- It contans 16 items, but not all are different. */
-
-static sljit_sw data_transfer_insts[16] = {
-/* s u w */ 0xe5000000 /* str */,
-/* s u b */ 0xe5400000 /* strb */,
-/* s u h */ 0xe10000b0 /* strh */,
-/* s u N */ 0x00000000 /* not allowed */,
-/* s s w */ 0xe5000000 /* str */,
-/* s s b */ 0xe5400000 /* strb */,
-/* s s h */ 0xe10000b0 /* strh */,
-/* s s N */ 0x00000000 /* not allowed */,
-
-/* l u w */ 0xe5100000 /* ldr */,
-/* l u b */ 0xe5500000 /* ldrb */,
-/* l u h */ 0xe11000b0 /* ldrh */,
-/* l u N */ 0x00000000 /* not allowed */,
-/* l s w */ 0xe5100000 /* ldr */,
-/* l s b */ 0xe11000d0 /* ldrsb */,
-/* l s h */ 0xe11000f0 /* ldrsh */,
-/* l s N */ 0x00000000 /* not allowed */,
-};
-
-#define EMIT_DATA_TRANSFER(type, add, wb, target, base1, base2) \
- (data_transfer_insts[(type) >> 4] | ((add) << 23) | ((wb) << 21) | (reg_map[target] << 12) | (reg_map[base1] << 16) | (base2))
-/* Normal ldr/str instruction.
- Type2: ldrsb, ldrh, ldrsh */
-#define IS_TYPE1_TRANSFER(type) \
- (data_transfer_insts[(type) >> 4] & 0x04000000)
-#define TYPE2_TRANSFER_IMM(imm) \
- (((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))
-
/* flags: */
/* Arguments are swapped. */
#define ARGS_SWAPPED 0x01
/* Inverted immediate. */
#define INV_IMM 0x02
/* Source and destination is register. */
-#define REG_DEST 0x04
-#define REG_SOURCE 0x08
- /* One instruction is enough. */
-#define FAST_DEST 0x10
- /* Multiple instructions are required. */
-#define SLOW_DEST 0x20
+#define MOVE_REG_CONV 0x04
+ /* Unused return value. */
+#define UNUSED_RETURN 0x08
/* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */
#define SET_FLAGS (1 << 20)
/* dst: reg
SRC2_IMM must be (1 << 25) as it is also the value of I bit (can be used for optimization). */
#define SRC2_IMM (1 << 25)
-#define EMIT_DATA_PROCESS_INS_AND_RETURN(opcode) \
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(opcode, flags & SET_FLAGS, dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)))
-
-#define EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(opcode, dst, src1, src2) \
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(opcode, flags & SET_FLAGS, dst, src1, src2))
-
#define EMIT_SHIFT_INS_AND_RETURN(opcode) \
SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); \
if (compiler->shift_imm != 0x20) { \
SLJIT_ASSERT(src1 == TMP_REG1); \
SLJIT_ASSERT(!(flags & ARGS_SWAPPED)); \
+ \
if (compiler->shift_imm != 0) \
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (compiler->shift_imm << 7) | (opcode << 5) | reg_map[src2])); \
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, reg_map[src2])); \
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, \
+ dst, SLJIT_UNUSED, (compiler->shift_imm << 7) | (opcode << 5) | RM(src2))); \
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, RM(src2))); \
} \
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (reg_map[(flags & ARGS_SWAPPED) ? src1 : src2] << 8) | (opcode << 5) | 0x10 | ((flags & ARGS_SWAPPED) ? reg_map[src2] : reg_map[src1])));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, \
+ dst, SLJIT_UNUSED, (reg_map[(flags & ARGS_SWAPPED) ? src1 : src2] << 8) | (opcode << 5) | 0x10 | RM((flags & ARGS_SWAPPED) ? src2 : src1)));
-static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_si src1, sljit_si src2)
+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_s32 src2)
{
- sljit_sw mul_inst;
-
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
if (dst != src2) {
if (src2 & SRC2_IMM) {
- if (flags & INV_IMM)
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS((flags & INV_IMM) ? MVN_DP : MOV_DP, 0,
+ dst, SLJIT_UNUSED, src2));
}
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, reg_map[src2]);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, RM(src2)));
}
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
- if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) {
+ if (flags & MOVE_REG_CONV) {
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- if (op == SLJIT_MOV_UB)
+ if (op == SLJIT_MOV_U8)
return push_inst(compiler, EMIT_DATA_PROCESS_INS(AND_DP, 0, dst, src2, SRC2_IMM | 0xff));
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | reg_map[src2])));
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | (op == SLJIT_MOV_UB ? 0x20 : 0x40) | reg_map[dst]));
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | RM(src2))));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | (op == SLJIT_MOV_U8 ? 0x20 : 0x40) | RM(dst)));
#else
- return push_inst(compiler, (op == SLJIT_MOV_UB ? UXTB : SXTB) | RD(dst) | RM(src2));
+ return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2));
#endif
}
else if (dst != src2) {
SLJIT_ASSERT(src2 & SRC2_IMM);
- if (flags & INV_IMM)
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS((flags & INV_IMM) ? MVN_DP : MOV_DP, 0,
+ dst, SLJIT_UNUSED, src2));
}
return SLJIT_SUCCESS;
- case SLJIT_MOV_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
- if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) {
+ if (flags & MOVE_REG_CONV) {
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | reg_map[src2])));
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | (op == SLJIT_MOV_UH ? 0x20 : 0x40) | reg_map[dst]));
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | RM(src2))));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | (op == SLJIT_MOV_U16 ? 0x20 : 0x40) | RM(dst)));
#else
- return push_inst(compiler, (op == SLJIT_MOV_UH ? UXTH : SXTH) | RD(dst) | RM(src2));
+ return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2));
#endif
}
else if (dst != src2) {
SLJIT_ASSERT(src2 & SRC2_IMM);
- if (flags & INV_IMM)
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS((flags & INV_IMM) ? MVN_DP : MOV_DP, 0,
+ dst, SLJIT_UNUSED, src2));
}
return SLJIT_SUCCESS;
case SLJIT_NOT:
if (src2 & SRC2_IMM) {
- if (flags & INV_IMM)
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS((flags & INV_IMM) ? MOV_DP : MVN_DP, flags & SET_FLAGS,
+ dst, SLJIT_UNUSED, src2));
}
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, RM(src2));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MVN_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, RM(src2)));
case SLJIT_CLZ:
SLJIT_ASSERT(!(flags & INV_IMM));
SLJIT_ASSERT(!(src2 & SRC2_IMM));
FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2)));
- if (flags & SET_FLAGS)
- EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(CMP_DP, SLJIT_UNUSED, dst, SRC2_IMM);
return SLJIT_SUCCESS;
case SLJIT_ADD:
SLJIT_ASSERT(!(flags & INV_IMM));
- EMIT_DATA_PROCESS_INS_AND_RETURN(ADD_DP);
+ if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(CMN_DP, SET_FLAGS,
+ SLJIT_UNUSED, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, flags & SET_FLAGS,
+ dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_ADDC:
SLJIT_ASSERT(!(flags & INV_IMM));
- EMIT_DATA_PROCESS_INS_AND_RETURN(ADC_DP);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(ADC_DP, flags & SET_FLAGS,
+ dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_SUB:
SLJIT_ASSERT(!(flags & INV_IMM));
- if (!(flags & ARGS_SWAPPED))
- EMIT_DATA_PROCESS_INS_AND_RETURN(SUB_DP);
- EMIT_DATA_PROCESS_INS_AND_RETURN(RSB_DP);
+ if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(CMP_DP, SET_FLAGS,
+ SLJIT_UNUSED, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(!(flags & ARGS_SWAPPED) ? SUB_DP : RSB_DP, flags & SET_FLAGS,
+ dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_SUBC:
SLJIT_ASSERT(!(flags & INV_IMM));
- if (!(flags & ARGS_SWAPPED))
- EMIT_DATA_PROCESS_INS_AND_RETURN(SBC_DP);
- EMIT_DATA_PROCESS_INS_AND_RETURN(RSC_DP);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(!(flags & ARGS_SWAPPED) ? SBC_DP : RSC_DP, flags & SET_FLAGS,
+ dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & INV_IMM));
SLJIT_ASSERT(!(src2 & SRC2_IMM));
- if (SLJIT_UNLIKELY(op & SLJIT_SET_O))
- mul_inst = SMULL | (reg_map[TMP_REG3] << 16) | (reg_map[dst] << 12);
- else
- mul_inst = MUL | (reg_map[dst] << 16);
- if (dst != src2)
- FAIL_IF(push_inst(compiler, mul_inst | (reg_map[src1] << 8) | reg_map[src2]));
- else if (dst != src1)
- FAIL_IF(push_inst(compiler, mul_inst | (reg_map[src2] << 8) | reg_map[src1]));
- else {
- /* Rm and Rd must not be the same register. */
- SLJIT_ASSERT(dst != TMP_REG1);
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, reg_map[src2])));
- FAIL_IF(push_inst(compiler, mul_inst | (reg_map[src2] << 8) | reg_map[TMP_REG1]));
- }
+ if (!HAS_FLAGS(op))
+ return push_inst(compiler, MUL | (reg_map[dst] << 16) | (reg_map[src2] << 8) | reg_map[src1]);
- if (!(op & SLJIT_SET_O))
- return SLJIT_SUCCESS;
+ FAIL_IF(push_inst(compiler, SMULL | (reg_map[TMP_REG1] << 16) | (reg_map[dst] << 12) | (reg_map[src2] << 8) | reg_map[src1]));
- /* We need to use TMP_REG3. */
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- /* cmp TMP_REG2, dst asr #31. */
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(CMP_DP, SET_FLAGS, SLJIT_UNUSED, TMP_REG3, RM(dst) | 0xfc0));
+ /* cmp TMP_REG1, dst asr #31. */
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(CMP_DP, SET_FLAGS, SLJIT_UNUSED, TMP_REG1, RM(dst) | 0xfc0));
case SLJIT_AND:
- if (!(flags & INV_IMM))
- EMIT_DATA_PROCESS_INS_AND_RETURN(AND_DP);
- EMIT_DATA_PROCESS_INS_AND_RETURN(BIC_DP);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(!(flags & INV_IMM) ? AND_DP : BIC_DP, flags & SET_FLAGS,
+ dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_OR:
SLJIT_ASSERT(!(flags & INV_IMM));
- EMIT_DATA_PROCESS_INS_AND_RETURN(ORR_DP);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(ORR_DP, flags & SET_FLAGS, dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_XOR:
SLJIT_ASSERT(!(flags & INV_IMM));
- EMIT_DATA_PROCESS_INS_AND_RETURN(EOR_DP);
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(EOR_DP, flags & SET_FLAGS, dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_SHL:
EMIT_SHIFT_INS_AND_RETURN(0);
case SLJIT_ASHR:
EMIT_SHIFT_INS_AND_RETURN(2);
}
- SLJIT_ASSERT_STOP();
+
+ SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
}
-#undef EMIT_DATA_PROCESS_INS_AND_RETURN
-#undef EMIT_FULL_DATA_PROCESS_INS_AND_RETURN
#undef EMIT_SHIFT_INS_AND_RETURN
/* Tests whether the immediate can be stored in the 12 bit imm field.
Returns with 0 if not possible. */
static sljit_uw get_imm(sljit_uw imm)
{
- sljit_si rol;
+ sljit_s32 rol;
if (imm <= 0xff)
return SRC2_IMM | imm;
}
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
-static sljit_si generate_int(struct sljit_compiler *compiler, sljit_si reg, sljit_uw imm, sljit_si positive)
+static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm, sljit_s32 positive)
{
sljit_uw mask;
sljit_uw imm1;
sljit_uw imm2;
- sljit_si rol;
+ sljit_s32 rol;
/* Step1: Search a zero byte (8 continous zero bit). */
mask = 0xff000000;
}
#endif
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_uw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm)
{
sljit_uw tmp;
/* Load integer. */
return push_inst_with_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, reg, TMP_PC, 0), imm);
#else
- return emit_imm(compiler, reg, imm);
+ FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));
+ if (imm <= 0xffff)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));
#endif
}
-/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */
-static sljit_si emit_set_delta(struct sljit_compiler *compiler, sljit_si dst, sljit_si reg, sljit_sw value)
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
+ sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
{
- if (value >= 0) {
- value = get_imm(value);
- if (value)
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, dst, reg, value));
- }
- else {
- value = get_imm(-value);
- if (value)
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, dst, reg, value));
- }
- return SLJIT_ERR_UNSUPPORTED;
-}
+ sljit_uw offset_reg, imm;
+ sljit_uw is_type1_transfer = IS_TYPE1_TRANSFER(flags);
-/* Can perform an operation using at most 1 instruction. */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw)
-{
- sljit_uw imm;
+ SLJIT_ASSERT (arg & SLJIT_MEM);
+ SLJIT_ASSERT((arg & REG_MASK) != tmp_reg);
- if (arg & SLJIT_IMM) {
- imm = get_imm(argw);
- if (imm) {
- if (inp_flags & ARG_TEST)
- return 1;
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, imm)));
- return -1;
+ SLJIT_COMPILE_ASSERT(WRITE_BACK == 0x10, optimized_for_emit_data_transfer);
+
+ if ((arg & REG_MASK) == SLJIT_UNUSED) {
+ /* Write back is not used. */
+ if (is_type1_transfer) {
+ FAIL_IF(load_immediate(compiler, tmp_reg, argw & ~0xfff));
+ argw &= 0xfff;
}
- imm = get_imm(~argw);
- if (imm) {
- if (inp_flags & ARG_TEST)
- return 1;
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MVN_DP, 0, reg, SLJIT_UNUSED, imm)));
- return -1;
+ else {
+ FAIL_IF(load_immediate(compiler, tmp_reg, argw & ~0xff));
+ argw &= 0xff;
}
- return 0;
+
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, 0, reg, tmp_reg, is_type1_transfer ? argw : TYPE2_TRANSFER_IMM(argw)));
}
- SLJIT_ASSERT(arg & SLJIT_MEM);
+ if (arg & OFFS_REG_MASK) {
+ offset_reg = OFFS_REG(arg);
+ arg &= REG_MASK;
+ argw &= 0x3;
- /* Fast loads/stores. */
- if (!(arg & REG_MASK))
- return 0;
+ if (argw != 0 && !is_type1_transfer) {
+ SLJIT_ASSERT(!(flags & WRITE_BACK));
- if (arg & OFFS_REG_MASK) {
- if ((argw & 0x3) != 0 && !IS_TYPE1_TRANSFER(inp_flags))
- return 0;
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_reg, arg, RM(offset_reg) | (argw << 7))));
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, 0, reg, tmp_reg, TYPE2_TRANSFER_IMM(0)));
+ }
- if (inp_flags & ARG_TEST)
- return 1;
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK,
- RM(OFFS_REG(arg)) | (IS_TYPE1_TRANSFER(inp_flags) ? SRC2_IMM : 0) | ((argw & 0x3) << 7))));
- return -1;
+ /* Bit 25: RM is offset. */
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, flags & WRITE_BACK, reg, arg,
+ RM(offset_reg) | (is_type1_transfer ? (1 << 25) : 0) | (argw << 7)));
}
- if (IS_TYPE1_TRANSFER(inp_flags)) {
+ arg &= REG_MASK;
+
+ if (is_type1_transfer) {
+ if (argw > 0xfff) {
+ imm = get_imm(argw & ~0xfff);
+ if (imm) {
+ offset_reg = (flags & WRITE_BACK) ? arg : tmp_reg;
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, offset_reg, arg, imm)));
+ argw = argw & 0xfff;
+ arg = offset_reg;
+ }
+ }
+ else if (argw < -0xfff) {
+ imm = get_imm(-argw & ~0xfff);
+ if (imm) {
+ offset_reg = (flags & WRITE_BACK) ? arg : tmp_reg;
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, offset_reg, arg, imm)));
+ argw = -(-argw & 0xfff);
+ arg = offset_reg;
+ }
+ }
+
if (argw >= 0 && argw <= 0xfff) {
- if (inp_flags & ARG_TEST)
- return 1;
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, argw)));
- return -1;
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, flags & WRITE_BACK, reg, arg & REG_MASK, argw));
}
if (argw < 0 && argw >= -0xfff) {
- if (inp_flags & ARG_TEST)
- return 1;
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 0, inp_flags & WRITE_BACK, reg, arg & REG_MASK, -argw)));
- return -1;
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 0, flags & WRITE_BACK, reg, arg & REG_MASK, -argw));
}
}
else {
+ if (argw > 0xff) {
+ imm = get_imm(argw & ~0xff);
+ if (imm) {
+ offset_reg = (flags & WRITE_BACK) ? arg : tmp_reg;
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, offset_reg, arg, imm)));
+ argw = argw & 0xff;
+ arg = offset_reg;
+ }
+ }
+ else if (argw < -0xff) {
+ imm = get_imm(-argw & ~0xff);
+ if (imm) {
+ offset_reg = (flags & WRITE_BACK) ? arg : tmp_reg;
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, offset_reg, arg, imm)));
+ argw = -(-argw & 0xff);
+ arg = offset_reg;
+ }
+ }
+
if (argw >= 0 && argw <= 0xff) {
- if (inp_flags & ARG_TEST)
- return 1;
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, TYPE2_TRANSFER_IMM(argw))));
- return -1;
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, flags & WRITE_BACK, reg, arg, TYPE2_TRANSFER_IMM(argw)));
}
if (argw < 0 && argw >= -0xff) {
- if (inp_flags & ARG_TEST)
- return 1;
argw = -argw;
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 0, inp_flags & WRITE_BACK, reg, arg & REG_MASK, TYPE2_TRANSFER_IMM(argw))));
- return -1;
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 0, flags & WRITE_BACK, reg, arg, TYPE2_TRANSFER_IMM(argw)));
}
}
- return 0;
+ FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+ return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, flags & WRITE_BACK, reg, arg,
+ RM(tmp_reg) | (is_type1_transfer ? (1 << 25) : 0)));
}
-/* See getput_arg below.
- Note: can_cache is called only for binary operators. Those
- operators always uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- /* Immediate caching is not supported as it would be an operation on constant arguments. */
- if (arg & SLJIT_IMM)
- return 0;
-
- /* Always a simple operation. */
- if (arg & OFFS_REG_MASK)
- return 0;
-
- if (!(arg & REG_MASK)) {
- /* Immediate access. */
- if ((next_arg & SLJIT_MEM) && ((sljit_uw)argw - (sljit_uw)next_argw <= 0xfff || (sljit_uw)next_argw - (sljit_uw)argw <= 0xfff))
- return 1;
- return 0;
- }
-
- if (argw <= 0xfffff && argw >= -0xfffff)
- return 0;
-
- if (argw == next_argw && (next_arg & SLJIT_MEM))
- return 1;
+ /* src1 is reg or TMP_REG1
+ src2 is reg, TMP_REG2, or imm
+ result goes to TMP_REG2, so put result can use TMP_REG1. */
- if (arg == next_arg && ((sljit_uw)argw - (sljit_uw)next_argw <= 0xfff || (sljit_uw)next_argw - (sljit_uw)argw <= 0xfff))
- return 1;
-
- return 0;
-}
+ /* We prefers register and simple consts. */
+ sljit_s32 dst_reg;
+ sljit_s32 src1_reg;
+ sljit_s32 src2_reg;
+ sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
-#define GETPUT_ARG_DATA_TRANSFER(add, wb, target, base, imm) \
- if (max_delta & 0xf00) \
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, imm))); \
- else \
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, TYPE2_TRANSFER_IMM(imm))));
-
-#define TEST_WRITE_BACK() \
- if (inp_flags & WRITE_BACK) { \
- tmp_r = arg & REG_MASK; \
- if (reg == tmp_r) { \
- /* This can only happen for stores */ \
- /* since ldr reg, [reg, ...]! has no meaning */ \
- SLJIT_ASSERT(!(inp_flags & LOAD_DATA)); \
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(reg)))); \
- reg = TMP_REG3; \
- } \
- }
-
-/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
-{
- sljit_si tmp_r;
- sljit_sw max_delta;
- sljit_sw sign;
- sljit_uw imm;
+ /* Destination check. */
+ if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED))
+ flags |= UNUSED_RETURN;
- if (arg & SLJIT_IMM) {
- SLJIT_ASSERT(inp_flags & LOAD_DATA);
- return load_immediate(compiler, reg, argw);
- }
+ SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM));
- SLJIT_ASSERT(arg & SLJIT_MEM);
+ src2_reg = 0;
- tmp_r = (inp_flags & LOAD_DATA) ? reg : TMP_REG3;
- max_delta = IS_TYPE1_TRANSFER(inp_flags) ? 0xfff : 0xff;
+ do {
+ if (!(inp_flags & ALLOW_IMM))
+ break;
- if ((arg & REG_MASK) == SLJIT_UNUSED) {
- /* Write back is not used. */
- imm = (sljit_uw)(argw - compiler->cache_argw);
- if ((compiler->cache_arg & SLJIT_IMM) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) {
- if (imm <= (sljit_uw)max_delta) {
- sign = 1;
- argw = argw - compiler->cache_argw;
+ if (src2 & SLJIT_IMM) {
+ src2_reg = get_imm(src2w);
+ if (src2_reg)
+ break;
+ if (inp_flags & ALLOW_INV_IMM) {
+ src2_reg = get_imm(~src2w);
+ if (src2_reg) {
+ flags |= INV_IMM;
+ break;
+ }
}
- else {
- sign = 0;
- argw = compiler->cache_argw - argw;
+ if (GET_OPCODE(op) == SLJIT_ADD) {
+ src2_reg = get_imm(-src2w);
+ if (src2_reg) {
+ op = SLJIT_SUB | GET_ALL_FLAGS(op);
+ break;
+ }
+ }
+ if (GET_OPCODE(op) == SLJIT_SUB) {
+ src2_reg = get_imm(-src2w);
+ if (src2_reg) {
+ op = SLJIT_ADD | GET_ALL_FLAGS(op);
+ break;
+ }
}
-
- GETPUT_ARG_DATA_TRANSFER(sign, 0, reg, TMP_REG3, argw);
- return SLJIT_SUCCESS;
- }
-
- /* With write back, we can create some sophisticated loads, but
- it is hard to decide whether we should convert downward (0s) or upward (1s). */
- imm = (sljit_uw)(argw - next_argw);
- if ((next_arg & SLJIT_MEM) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) {
- SLJIT_ASSERT(inp_flags & LOAD_DATA);
-
- compiler->cache_arg = SLJIT_IMM;
- compiler->cache_argw = argw;
- tmp_r = TMP_REG3;
- }
-
- FAIL_IF(load_immediate(compiler, tmp_r, argw));
- GETPUT_ARG_DATA_TRANSFER(1, 0, reg, tmp_r, 0);
- return SLJIT_SUCCESS;
- }
-
- if (arg & OFFS_REG_MASK) {
- SLJIT_ASSERT((argw & 0x3) && !(max_delta & 0xf00));
- if (inp_flags & WRITE_BACK)
- tmp_r = arg & REG_MASK;
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_r, arg & REG_MASK, RM(OFFS_REG(arg)) | ((argw & 0x3) << 7))));
- return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, 0, reg, tmp_r, TYPE2_TRANSFER_IMM(0)));
- }
-
- imm = (sljit_uw)(argw - compiler->cache_argw);
- if (compiler->cache_arg == arg && imm <= (sljit_uw)max_delta) {
- SLJIT_ASSERT(!(inp_flags & WRITE_BACK));
- GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, imm);
- return SLJIT_SUCCESS;
- }
- if (compiler->cache_arg == arg && imm >= (sljit_uw)-max_delta) {
- SLJIT_ASSERT(!(inp_flags & WRITE_BACK));
- imm = (sljit_uw)-(sljit_sw)imm;
- GETPUT_ARG_DATA_TRANSFER(0, 0, reg, TMP_REG3, imm);
- return SLJIT_SUCCESS;
- }
-
- imm = get_imm(argw & ~max_delta);
- if (imm) {
- TEST_WRITE_BACK();
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_r, arg & REG_MASK, imm)));
- GETPUT_ARG_DATA_TRANSFER(1, inp_flags & WRITE_BACK, reg, tmp_r, argw & max_delta);
- return SLJIT_SUCCESS;
- }
-
- imm = get_imm(-argw & ~max_delta);
- if (imm) {
- argw = -argw;
- TEST_WRITE_BACK();
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, tmp_r, arg & REG_MASK, imm)));
- GETPUT_ARG_DATA_TRANSFER(0, inp_flags & WRITE_BACK, reg, tmp_r, argw & max_delta);
- return SLJIT_SUCCESS;
- }
-
- if ((compiler->cache_arg & SLJIT_IMM) && compiler->cache_argw == argw) {
- TEST_WRITE_BACK();
- return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, RM(TMP_REG3) | (max_delta & 0xf00 ? SRC2_IMM : 0)));
- }
-
- if (argw == next_argw && (next_arg & SLJIT_MEM)) {
- SLJIT_ASSERT(inp_flags & LOAD_DATA);
- FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
-
- compiler->cache_arg = SLJIT_IMM;
- compiler->cache_argw = argw;
-
- TEST_WRITE_BACK();
- return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, RM(TMP_REG3) | (max_delta & 0xf00 ? SRC2_IMM : 0)));
- }
-
- imm = (sljit_uw)(argw - next_argw);
- if (arg == next_arg && !(inp_flags & WRITE_BACK) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) {
- SLJIT_ASSERT(inp_flags & LOAD_DATA);
- FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG3, TMP_REG3, reg_map[arg & REG_MASK])));
-
- compiler->cache_arg = arg;
- compiler->cache_argw = argw;
-
- GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, 0);
- return SLJIT_SUCCESS;
- }
-
- if ((arg & REG_MASK) == tmp_r) {
- compiler->cache_arg = SLJIT_IMM;
- compiler->cache_argw = argw;
- tmp_r = TMP_REG3;
- }
-
- FAIL_IF(load_immediate(compiler, tmp_r, argw));
- return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, reg_map[tmp_r] | (max_delta & 0xf00 ? SRC2_IMM : 0)));
-}
-
-static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
-{
- if (getput_arg_fast(compiler, flags, reg, arg, argw))
- return compiler->error;
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
-}
-
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
-{
- if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
- return compiler->error;
- return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
-}
-
-static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si inp_flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
-{
- /* arg1 goes to TMP_REG1 or src reg
- arg2 goes to TMP_REG2, imm or src reg
- TMP_REG3 can be used for caching
- result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
-
- /* We prefers register and simple consts. */
- sljit_si dst_r;
- sljit_si src1_r;
- sljit_si src2_r = 0;
- sljit_si sugg_src2_r = TMP_REG2;
- sljit_si flags = GET_FLAGS(op) ? SET_FLAGS : 0;
-
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
-
- /* Destination check. */
- if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
- return SLJIT_SUCCESS;
- dst_r = TMP_REG2;
- }
- else if (FAST_IS_REG(dst)) {
- dst_r = dst;
- flags |= REG_DEST;
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
- sugg_src2_r = dst_r;
- }
- else {
- SLJIT_ASSERT(dst & SLJIT_MEM);
- if (getput_arg_fast(compiler, inp_flags | ARG_TEST, TMP_REG2, dst, dstw)) {
- flags |= FAST_DEST;
- dst_r = TMP_REG2;
- }
- else {
- flags |= SLOW_DEST;
- dst_r = 0;
}
- }
- /* Source 1. */
- if (FAST_IS_REG(src1))
- src1_r = src1;
- else if (FAST_IS_REG(src2)) {
- flags |= ARGS_SWAPPED;
- src1_r = src2;
- src2 = src1;
- src2w = src1w;
- }
- else do { /* do { } while(0) is used because of breaks. */
- src1_r = 0;
- if ((inp_flags & ALLOW_ANY_IMM) && (src1 & SLJIT_IMM)) {
- /* The second check will generate a hit. */
- src2_r = get_imm(src1w);
- if (src2_r) {
+ if (src1 & SLJIT_IMM) {
+ src2_reg = get_imm(src1w);
+ if (src2_reg) {
flags |= ARGS_SWAPPED;
src1 = src2;
src1w = src2w;
break;
}
if (inp_flags & ALLOW_INV_IMM) {
- src2_r = get_imm(~src1w);
- if (src2_r) {
+ src2_reg = get_imm(~src1w);
+ if (src2_reg) {
flags |= ARGS_SWAPPED | INV_IMM;
src1 = src2;
src1w = src2w;
}
}
if (GET_OPCODE(op) == SLJIT_ADD) {
- src2_r = get_imm(-src1w);
- if (src2_r) {
- /* Note: ARGS_SWAPPED is intentionally not applied! */
+ src2_reg = get_imm(-src1w);
+ if (src2_reg) {
+ /* Note: add is commutative operation. */
src1 = src2;
src1w = src2w;
op = SLJIT_SUB | GET_ALL_FLAGS(op);
}
}
}
+ } while(0);
- if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w)) {
- FAIL_IF(compiler->error);
- src1_r = TMP_REG1;
- }
- } while (0);
+ /* Source 1. */
+ if (FAST_IS_REG(src1))
+ src1_reg = src1;
+ else if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
+ src1_reg = TMP_REG1;
+ }
+ else {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+ src1_reg = TMP_REG1;
+ }
- /* Source 2. */
- if (src2_r == 0) {
- if (FAST_IS_REG(src2)) {
- src2_r = src2;
- flags |= REG_SOURCE;
- if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
- dst_r = src2_r;
- }
- else do { /* do { } while(0) is used because of breaks. */
- if ((inp_flags & ALLOW_ANY_IMM) && (src2 & SLJIT_IMM)) {
- src2_r = get_imm(src2w);
- if (src2_r)
- break;
- if (inp_flags & ALLOW_INV_IMM) {
- src2_r = get_imm(~src2w);
- if (src2_r) {
- flags |= INV_IMM;
- break;
- }
- }
- if (GET_OPCODE(op) == SLJIT_ADD) {
- src2_r = get_imm(-src2w);
- if (src2_r) {
- op = SLJIT_SUB | GET_ALL_FLAGS(op);
- flags &= ~ARGS_SWAPPED;
- break;
- }
- }
- if (GET_OPCODE(op) == SLJIT_SUB && !(flags & ARGS_SWAPPED)) {
- src2_r = get_imm(-src2w);
- if (src2_r) {
- op = SLJIT_ADD | GET_ALL_FLAGS(op);
- flags &= ~ARGS_SWAPPED;
- break;
- }
- }
- }
+ /* Destination. */
+ dst_reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
- /* src2_r is 0. */
- if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w)) {
- FAIL_IF(compiler->error);
- src2_r = sugg_src2_r;
- }
- } while (0);
- }
+ if (op <= SLJIT_MOVU_P) {
+ if (dst & SLJIT_MEM) {
+ if (inp_flags & BYTE_DATA)
+ inp_flags &= ~SIGNED_DATA;
- /* src1_r, src2_r and dst_r can be zero (=unprocessed) or non-zero.
- If they are zero, they must not be registers. */
- if (src1_r == 0 && src2_r == 0 && dst_r == 0) {
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
- SLJIT_ASSERT(!(flags & ARGS_SWAPPED));
- flags |= ARGS_SWAPPED;
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src2, src2w, src1, src1w));
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src1, src1w, dst, dstw));
+ if (FAST_IS_REG(src2))
+ return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG2);
}
- else {
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
- }
- src1_r = TMP_REG1;
- src2_r = TMP_REG2;
- }
- else if (src1_r == 0 && src2_r == 0) {
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
- src1_r = TMP_REG1;
- }
- else if (src1_r == 0 && dst_r == 0) {
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
- src1_r = TMP_REG1;
- }
- else if (src2_r == 0 && dst_r == 0) {
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
- src2_r = sugg_src2_r;
+
+ if (FAST_IS_REG(src2) && dst_reg != TMP_REG2)
+ flags |= MOVE_REG_CONV;
}
- if (dst_r == 0)
- dst_r = TMP_REG2;
+ /* Source 2. */
+ if (src2_reg == 0) {
+ src2_reg = (op <= SLJIT_MOVU_P) ? dst_reg : TMP_REG2;
- if (src1_r == 0) {
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, 0, 0));
- src1_r = TMP_REG1;
+ if (FAST_IS_REG(src2))
+ src2_reg = src2;
+ else if (src2 & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG2));
+ else
+ FAIL_IF(load_immediate(compiler, src2_reg, src2w));
}
- if (src2_r == 0) {
- FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, 0, 0));
- src2_r = sugg_src2_r;
- }
+ FAIL_IF(emit_single_op(compiler, op, flags, dst_reg, src1_reg, src2_reg));
- FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
+ if (!(dst & SLJIT_MEM))
+ return SLJIT_SUCCESS;
- if (flags & (FAST_DEST | SLOW_DEST)) {
- if (flags & FAST_DEST)
- FAIL_IF(getput_arg_fast(compiler, inp_flags, dst_r, dst, dstw));
- else
- FAIL_IF(getput_arg(compiler, inp_flags, dst_r, dst, dstw, 0, 0));
- }
- return SLJIT_SUCCESS;
+ return emit_op_mem(compiler, inp_flags, dst_reg, dst, dstw, TMP_REG1);
}
#ifdef __cplusplus
}
#endif
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
+ sljit_sw saved_reg_list[3];
+ sljit_sw saved_reg_count;
+
CHECK_ERROR();
CHECK(check_sljit_emit_op0(compiler, op));
case SLJIT_NOP:
FAIL_IF(push_inst(compiler, NOP));
break;
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
-#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
- return push_inst(compiler, (op == SLJIT_LUMUL ? UMULL : SMULL)
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
+ return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL)
| (reg_map[SLJIT_R1] << 16)
| (reg_map[SLJIT_R0] << 12)
| (reg_map[SLJIT_R0] << 8)
| reg_map[SLJIT_R1]);
-#else
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, RM(SLJIT_R1))));
- return push_inst(compiler, (op == SLJIT_LUMUL ? UMULL : SMULL)
- | (reg_map[SLJIT_R1] << 16)
- | (reg_map[SLJIT_R0] << 12)
- | (reg_map[SLJIT_R0] << 8)
- | reg_map[TMP_REG1]);
-#endif
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
- SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2, bad_register_mapping);
-
- if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) {
- FAIL_IF(push_inst(compiler, 0xe52d2008 /* str r2, [sp, #-8]! */));
- FAIL_IF(push_inst(compiler, 0xe58d1004 /* str r1, [sp, #4] */));
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
+ SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+ SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 3);
+
+ saved_reg_count = 0;
+ if (compiler->scratches >= 4)
+ saved_reg_list[saved_reg_count++] = 3;
+ if (compiler->scratches >= 3)
+ saved_reg_list[saved_reg_count++] = 2;
+ if (op >= SLJIT_DIV_UW)
+ saved_reg_list[saved_reg_count++] = 1;
+
+ if (saved_reg_count > 0) {
+ FAIL_IF(push_inst(compiler, 0xe52d0000 | (saved_reg_count >= 3 ? 16 : 8)
+ | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */));
+ if (saved_reg_count >= 2) {
+ SLJIT_ASSERT(saved_reg_list[1] < 8);
+ FAIL_IF(push_inst(compiler, 0xe58d0004 | (saved_reg_list[1] << 12) /* str rX, [sp, #4] */));
+ }
+ if (saved_reg_count >= 3) {
+ SLJIT_ASSERT(saved_reg_list[2] < 8);
+ FAIL_IF(push_inst(compiler, 0xe58d0008 | (saved_reg_list[2] << 12) /* str rX, [sp, #8] */));
+ }
}
- else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3))
- FAIL_IF(push_inst(compiler, 0xe52d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* str r1/r2, [sp, #-8]! */));
#if defined(__GNUC__)
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
- ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
+ ((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
#else
#error "Software divmod functions are needed"
#endif
- if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) {
- FAIL_IF(push_inst(compiler, 0xe59d1004 /* ldr r1, [sp, #4] */));
- FAIL_IF(push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */));
+ if (saved_reg_count > 0) {
+ if (saved_reg_count >= 3) {
+ SLJIT_ASSERT(saved_reg_list[2] < 8);
+ FAIL_IF(push_inst(compiler, 0xe59d0008 | (saved_reg_list[2] << 12) /* ldr rX, [sp, #8] */));
+ }
+ if (saved_reg_count >= 2) {
+ SLJIT_ASSERT(saved_reg_list[1] < 8);
+ FAIL_IF(push_inst(compiler, 0xe59d0004 | (saved_reg_list[1] << 12) /* ldr rX, [sp, #4] */));
+ }
+ return push_inst(compiler, 0xe49d0000 | (saved_reg_count >= 3 ? 16 : 8)
+ | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */);
}
- else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3))
- return push_inst(compiler, 0xe49d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* ldr r1/r2, [sp], #8 */);
return SLJIT_SUCCESS;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
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)) {
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+ if (op <= SLJIT_MOV_P && (src & SLJIT_MEM))
+ return emit_op_mem(compiler, PRELOAD_DATA | LOAD_DATA, TMP_PC, src, srcw, TMP_REG1);
+#endif
+ return SLJIT_SUCCESS;
+ }
+
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
case SLJIT_MOV_P:
return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_UB:
- return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
+ case SLJIT_MOV_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
- case SLJIT_MOV_SB:
- return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
+ case SLJIT_MOV_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
- case SLJIT_MOV_UH:
- return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
+ case SLJIT_MOV_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
- case SLJIT_MOV_SH:
- return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
+ case SLJIT_MOV_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_MOVU:
- case SLJIT_MOVU_UI:
- case SLJIT_MOVU_SI:
+ case SLJIT_MOVU_U32:
+ case SLJIT_MOVU_S32:
case SLJIT_MOVU_P:
return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_UB:
- return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
+ case SLJIT_MOVU_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
- case SLJIT_MOVU_SB:
- return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
+ case SLJIT_MOVU_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
- case SLJIT_MOVU_UH:
- return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
+ case SLJIT_MOVU_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
- case SLJIT_MOVU_SH:
- return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
+ case SLJIT_MOVU_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_NOT:
return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
+ if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+ return SLJIT_SUCCESS;
+
switch (GET_OPCODE(op)) {
case SLJIT_ADD:
case SLJIT_ADDC:
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg << 1;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
/* Floating point operators */
/* --------------------------------------------------------------------- */
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
-
-/* 0 - no fpu
- 1 - vfp */
-static sljit_si arm_fpu_type = -1;
-
-static void init_compiler(void)
-{
- if (arm_fpu_type != -1)
- return;
-
- /* TODO: Only the OS can help to determine the correct fpu type. */
- arm_fpu_type = 1;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
-{
-#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
-#else
- if (arm_fpu_type == -1)
- init_compiler();
- return arm_fpu_type;
-#endif
-}
-
-#else
-
-#define arm_fpu_type 1
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
-{
- /* Always available. */
- return 1;
-}
-
-#endif
#define FPU_LOAD (1 << 20)
#define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \
#define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \
((opcode) | (mode) | ((dst) << 12) | (src1) | ((src2) << 16))
-static sljit_si emit_fop_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
- sljit_sw tmp;
sljit_uw imm;
- sljit_sw inst = VSTR_F32 | (flags & (SLJIT_SINGLE_OP | FPU_LOAD));
+ sljit_sw inst = VSTR_F32 | (flags & (SLJIT_F32_OP | FPU_LOAD));
+
SLJIT_ASSERT(arg & SLJIT_MEM);
+ arg &= ~SLJIT_MEM;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & REG_MASK, RM(OFFS_REG(arg)) | ((argw & 0x3) << 7))));
- arg = SLJIT_MEM | TMP_REG1;
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG2, arg & REG_MASK, RM(OFFS_REG(arg)) | ((argw & 0x3) << 7))));
+ arg = TMP_REG2;
argw = 0;
}
/* Fast loads and stores. */
- if ((arg & REG_MASK)) {
+ if (arg) {
if (!(argw & ~0x3fc))
return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, arg & REG_MASK, reg, argw >> 2));
if (!(-argw & ~0x3fc))
return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, arg & REG_MASK, reg, (-argw) >> 2));
- }
-
- if (compiler->cache_arg == arg) {
- tmp = argw - compiler->cache_argw;
- if (!(tmp & ~0x3fc))
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG3, reg, tmp >> 2));
- if (!(-tmp & ~0x3fc))
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG3, reg, -tmp >> 2));
- if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, tmp) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- compiler->cache_argw = argw;
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG3, reg, 0));
- }
- }
- if (arg & REG_MASK) {
- if (emit_set_delta(compiler, TMP_REG1, arg & REG_MASK, argw) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, 0));
- }
imm = get_imm(argw & ~0x3fc);
if (imm) {
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & REG_MASK, imm)));
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, (argw & 0x3fc) >> 2));
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG2, arg & REG_MASK, imm)));
+ return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, (argw & 0x3fc) >> 2));
}
imm = get_imm(-argw & ~0x3fc);
if (imm) {
argw = -argw;
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, TMP_REG1, arg & REG_MASK, imm)));
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG1, reg, (argw & 0x3fc) >> 2));
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, TMP_REG2, arg & REG_MASK, imm)));
+ return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG2, reg, (argw & 0x3fc) >> 2));
}
}
- compiler->cache_arg = arg;
- compiler->cache_argw = argw;
- if (arg & REG_MASK) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, argw));
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG3, arg & REG_MASK, reg_map[TMP_REG1])));
+ if (arg) {
+ FAIL_IF(load_immediate(compiler, TMP_REG2, argw));
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG2, arg & REG_MASK, RM(TMP_REG2))));
}
else
- FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
+ FAIL_IF(load_immediate(compiler, TMP_REG2, argw));
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG3, reg, 0));
+ return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, 0));
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
+ op ^= SLJIT_F32_OP;
+
if (src & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src, srcw));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src, srcw));
src = TMP_FREG1;
}
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_S32_F32, op & SLJIT_SINGLE_OP, TMP_FREG1, src, 0)));
-
- if (dst == SLJIT_UNUSED)
- return SLJIT_SUCCESS;
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_S32_F32, op & SLJIT_F32_OP, TMP_FREG1, src, 0)));
if (FAST_IS_REG(dst))
return push_inst(compiler, VMOV | (1 << 20) | RD(dst) | (TMP_FREG1 << 16));
return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ op ^= SLJIT_F32_OP;
if (FAST_IS_REG(src))
FAIL_IF(push_inst(compiler, VMOV | RD(src) | (TMP_FREG1 << 16)));
FAIL_IF(push_inst(compiler, VMOV | RD(TMP_REG1) | (TMP_FREG1 << 16)));
}
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F32_S32, op & SLJIT_SINGLE_OP, dst_r, TMP_FREG1, 0)));
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F32_S32, op & SLJIT_F32_OP, dst_r, TMP_FREG1, 0)));
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
+ op ^= SLJIT_F32_OP;
+
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src1, src1w));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w));
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src2, src2w));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w));
src2 = TMP_FREG2;
}
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_SINGLE_OP, src1, src2, 0)));
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_F32_OP, src1, src2, 0)));
return push_inst(compiler, VMRS);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- if (GET_OPCODE(op) != SLJIT_CONVD_FROMS)
- op ^= SLJIT_SINGLE_OP;
- SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100), float_transfer_bit_error);
+ SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100), float_transfer_bit_error);
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32)
+ op ^= SLJIT_F32_OP;
+
if (src & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, dst_r, src, srcw));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, dst_r, src, srcw));
src = dst_r;
}
switch (GET_OPCODE(op)) {
- case SLJIT_DMOV:
+ case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_SINGLE_OP, dst_r, src, 0)));
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
else
dst_r = src;
}
break;
- case SLJIT_DNEG:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VNEG_F32, op & SLJIT_SINGLE_OP, dst_r, src, 0)));
+ case SLJIT_NEG_F64:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VNEG_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
break;
- case SLJIT_DABS:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_SINGLE_OP, dst_r, src, 0)));
+ case SLJIT_ABS_F64:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
break;
- case SLJIT_CONVD_FROMS:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F64_F32, op & SLJIT_SINGLE_OP, dst_r, src, 0)));
- op ^= SLJIT_SINGLE_OP;
+ case SLJIT_CONV_F64_FROM_F32:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F64_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
+ op ^= SLJIT_F32_OP;
break;
}
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), dst_r, dst, dstw);
+ return emit_fop_mem(compiler, (op & SLJIT_F32_OP), dst_r, dst, dstw);
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- op ^= SLJIT_SINGLE_OP;
+ op ^= SLJIT_F32_OP;
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src2, src2w));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w));
src2 = TMP_FREG2;
}
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src1, src1w));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w));
src1 = TMP_FREG1;
}
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_SINGLE_OP, dst_r, src2, src1)));
+ case SLJIT_ADD_F64:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
break;
- case SLJIT_DSUB:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_SINGLE_OP, dst_r, src2, src1)));
+ case SLJIT_SUB_F64:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
break;
- case SLJIT_DMUL:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_SINGLE_OP, dst_r, src2, src1)));
+ case SLJIT_MUL_F64:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
break;
- case SLJIT_DDIV:
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_SINGLE_OP, dst_r, src2, src1)));
+ case SLJIT_DIV_F64:
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
break;
}
if (dst_r == TMP_FREG1)
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw));
return SLJIT_SUCCESS;
}
/* Other instructions */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
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;
+ SLJIT_ASSERT(reg_map[TMP_REG1] == 14);
if (FAST_IS_REG(dst))
- return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, RM(TMP_REG3)));
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, RM(TMP_REG1)));
/* Memory. */
- if (getput_arg_fast(compiler, WORD_DATA, TMP_REG3, dst, dstw))
- return compiler->error;
- /* TMP_REG3 is used for caching. */
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG2, SLJIT_UNUSED, RM(TMP_REG3))));
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- return getput_arg(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0);
+ return emit_op_mem(compiler, WORD_DATA, TMP_REG1, dst, dstw, TMP_REG2);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
+ SLJIT_ASSERT(reg_map[TMP_REG1] == 14);
+
if (FAST_IS_REG(src))
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(src))));
- else if (src & SLJIT_MEM) {
- if (getput_arg_fast(compiler, WORD_DATA | LOAD_DATA, TMP_REG3, src, srcw))
- FAIL_IF(compiler->error);
- else {
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- FAIL_IF(getput_arg(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw, 0, 0));
- FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(TMP_REG2))));
- }
- }
+ FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, 0, RM(src))));
+ else if (src & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG2));
else if (src & SLJIT_IMM)
- FAIL_IF(load_immediate(compiler, TMP_REG3, srcw));
- return push_inst(compiler, BLX | RM(TMP_REG3));
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+
+ return push_inst(compiler, BX | RM(TMP_REG1));
}
/* --------------------------------------------------------------------- */
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(sljit_si type)
+static sljit_uw get_cc(sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
- case SLJIT_D_EQUAL:
+ case SLJIT_EQUAL_F64:
return 0x00000000;
case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
- case SLJIT_D_NOT_EQUAL:
+ case SLJIT_NOT_EQUAL_F64:
return 0x10000000;
case SLJIT_LESS:
- case SLJIT_D_LESS:
+ case SLJIT_LESS_F64:
return 0x30000000;
case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
+ case SLJIT_GREATER_EQUAL_F64:
return 0x20000000;
case SLJIT_GREATER:
- case SLJIT_D_GREATER:
+ case SLJIT_GREATER_F64:
return 0x80000000;
case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
+ case SLJIT_LESS_EQUAL_F64:
return 0x90000000;
case SLJIT_SIG_LESS:
return 0xd0000000;
case SLJIT_OVERFLOW:
- case SLJIT_D_UNORDERED:
+ case SLJIT_UNORDERED_F64:
return 0x60000000;
case SLJIT_NOT_OVERFLOW:
- case SLJIT_D_ORDERED:
+ case SLJIT_ORDERED_F64:
return 0x70000000;
default:
return label;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
if (type >= SLJIT_FAST_CALL)
PTR_FAIL_IF(prepare_blx(compiler));
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0,
- type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(type), 0));
+ type <= SLJIT_JUMP ? TMP_PC : TMP_REG2, TMP_PC, 0)) & ~COND_MASK) | get_cc(type), 0));
if (jump->flags & SLJIT_REWRITABLE_JUMP) {
jump->addr = compiler->size;
#else
if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL;
- PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
- PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(type)));
+ PTR_FAIL_IF(emit_imm(compiler, TMP_REG2, 0));
+ PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG2)) & ~COND_MASK) | get_cc(type)));
jump->addr = compiler->size;
#endif
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump;
return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src));
SLJIT_ASSERT(src & SLJIT_MEM);
- FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw));
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw, TMP_REG2));
return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG2));
}
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
if (type >= SLJIT_FAST_CALL)
FAIL_IF(prepare_blx(compiler));
- FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0));
+ FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, type <= SLJIT_JUMP ? TMP_PC : TMP_REG2, TMP_PC, 0), 0));
if (type >= SLJIT_FAST_CALL)
FAIL_IF(emit_blx(compiler));
#else
- FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
- FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));
+ FAIL_IF(emit_imm(compiler, TMP_REG2, 0));
+ FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG2)));
#endif
jump->addr = compiler->size;
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_si dst_r, flags = GET_ALL_FLAGS(op);
+ sljit_s32 dst_r, flags = GET_ALL_FLAGS(op);
sljit_uw cc, ins;
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;
op = GET_OPCODE(op);
cc = get_cc(type & 0xff);
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (op < SLJIT_ADD) {
FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst_r, SLJIT_UNUSED, SRC2_IMM | 0)));
FAIL_IF(push_inst(compiler, (EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst_r, SLJIT_UNUSED, SRC2_IMM | 1) & ~COND_MASK) | cc));
- return (dst_r == TMP_REG2) ? emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw) : SLJIT_SUCCESS;
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_DATA, TMP_REG1, dst, dstw, TMP_REG2);
+ return SLJIT_SUCCESS;
}
ins = (op == SLJIT_AND ? AND_DP : (op == SLJIT_OR ? ORR_DP : EOR_DP));
- if ((op == SLJIT_OR || op == SLJIT_XOR) && FAST_IS_REG(dst) && dst == src) {
- FAIL_IF(push_inst(compiler, (EMIT_DATA_PROCESS_INS(ins, 0, dst, dst, SRC2_IMM | 1) & ~COND_MASK) | cc));
- /* The condition must always be set, even if the ORR/EOR is not executed above. */
- return (flags & SLJIT_SET_E) ? push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG1, SLJIT_UNUSED, RM(dst))) : SLJIT_SUCCESS;
- }
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- if (src & SLJIT_MEM) {
- FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
- src = TMP_REG1;
- srcw = 0;
- } else if (src & SLJIT_IMM) {
+ if (dst & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG2));
+
+ FAIL_IF(push_inst(compiler, (EMIT_DATA_PROCESS_INS(ins, 0, dst_r, dst_r, SRC2_IMM | 1) & ~COND_MASK) | cc));
+
+ if (op == SLJIT_AND)
+ FAIL_IF(push_inst(compiler, (EMIT_DATA_PROCESS_INS(ins, 0, dst_r, dst_r, SRC2_IMM | 0) & ~COND_MASK) | (cc ^ 0x10000000)));
+
+ if (dst & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, dst, dstw, TMP_REG2));
+
+ if (flags & SLJIT_SET_Z)
+ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG2, SLJIT_UNUSED, RM(dst_r)));
+ 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_uw cc, tmp;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+ dst_reg &= ~SLJIT_I32_OP;
+
+ cc = get_cc(type & 0xff);
+
+ if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+ tmp = get_imm(srcw);
+ if (tmp)
+ return push_inst(compiler, (EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst_reg, SLJIT_UNUSED, tmp) & ~COND_MASK) | cc);
+
+ tmp = get_imm(~srcw);
+ if (tmp)
+ return push_inst(compiler, (EMIT_DATA_PROCESS_INS(MVN_DP, 0, dst_reg, SLJIT_UNUSED, tmp) & ~COND_MASK) | cc);
+
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+ tmp = (sljit_uw) srcw;
+ FAIL_IF(push_inst(compiler, (MOVW & ~COND_MASK) | cc | RD(dst_reg) | ((tmp << 4) & 0xf0000) | (tmp & 0xfff)));
+ if (tmp <= 0xffff)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, (MOVT & ~COND_MASK) | cc | RD(dst_reg) | ((tmp >> 12) & 0xf0000) | ((tmp >> 16) & 0xfff));
+#else
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
src = TMP_REG1;
- srcw = 0;
+#endif
}
- FAIL_IF(push_inst(compiler, (EMIT_DATA_PROCESS_INS(ins, 0, dst_r, src, SRC2_IMM | 1) & ~COND_MASK) | cc));
- FAIL_IF(push_inst(compiler, (EMIT_DATA_PROCESS_INS(ins, 0, dst_r, src, SRC2_IMM | 0) & ~COND_MASK) | (cc ^ 0x10000000)));
- if (dst_r == TMP_REG2)
- FAIL_IF(emit_op_mem2(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0));
-
- return (flags & SLJIT_SET_E) ? push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG1, SLJIT_UNUSED, RM(dst_r))) : SLJIT_SUCCESS;
+ return push_inst(compiler, (EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst_reg, SLJIT_UNUSED, RM(src)) & ~COND_MASK) | cc);
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
- sljit_si reg;
+ sljit_s32 reg;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
set_const(const_, compiler);
if (dst & SLJIT_MEM)
- PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+ PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw, TMP_REG1));
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)
{
- inline_set_jump_addr(addr, new_addr, 1);
+ inline_set_jump_addr(addr, executable_offset, new_target, 1);
}
-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)
{
- inline_set_const(addr, new_constant, 1);
+ inline_set_const(addr, executable_offset, new_constant, 1);
}
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "ARM-64" SLJIT_CPUINFO;
}
/* Length of an instruction word */
-typedef sljit_ui sljit_ins;
+typedef sljit_u32 sljit_ins;
#define TMP_ZERO (0)
#define TMP_FREG1 (0)
#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 8] = {
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 8] = {
31, 0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, 8, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 29, 9, 10, 11, 30, 31
};
#define BRK 0xd4200000
#define CBZ 0xb4000000
#define CLZ 0xdac01000
+#define CSEL 0x9a800000
#define CSINC 0x9a800400
#define EOR 0xca000000
#define EORI 0xd2000000
/* dest_reg is the absolute name of the register
Useful for reordering instructions in the delay slot. */
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_imm64_const(struct sljit_compiler *compiler, sljit_si dst, sljit_uw imm)
+static SLJIT_INLINE sljit_s32 emit_imm64_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
{
FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | ((imm & 0xffff) << 5)));
FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((imm >> 16) & 0xffff) << 5) | (1 << 21)));
static SLJIT_INLINE void modify_imm64_const(sljit_ins* inst, sljit_uw new_imm)
{
- sljit_si dst = inst[0] & 0x1f;
+ sljit_s32 dst = inst[0] & 0x1f;
SLJIT_ASSERT((inst[0] & 0xffe00000) == MOVZ && (inst[1] & 0xffe00000) == (MOVK | (1 << 21)));
inst[0] = MOVZ | dst | ((new_imm & 0xffff) << 5);
inst[1] = MOVK | dst | (((new_imm >> 16) & 0xffff) << 5) | (1 << 21);
inst[3] = MOVK | dst | ((new_imm >> 48) << 5) | (3 << 21);
}
-static SLJIT_INLINE sljit_si 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;
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);
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
+ sljit_sw executable_offset;
sljit_uw addr;
- sljit_si dst;
+ sljit_s32 dst;
struct sljit_label *label;
struct sljit_jump *jump;
code_ptr = code;
word_count = 0;
+ executable_offset = SLJIT_EXEC_OFFSET(code);
+
label = compiler->labels;
jump = compiler->jumps;
const_ = compiler->consts;
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) {
} 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;
}
while (jump) {
do {
addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
- buf_ptr = (sljit_ins*)jump->addr;
+ 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)
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;
}
compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+ 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. */
/* --------------------------------------------------------------------- */
#define LOGICAL_IMM_CHECK 0x100
-static sljit_ins logical_imm(sljit_sw imm, sljit_si len)
+static sljit_ins logical_imm(sljit_sw imm, sljit_s32 len)
{
- sljit_si negated, ones, right;
+ sljit_s32 negated, ones, right;
sljit_uw mask, uimm;
sljit_ins ins;
len &= ~LOGICAL_IMM_CHECK;
if (len == 32 && (imm == 0 || imm == -1))
return 0;
- if (len == 16 && ((sljit_si)imm == 0 || (sljit_si)imm == -1))
+ if (len == 16 && ((sljit_s32)imm == 0 || (sljit_s32)imm == -1))
return 0;
}
SLJIT_ASSERT((len == 32 && imm != 0 && imm != -1)
- || (len == 16 && (sljit_si)imm != 0 && (sljit_si)imm != -1));
+ || (len == 16 && (sljit_s32)imm != 0 && (sljit_s32)imm != -1));
uimm = (sljit_uw)imm;
while (1) {
if (len <= 0) {
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return 0;
}
mask = ((sljit_uw)1 << len) - 1;
#undef COUNT_TRAILING_ZERO
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst, sljit_sw simm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw simm)
{
sljit_uw imm = (sljit_uw)simm;
- sljit_si i, zeros, ones, first;
+ sljit_s32 i, zeros, ones, first;
sljit_ins bitmask;
if (imm <= 0xffff)
dst = TMP_ZERO; \
}
-static sljit_si emit_op_imm(struct sljit_compiler *compiler, sljit_si flags, sljit_si dst, sljit_sw arg1, sljit_sw arg2)
+static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_sw arg1, sljit_sw arg2)
{
/* dst must be register, TMP_REG1
arg1 must be register, TMP_REG1, imm
arg2 must be register, TMP_REG2, imm */
sljit_ins inv_bits = (flags & INT_OP) ? (1 << 31) : 0;
sljit_ins inst_bits;
- sljit_si op = (flags & 0xffff);
- sljit_si reg;
+ sljit_s32 op = (flags & 0xffff);
+ sljit_s32 reg;
sljit_sw imm, nimm;
if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) {
}
goto set_flags;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
if (dst == arg2)
return SLJIT_SUCCESS;
return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(arg2));
- case SLJIT_MOV_UB:
- case SLJIT_MOVU_UB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOVU_U8:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
return push_inst(compiler, (UBFM ^ (1 << 31)) | RD(dst) | RN(arg2) | (7 << 10));
- case SLJIT_MOV_SB:
- case SLJIT_MOVU_SB:
+ case SLJIT_MOV_S8:
+ case SLJIT_MOVU_S8:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
if (!(flags & INT_OP))
inv_bits |= 1 << 22;
return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (7 << 10));
- case SLJIT_MOV_UH:
- case SLJIT_MOVU_UH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOVU_U16:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
return push_inst(compiler, (UBFM ^ (1 << 31)) | RD(dst) | RN(arg2) | (15 << 10));
- case SLJIT_MOV_SH:
- case SLJIT_MOVU_SH:
+ case SLJIT_MOV_S16:
+ case SLJIT_MOVU_S16:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
if (!(flags & INT_OP))
inv_bits |= 1 << 22;
return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (15 << 10));
- case SLJIT_MOV_UI:
- case SLJIT_MOVU_UI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOVU_U32:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
if ((flags & INT_OP) && dst == arg2)
return SLJIT_SUCCESS;
return push_inst(compiler, (ORR ^ (1 << 31)) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
- case SLJIT_MOV_SI:
- case SLJIT_MOVU_SI:
+ case SLJIT_MOV_S32:
+ case SLJIT_MOVU_S32:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
if ((flags & INT_OP) && dst == arg2)
return SLJIT_SUCCESS;
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)
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));
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;
+ break; /* Set flags. */
+ default:
+ SLJIT_UNREACHABLE();
+ return SLJIT_SUCCESS;
}
- SLJIT_ASSERT_STOP();
- return SLJIT_SUCCESS;
-
set_flags:
if (flags & SET_FLAGS)
return push_inst(compiler, (SUBS ^ inv_bits) | RD(TMP_ZERO) | RN(dst) | RM(TMP_ZERO));
#define MEM_SIZE_SHIFT(flags) ((flags) >> 8)
-static SLJIT_CONST sljit_ins sljit_mem_imm[4] = {
+static const sljit_ins sljit_mem_imm[4] = {
/* u l */ 0x39400000 /* ldrb [reg,imm] */,
/* u s */ 0x39000000 /* strb [reg,imm] */,
/* s l */ 0x39800000 /* ldrsb [reg,imm] */,
/* s s */ 0x39000000 /* strb [reg,imm] */,
};
-static SLJIT_CONST sljit_ins sljit_mem_simm[4] = {
+static const sljit_ins sljit_mem_simm[4] = {
/* u l */ 0x38400000 /* ldurb [reg,imm] */,
/* u s */ 0x38000000 /* sturb [reg,imm] */,
/* s l */ 0x38800000 /* ldursb [reg,imm] */,
/* s s */ 0x38000000 /* sturb [reg,imm] */,
};
-static SLJIT_CONST sljit_ins sljit_mem_pre_simm[4] = {
+static const sljit_ins sljit_mem_pre_simm[4] = {
/* u l */ 0x38400c00 /* ldrb [reg,imm]! */,
/* u s */ 0x38000c00 /* strb [reg,imm]! */,
/* s l */ 0x38800c00 /* ldrsb [reg,imm]! */,
/* s s */ 0x38000c00 /* strb [reg,imm]! */,
};
-static SLJIT_CONST sljit_ins sljit_mem_reg[4] = {
+static const sljit_ins sljit_mem_reg[4] = {
/* u l */ 0x38606800 /* ldrb [reg,reg] */,
/* u s */ 0x38206800 /* strb [reg,reg] */,
/* s l */ 0x38a06800 /* ldrsb [reg,reg] */,
};
/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */
-static sljit_si emit_set_delta(struct sljit_compiler *compiler, sljit_si dst, sljit_si reg, sljit_sw value)
+static sljit_s32 emit_set_delta(struct sljit_compiler *compiler, sljit_s32 dst, sljit_s32 reg, sljit_sw value)
{
if (value >= 0) {
if (value <= 0xfff)
}
/* Can perform an operation using at most 1 instruction. */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
- sljit_ui shift = MEM_SIZE_SHIFT(flags);
+ sljit_u32 shift = MEM_SIZE_SHIFT(flags);
SLJIT_ASSERT(arg & SLJIT_MEM);
}
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;
/* see getput_arg below.
Note: can_cache is called only for binary operators. Those
operators always uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
sljit_sw diff;
if ((arg & OFFS_REG_MASK) || !(next_arg & SLJIT_MEM))
}
/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg,
- sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
+ sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
- sljit_ui shift = MEM_SIZE_SHIFT(flags);
- sljit_si tmp_r, other_r;
+ sljit_u32 shift = MEM_SIZE_SHIFT(flags);
+ sljit_s32 tmp_r, other_r;
sljit_sw diff;
SLJIT_ASSERT(arg & SLJIT_MEM);
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)));
/* 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) {
}
}
- 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));
return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(TMP_REG3));
}
-static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
if (getput_arg_fast(compiler, flags, reg, arg, argw))
return compiler->error;
return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
}
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
{
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
return compiler->error;
/* Entry, exit */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si i, tmp, offs, prev, saved_regs_size;
+ sljit_s32 i, tmp, offs, prev, saved_regs_size;
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si local_size;
- sljit_si i, tmp, offs, prev, saved_regs_size;
+ sljit_s32 local_size;
+ sljit_s32 i, tmp, offs, prev, saved_regs_size;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
/* Operators */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
- sljit_ins inv_bits = (op & SLJIT_INT_OP) ? (1 << 31) : 0;
+ sljit_ins inv_bits = (op & SLJIT_I32_OP) ? (1 << 31) : 0;
CHECK_ERROR();
CHECK(check_sljit_emit_op0(compiler, op));
return push_inst(compiler, BRK);
case SLJIT_NOP:
return push_inst(compiler, NOP);
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
- return push_inst(compiler, (op == SLJIT_LUMUL ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
+ return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
- FAIL_IF(push_inst(compiler, ((op == SLJIT_UDIVMOD ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)));
+ FAIL_IF(push_inst(compiler, ((op == SLJIT_DIVMOD_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)));
FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- return push_inst(compiler, ((op == SLJIT_UDIVI ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1));
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
+ return push_inst(compiler, ((op == SLJIT_DIV_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1));
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
- sljit_si dst_r, flags, mem_flags;
- sljit_si op_flags = GET_ALL_FLAGS(op);
+ sljit_s32 dst_r, flags, mem_flags;
+ sljit_s32 op_flags = GET_ALL_FLAGS(op);
CHECK_ERROR();
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
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);
case SLJIT_MOV_P:
flags = WORD_SIZE;
break;
- case SLJIT_MOV_UB:
+ case SLJIT_MOV_U8:
flags = BYTE_SIZE;
if (src & SLJIT_IMM)
- srcw = (sljit_ub)srcw;
+ srcw = (sljit_u8)srcw;
break;
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_S8:
flags = BYTE_SIZE | SIGNED;
if (src & SLJIT_IMM)
- srcw = (sljit_sb)srcw;
+ srcw = (sljit_s8)srcw;
break;
- case SLJIT_MOV_UH:
+ case SLJIT_MOV_U16:
flags = HALF_SIZE;
if (src & SLJIT_IMM)
- srcw = (sljit_uh)srcw;
+ srcw = (sljit_u16)srcw;
break;
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_S16:
flags = HALF_SIZE | SIGNED;
if (src & SLJIT_IMM)
- srcw = (sljit_sh)srcw;
+ srcw = (sljit_s16)srcw;
break;
- case SLJIT_MOV_UI:
+ case SLJIT_MOV_U32:
flags = INT_SIZE;
if (src & SLJIT_IMM)
- srcw = (sljit_ui)srcw;
+ srcw = (sljit_u32)srcw;
break;
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_S32:
flags = INT_SIZE | SIGNED;
if (src & SLJIT_IMM)
- srcw = (sljit_si)srcw;
+ srcw = (sljit_s32)srcw;
break;
case SLJIT_MOVU:
case SLJIT_MOVU_P:
flags = WORD_SIZE | UPDATE;
break;
- case SLJIT_MOVU_UB:
+ case SLJIT_MOVU_U8:
flags = BYTE_SIZE | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_ub)srcw;
+ srcw = (sljit_u8)srcw;
break;
- case SLJIT_MOVU_SB:
+ case SLJIT_MOVU_S8:
flags = BYTE_SIZE | SIGNED | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_sb)srcw;
+ srcw = (sljit_s8)srcw;
break;
- case SLJIT_MOVU_UH:
+ case SLJIT_MOVU_U16:
flags = HALF_SIZE | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_uh)srcw;
+ srcw = (sljit_u16)srcw;
break;
- case SLJIT_MOVU_SH:
+ case SLJIT_MOVU_S16:
flags = HALF_SIZE | SIGNED | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_sh)srcw;
+ srcw = (sljit_s16)srcw;
break;
- case SLJIT_MOVU_UI:
+ case SLJIT_MOVU_U32:
flags = INT_SIZE | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_ui)srcw;
+ srcw = (sljit_u32)srcw;
break;
- case SLJIT_MOVU_SI:
+ case SLJIT_MOVU_S32:
flags = INT_SIZE | SIGNED | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_si)srcw;
+ srcw = (sljit_s32)srcw;
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
flags = 0;
break;
}
FAIL_IF(getput_arg(compiler, flags, dst_r, src, srcw, dst, dstw));
} else {
if (dst_r != TMP_REG1)
- return emit_op_imm(compiler, op | ((op_flags & SLJIT_INT_OP) ? INT_OP : 0), dst_r, TMP_REG1, src);
+ return emit_op_imm(compiler, op | ((op_flags & SLJIT_I32_OP) ? INT_OP : 0), dst_r, TMP_REG1, src);
dst_r = src;
}
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_INT_OP) {
+ if (op_flags & SLJIT_I32_OP) {
flags |= INT_OP;
mem_flags = INT_SIZE;
}
if (src & SLJIT_IMM) {
flags |= ARG2_IMM;
- if (op_flags & SLJIT_INT_OP)
- srcw = (sljit_si)srcw;
+ if (op_flags & SLJIT_I32_OP)
+ srcw = (sljit_s32)srcw;
} else
srcw = src;
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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_si dst_r, flags, mem_flags;
+ sljit_s32 dst_r, flags, mem_flags;
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
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_INT_OP) {
+ if (op & SLJIT_I32_OP) {
flags |= INT_OP;
mem_flags = INT_SIZE;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
/* Floating point operators */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
+static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
-#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
-#else
- /* Available by default. */
- return 1;
-#endif
-}
-
-static sljit_si emit_fop_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
-{
- sljit_ui shift = MEM_SIZE_SHIFT(flags);
+ sljit_u32 shift = MEM_SIZE_SHIFT(flags);
sljit_ins ins_bits = (shift << 30);
- sljit_si other_r;
+ sljit_s32 other_r;
sljit_sw diff;
SLJIT_ASSERT(arg & SLJIT_MEM);
return push_inst(compiler, STR_FI | ins_bits | VT(reg) | RN(TMP_REG3));
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
- sljit_ins inv_bits = (op & SLJIT_SINGLE_OP) ? (1 << 22) : 0;
+ 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_CONVI_FROMD)
+ if (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64)
inv_bits |= (1 << 31);
if (src & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src, srcw);
+ emit_fop_mem(compiler, (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src, srcw);
src = TMP_FREG1;
}
FAIL_IF(push_inst(compiler, (FCVTZS ^ inv_bits) | RD(dst_r) | VN(src)));
- if (dst_r == TMP_REG1 && dst != SLJIT_UNUSED)
- return emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONVI_FROMD) ? INT_SIZE : WORD_SIZE) | STORE, TMP_REG1, dst, dstw);
+ 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;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- sljit_ins inv_bits = (op & SLJIT_SINGLE_OP) ? (1 << 22) : 0;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMI)
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
inv_bits |= (1 << 31);
if (src & SLJIT_MEM) {
- emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONVD_FROMI) ? INT_SIZE : WORD_SIZE), TMP_REG1, src, srcw);
+ emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? INT_SIZE : WORD_SIZE), TMP_REG1, src, srcw);
src = TMP_REG1;
} else if (src & SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMI)
- srcw = (sljit_si)srcw;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
#endif
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
src = TMP_REG1;
FAIL_IF(push_inst(compiler, (SCVTF ^ inv_bits) | VD(dst_r) | RN(src)));
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, ((op & SLJIT_SINGLE_OP) ? INT_SIZE : WORD_SIZE) | STORE, TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, ((op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE) | STORE, TMP_FREG1, dst, dstw);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_si mem_flags = (op & SLJIT_SINGLE_OP) ? INT_SIZE : WORD_SIZE;
- sljit_ins inv_bits = (op & SLJIT_SINGLE_OP) ? (1 << 22) : 0;
+ sljit_s32 mem_flags = (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE;
+ sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
if (src1 & SLJIT_MEM) {
emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w);
return push_inst(compiler, (FCMP ^ inv_bits) | VN(src1) | VM(src2));
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r, mem_flags = (op & SLJIT_SINGLE_OP) ? INT_SIZE : WORD_SIZE;
+ sljit_s32 dst_r, mem_flags = (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE;
sljit_ins inv_bits;
CHECK_ERROR();
SLJIT_COMPILE_ASSERT((INT_SIZE ^ 0x100) == WORD_SIZE, must_be_one_bit_difference);
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
- inv_bits = (op & SLJIT_SINGLE_OP) ? (1 << 22) : 0;
+ inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src & SLJIT_MEM) {
- emit_fop_mem(compiler, (GET_OPCODE(op) == SLJIT_CONVD_FROMS) ? (mem_flags ^ 0x100) : mem_flags, dst_r, src, srcw);
+ emit_fop_mem(compiler, (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) ? (mem_flags ^ 0x100) : mem_flags, dst_r, src, srcw);
src = dst_r;
}
switch (GET_OPCODE(op)) {
- case SLJIT_DMOV:
+ case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
FAIL_IF(push_inst(compiler, (FMOV ^ inv_bits) | VD(dst_r) | VN(src)));
dst_r = src;
}
break;
- case SLJIT_DNEG:
+ case SLJIT_NEG_F64:
FAIL_IF(push_inst(compiler, (FNEG ^ inv_bits) | VD(dst_r) | VN(src)));
break;
- case SLJIT_DABS:
+ case SLJIT_ABS_F64:
FAIL_IF(push_inst(compiler, (FABS ^ inv_bits) | VD(dst_r) | VN(src)));
break;
- case SLJIT_CONVD_FROMS:
- FAIL_IF(push_inst(compiler, FCVT | ((op & SLJIT_SINGLE_OP) ? (1 << 22) : (1 << 15)) | VD(dst_r) | VN(src)));
+ case SLJIT_CONV_F64_FROM_F32:
+ FAIL_IF(push_inst(compiler, FCVT | ((op & SLJIT_F32_OP) ? (1 << 22) : (1 << 15)) | VD(dst_r) | VN(src)));
break;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r, mem_flags = (op & SLJIT_SINGLE_OP) ? INT_SIZE : WORD_SIZE;
- sljit_ins inv_bits = (op & SLJIT_SINGLE_OP) ? (1 << 22) : 0;
+ sljit_s32 dst_r, mem_flags = (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE;
+ sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
}
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
+ case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, (FADD ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
break;
- case SLJIT_DSUB:
+ case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, (FSUB ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
break;
- case SLJIT_DMUL:
+ case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, (FMUL ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
break;
- case SLJIT_DDIV:
+ case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, (FDIV ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
break;
}
/* Other instructions */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
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));
return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_LR, dst, dstw);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(sljit_si type)
+static sljit_uw get_cc(sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
- case SLJIT_D_EQUAL:
+ case SLJIT_EQUAL_F64:
return 0x1;
case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
- case SLJIT_D_NOT_EQUAL:
+ case SLJIT_NOT_EQUAL_F64:
return 0x0;
case SLJIT_LESS:
- case SLJIT_D_LESS:
+ case SLJIT_LESS_F64:
return 0x2;
case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
+ case SLJIT_GREATER_EQUAL_F64:
return 0x3;
case SLJIT_GREATER:
- case SLJIT_D_GREATER:
+ case SLJIT_GREATER_F64:
return 0x9;
case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
+ case SLJIT_LESS_EQUAL_F64:
return 0x8;
case SLJIT_SIG_LESS:
return 0xc;
case SLJIT_OVERFLOW:
- case SLJIT_D_UNORDERED:
+ case SLJIT_UNORDERED_F64:
return 0x7;
case SLJIT_NOT_OVERFLOW:
- case SLJIT_D_ORDERED:
+ case SLJIT_ORDERED_F64:
return 0x6;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return 0xe;
}
}
return label;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
return jump;
}
-static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump;
- sljit_ins inv_bits = (type & SLJIT_INT_OP) ? (1 << 31) : 0;
+ sljit_ins inv_bits = (type & SLJIT_I32_OP) ? (1 << 31) : 0;
SLJIT_ASSERT((type & 0xff) == SLJIT_EQUAL || (type & 0xff) == SLJIT_NOT_EQUAL);
ADJUST_LOCAL_OFFSET(src, srcw);
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump;
return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1));
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_si 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;
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_INT_OP) {
+ 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_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_r, TMP_REG2);
+
+ 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;
- } else if (src & SLJIT_IMM)
- flags |= ARG1_IMM;
+ }
- 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);
+ cc = get_cc(type & 0xff);
+ dst_reg &= ~SLJIT_I32_OP;
- if (dst_r != TMP_REG1)
- return SLJIT_SUCCESS;
- return emit_op_mem2(compiler, mem_flags | STORE, TMP_REG1, dst, dstw, 0, 0);
+ 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_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
- sljit_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
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)
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);
}
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "ARM-Thumb2" SLJIT_CPUINFO;
}
/* Length of an instruction word. */
-typedef sljit_ui sljit_ins;
+typedef sljit_u32 sljit_ins;
/* Last register + 1. */
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
-#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
-#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 5)
+#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 4)
#define TMP_FREG1 (0)
#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
- 0, 0, 1, 2, 12, 11, 10, 9, 8, 7, 6, 5, 13, 3, 4, 14, 15
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+ 0, 0, 1, 2, 12, 11, 10, 9, 8, 7, 6, 5, 4, 13, 3, 14, 15
};
#define COPY_BITS(src, from, to, bits) \
#define BLX 0x4780
#define BX 0x4700
#define CLZ 0xfab0f080
+#define CMNI_W 0xf1100f00
+#define CMP 0x4280
#define CMPI 0x2800
+#define CMPI_W 0xf1b00f00
+#define CMP_X 0x4500
#define CMP_W 0xebb00f00
#define EORI 0xf0800000
#define EORS 0x4040
#define VSTR_F32 0xed000a00
#define VSUB_F32 0xee300a40
-static sljit_si push_inst16(struct sljit_compiler *compiler, sljit_ins inst)
+static sljit_s32 push_inst16(struct sljit_compiler *compiler, sljit_ins inst)
{
- sljit_uh *ptr;
+ sljit_u16 *ptr;
SLJIT_ASSERT(!(inst & 0xffff0000));
- ptr = (sljit_uh*)ensure_buf(compiler, sizeof(sljit_uh));
+ ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_u16));
FAIL_IF(!ptr);
*ptr = inst;
compiler->size++;
return SLJIT_SUCCESS;
}
-static sljit_si push_inst32(struct sljit_compiler *compiler, sljit_ins inst)
+static sljit_s32 push_inst32(struct sljit_compiler *compiler, sljit_ins inst)
{
- sljit_uh *ptr = (sljit_uh*)ensure_buf(compiler, sizeof(sljit_ins));
+ sljit_u16 *ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
*ptr++ = inst >> 16;
*ptr = inst;
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_imm32_const(struct sljit_compiler *compiler, sljit_si dst, sljit_uw imm)
+static SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
{
FAIL_IF(push_inst32(compiler, MOVW | RD4(dst) |
COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff)));
COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16));
}
-static SLJIT_INLINE void modify_imm32_const(sljit_uh *inst, sljit_uw new_imm)
+static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm)
{
- sljit_si dst = inst[1] & 0x0f00;
+ sljit_s32 dst = inst[1] & 0x0f00;
SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00));
inst[0] = (MOVW >> 16) | COPY_BITS(new_imm, 12, 0, 4) | COPY_BITS(new_imm, 11, 10, 1);
inst[1] = dst | COPY_BITS(new_imm, 8, 12, 3) | (new_imm & 0xff);
inst[3] = dst | COPY_BITS(new_imm, 8 + 16, 12, 3) | ((new_imm & 0xff0000) >> 16);
}
-static SLJIT_INLINE sljit_si detect_jump_type(struct sljit_jump *jump, sljit_uh *code_ptr, sljit_uh *code)
+static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset)
{
sljit_sw diff;
/* Branch to ARM code is not optimized yet. */
if (!(jump->u.target & 0x1))
return 0;
- diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2)) >> 1;
+ diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset) >> 1;
}
else {
SLJIT_ASSERT(jump->flags & JUMP_LABEL);
return 0;
}
-static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump)
+static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset)
{
- sljit_si type = (jump->flags >> 4) & 0xf;
+ sljit_s32 type = (jump->flags >> 4) & 0xf;
sljit_sw diff;
- sljit_uh *jump_inst;
- sljit_si s, j1, j2;
+ sljit_u16 *jump_inst;
+ sljit_s32 s, j1, j2;
if (SLJIT_UNLIKELY(type == 0)) {
- modify_imm32_const((sljit_uh*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
+ modify_imm32_const((sljit_u16*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
return;
}
if (jump->flags & JUMP_ADDR) {
SLJIT_ASSERT(jump->u.target & 0x1);
- diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + 4)) >> 1;
+ diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
}
- else
- diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + 4)) >> 1;
- jump_inst = (sljit_uh*)jump->addr;
+ else {
+ SLJIT_ASSERT(jump->u.label->addr & 0x1);
+ diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
+ }
+ jump_inst = (sljit_u16*)jump->addr;
switch (type) {
case 1:
else if (type == 6) /* Encoding T1 of 'BL' instruction */
jump_inst[1] |= 0xd000;
else
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
{
struct sljit_memory_fragment *buf;
- sljit_uh *code;
- sljit_uh *code_ptr;
- sljit_uh *buf_ptr;
- sljit_uh *buf_end;
+ sljit_u16 *code;
+ sljit_u16 *code_ptr;
+ sljit_u16 *buf_ptr;
+ sljit_u16 *buf_end;
sljit_uw half_count;
+ sljit_sw executable_offset;
struct sljit_label *label;
struct sljit_jump *jump;
CHECK_PTR(check_sljit_generate_code(compiler));
reverse_buf(compiler);
- code = (sljit_uh*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_uh));
+ code = (sljit_u16*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_u16));
PTR_FAIL_WITH_EXEC_IF(code);
buf = compiler->buf;
code_ptr = code;
half_count = 0;
+ executable_offset = SLJIT_EXEC_OFFSET(code);
+
label = compiler->labels;
jump = compiler->jumps;
const_ = compiler->consts;
do {
- buf_ptr = (sljit_uh*)buf->memory;
+ buf_ptr = (sljit_u16*)buf->memory;
buf_end = buf_ptr + (buf->used_size >> 1);
do {
*code_ptr = *buf_ptr++;
SLJIT_ASSERT(!jump || jump->addr >= half_count);
SLJIT_ASSERT(!const_ || const_->addr >= half_count);
if (label && label->size == half_count) {
- label->addr = ((sljit_uw)code_ptr) | 0x1;
+ label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
label->size = code_ptr - code;
label = label->next;
}
if (jump && jump->addr == half_count) {
jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_COND) ? 10 : 8);
- 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 == half_count) {
} while (buf);
if (label && label->size == half_count) {
- label->addr = ((sljit_uw)code_ptr) | 0x1;
+ label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
label->size = code_ptr - code;
label = label->next;
}
jump = compiler->jumps;
while (jump) {
- set_jump_instruction(jump);
+ set_jump_instruction(jump, executable_offset);
jump = jump->next;
}
compiler->error = SLJIT_ERR_COMPILED;
- compiler->executable_size = (code_ptr - code) * sizeof(sljit_uh);
+ compiler->executable_offset = executable_offset;
+ compiler->executable_size = (code_ptr - code) * sizeof(sljit_u16);
+
+ code = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+ code_ptr = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
SLJIT_CACHE_FLUSH(code, code_ptr);
/* Set thumb mode flag. */
return (void*)((sljit_uw)code | 0x1);
}
+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. */
/* --------------------------------------------------------------------- */
static sljit_uw get_imm(sljit_uw imm)
{
/* Thumb immediate form. */
- sljit_si counter;
+ sljit_s32 counter;
if (imm <= 0xff)
return imm;
return ((imm >> 24) & 0x7f) | COPY_BITS(counter, 4, 26, 1) | COPY_BITS(counter, 1, 12, 3) | COPY_BITS(counter, 0, 7, 1);
}
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst, sljit_uw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
{
sljit_uw tmp;
#define ARG1_IMM 0x0010000
#define ARG2_IMM 0x0020000
-#define KEEP_FLAGS 0x0040000
/* SET_FLAGS must be 0x100000 as it is also the value of S bit (can be used for optimization). */
#define SET_FLAGS 0x0100000
#define UNUSED_RETURN 0x0200000
-#define SLOW_DEST 0x0400000
-#define SLOW_SRC1 0x0800000
-#define SLOW_SRC2 0x1000000
-static sljit_si emit_op_imm(struct sljit_compiler *compiler, sljit_si flags, sljit_si dst, sljit_uw arg1, sljit_uw arg2)
+static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_uw arg1, sljit_uw arg2)
{
/* dst must be register, TMP_REG1
- arg1 must be register, TMP_REG1, imm
- arg2 must be register, TMP_REG2, imm */
- sljit_si reg;
+ arg1 must be register, imm
+ arg2 must be register, imm */
+ sljit_s32 reg;
sljit_uw imm, nimm;
if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) {
- /* Both are immediates. */
+ /* Both are immediates, no temporaries are used. */
flags &= ~ARG1_IMM;
FAIL_IF(load_immediate(compiler, TMP_REG1, arg1));
arg1 = TMP_REG1;
/* No form with immediate operand. */
break;
case SLJIT_MOV:
- SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG1);
+ SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG2);
return load_immediate(compiler, dst, imm);
case SLJIT_NOT:
if (!(flags & SET_FLAGS))
break;
case SLJIT_ADD:
nimm = -imm;
- if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(reg, dst)) {
+ if (IS_2_LO_REGS(reg, dst)) {
if (imm <= 0x7)
return push_inst16(compiler, ADDSI3 | IMM3(imm) | RD3(dst) | RN3(reg));
if (nimm <= 0x7)
if (nimm <= 0xfff)
return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(nimm));
}
- imm = get_imm(imm);
- if (imm != INVALID_IMM)
- return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+ nimm = get_imm(imm);
+ if (nimm != INVALID_IMM)
+ return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+ nimm = get_imm(-imm);
+ if (nimm != INVALID_IMM)
+ return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
break;
case SLJIT_ADDC:
imm = get_imm(imm);
return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
break;
case SLJIT_SUB:
+ /* SUB operation can be replaced by ADD because of the negative carry flag. */
if (flags & ARG1_IMM) {
- if (!(flags & KEEP_FLAGS) && imm == 0 && IS_2_LO_REGS(reg, dst))
+ if (imm == 0 && IS_2_LO_REGS(reg, dst))
return push_inst16(compiler, RSBSI | RD3(dst) | RN3(reg));
imm = get_imm(imm);
if (imm != INVALID_IMM)
return push_inst32(compiler, RSB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
break;
}
+ if (flags & UNUSED_RETURN) {
+ if (imm <= 0xff && reg_map[reg] <= 7)
+ return push_inst16(compiler, CMPI | IMM8(imm) | RDN3(reg));
+ nimm = get_imm(imm);
+ if (nimm != INVALID_IMM)
+ return push_inst32(compiler, CMPI_W | RN4(reg) | nimm);
+ nimm = get_imm(-imm);
+ if (nimm != INVALID_IMM)
+ return push_inst32(compiler, CMNI_W | RN4(reg) | nimm);
+ }
nimm = -imm;
- if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(reg, dst)) {
+ if (IS_2_LO_REGS(reg, dst)) {
if (imm <= 0x7)
return push_inst16(compiler, SUBSI3 | IMM3(imm) | RD3(dst) | RN3(reg));
if (nimm <= 0x7)
if (nimm <= 0xff)
return push_inst16(compiler, ADDSI8 | IMM8(nimm) | RDN3(dst));
}
- if (imm <= 0xff && (flags & UNUSED_RETURN))
- return push_inst16(compiler, CMPI | IMM8(imm) | RDN3(reg));
}
if (!(flags & SET_FLAGS)) {
if (imm <= 0xfff)
if (nimm <= 0xfff)
return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(nimm));
}
- imm = get_imm(imm);
- if (imm != INVALID_IMM)
- return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+ nimm = get_imm(imm);
+ if (nimm != INVALID_IMM)
+ return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+ nimm = get_imm(-imm);
+ if (nimm != INVALID_IMM)
+ return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
break;
case SLJIT_SUBC:
if (flags & ARG1_IMM)
}
switch (flags & 0xffff) {
case SLJIT_SHL:
- if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg))
+ if (IS_2_LO_REGS(dst, reg))
return push_inst16(compiler, LSLSI | RD3(dst) | RN3(reg) | (imm << 6));
return push_inst32(compiler, LSL_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
case SLJIT_LSHR:
- if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg))
+ if (IS_2_LO_REGS(dst, reg))
return push_inst16(compiler, LSRSI | RD3(dst) | RN3(reg) | (imm << 6));
return push_inst32(compiler, LSR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
default: /* SLJIT_ASHR */
- if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg))
+ if (IS_2_LO_REGS(dst, reg))
return push_inst16(compiler, ASRSI | RD3(dst) | RN3(reg) | (imm << 6));
return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
}
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
break;
}
if (flags & ARG2_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG2, arg2));
- arg2 = TMP_REG2;
+ imm = arg2;
+ arg2 = (arg1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+ FAIL_IF(load_immediate(compiler, arg2, imm));
}
else {
- FAIL_IF(load_immediate(compiler, TMP_REG1, arg1));
- arg1 = TMP_REG1;
+ imm = arg1;
+ arg1 = (arg2 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+ FAIL_IF(load_immediate(compiler, arg1, imm));
}
+
+ SLJIT_ASSERT(arg1 != arg2);
}
/* Both arguments are registers. */
switch (flags & 0xffff) {
case SLJIT_MOV:
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
case SLJIT_MOV_P:
case SLJIT_MOVU:
- case SLJIT_MOVU_UI:
- case SLJIT_MOVU_SI:
+ case SLJIT_MOVU_U32:
+ case SLJIT_MOVU_S32:
case SLJIT_MOVU_P:
- SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+ SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
if (dst == arg2)
return SLJIT_SUCCESS;
return push_inst16(compiler, MOV | SET_REGS44(dst, arg2));
- case SLJIT_MOV_UB:
- case SLJIT_MOVU_UB:
- SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+ case SLJIT_MOV_U8:
+ case SLJIT_MOVU_U8:
+ SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
if (IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, UXTB | RD3(dst) | RN3(arg2));
return push_inst32(compiler, UXTB_W | RD4(dst) | RM4(arg2));
- case SLJIT_MOV_SB:
- case SLJIT_MOVU_SB:
- SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+ case SLJIT_MOV_S8:
+ case SLJIT_MOVU_S8:
+ SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
if (IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, SXTB | RD3(dst) | RN3(arg2));
return push_inst32(compiler, SXTB_W | RD4(dst) | RM4(arg2));
- case SLJIT_MOV_UH:
- case SLJIT_MOVU_UH:
- SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+ case SLJIT_MOV_U16:
+ case SLJIT_MOVU_U16:
+ SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
if (IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, UXTH | RD3(dst) | RN3(arg2));
return push_inst32(compiler, UXTH_W | RD4(dst) | RM4(arg2));
- case SLJIT_MOV_SH:
- case SLJIT_MOVU_SH:
- SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+ case SLJIT_MOV_S16:
+ case SLJIT_MOVU_S16:
+ SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
if (IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, SXTH | RD3(dst) | RN3(arg2));
return push_inst32(compiler, SXTH_W | RD4(dst) | RM4(arg2));
case SLJIT_NOT:
- SLJIT_ASSERT(arg1 == TMP_REG1);
- if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ SLJIT_ASSERT(arg1 == TMP_REG2);
+ if (IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, MVNS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, MVN_W | (flags & SET_FLAGS) | RD4(dst) | RM4(arg2));
case SLJIT_CLZ:
- SLJIT_ASSERT(arg1 == TMP_REG1);
+ SLJIT_ASSERT(arg1 == TMP_REG2);
FAIL_IF(push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2)));
- if (flags & SET_FLAGS) {
- if (reg_map[dst] <= 7)
- return push_inst16(compiler, CMPI | RDN3(dst));
- return push_inst32(compiler, ADD_WI | SET_FLAGS | RN4(dst) | RD4(dst));
- }
return SLJIT_SUCCESS;
case SLJIT_ADD:
- if (!(flags & KEEP_FLAGS) && IS_3_LO_REGS(dst, arg1, arg2))
+ if (IS_3_LO_REGS(dst, arg1, arg2))
return push_inst16(compiler, ADDS | RD3(dst) | RN3(arg1) | RM3(arg2));
if (dst == arg1 && !(flags & SET_FLAGS))
return push_inst16(compiler, ADD | SET_REGS44(dst, arg2));
return push_inst32(compiler, ADD_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_ADDC:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, ADCS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, ADC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_SUB:
- if (!(flags & KEEP_FLAGS) && IS_3_LO_REGS(dst, arg1, arg2))
+ if (flags & UNUSED_RETURN) {
+ if (IS_2_LO_REGS(arg1, arg2))
+ return push_inst16(compiler, CMP | RD3(arg1) | RN3(arg2));
+ return push_inst16(compiler, CMP_X | SET_REGS44(arg1, arg2));
+ }
+ if (IS_3_LO_REGS(dst, arg1, arg2))
return push_inst16(compiler, SUBS | RD3(dst) | RN3(arg1) | RM3(arg2));
return push_inst32(compiler, SUB_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_SUBC:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, SBCS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, SBC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_MUL:
if (!(flags & SET_FLAGS))
return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2));
- SLJIT_ASSERT(reg_map[TMP_REG2] <= 7 && dst != TMP_REG2);
+ SLJIT_ASSERT(dst != TMP_REG2);
FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(TMP_REG2) | RN4(arg1) | RM4(arg2)));
/* cmp TMP_REG2, dst asr #31. */
return push_inst32(compiler, CMP_W | RN4(TMP_REG2) | 0x70e0 | RM4(dst));
case SLJIT_AND:
- if (!(flags & KEEP_FLAGS)) {
- if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
- return push_inst16(compiler, ANDS | RD3(dst) | RN3(arg2));
- if ((flags & UNUSED_RETURN) && IS_2_LO_REGS(arg1, arg2))
- return push_inst16(compiler, TST | RD3(arg1) | RN3(arg2));
- }
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+ return push_inst16(compiler, ANDS | RD3(dst) | RN3(arg2));
+ if ((flags & UNUSED_RETURN) && IS_2_LO_REGS(arg1, arg2))
+ return push_inst16(compiler, TST | RD3(arg1) | RN3(arg2));
return push_inst32(compiler, AND_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_OR:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, ORRS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, ORR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_XOR:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, EORS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, EOR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_SHL:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, LSLS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, LSL_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_LSHR:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, LSRS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, LSR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_ASHR:
- if (dst == arg1 && !(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, arg2))
+ if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, ASRS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, ASR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
}
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
}
#define WORD_SIZE 0x00
#define BYTE_SIZE 0x04
#define HALF_SIZE 0x08
+#define PRELOAD 0x0c
#define UPDATE 0x10
-#define ARG_TEST 0x20
#define IS_WORD_SIZE(flags) (!(flags & (BYTE_SIZE | HALF_SIZE)))
#define OFFSET_CHECK(imm, shift) (!(argw & ~(imm << shift)))
s = store
*/
-static SLJIT_CONST sljit_ins sljit_mem16[12] = {
+static const sljit_ins sljit_mem16[12] = {
/* w u l */ 0x5800 /* ldr */,
/* w u s */ 0x5000 /* str */,
/* w s l */ 0x5800 /* ldr */,
/* h s s */ 0x5200 /* strh */,
};
-static SLJIT_CONST sljit_ins sljit_mem16_imm5[12] = {
+static const sljit_ins sljit_mem16_imm5[12] = {
/* w u l */ 0x6800 /* ldr imm5 */,
/* w u s */ 0x6000 /* str imm5 */,
/* w s l */ 0x6800 /* ldr imm5 */,
#define MEM_IMM8 0xc00
#define MEM_IMM12 0x800000
-static SLJIT_CONST sljit_ins sljit_mem32[12] = {
+static const sljit_ins sljit_mem32[13] = {
/* w u l */ 0xf8500000 /* ldr.w */,
/* w u s */ 0xf8400000 /* str.w */,
/* w s l */ 0xf8500000 /* ldr.w */,
/* h u s */ 0xf8200000 /* strsh.w */,
/* h s l */ 0xf9300000 /* ldrsh.w */,
/* h s s */ 0xf8200000 /* strsh.w */,
+
+/* p u l */ 0xf8100000 /* pld */,
};
/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */
-static sljit_si emit_set_delta(struct sljit_compiler *compiler, sljit_si dst, sljit_si reg, sljit_sw value)
+static sljit_s32 emit_set_delta(struct sljit_compiler *compiler, sljit_s32 dst, sljit_s32 reg, sljit_sw value)
{
if (value >= 0) {
if (value <= 0xfff)
return SLJIT_ERR_UNSUPPORTED;
}
-/* Can perform an operation using at most 1 instruction. */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
+ sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
{
- sljit_si other_r, shift;
+ sljit_s32 other_r;
+ sljit_s32 update = flags & UPDATE;
+ sljit_uw tmp;
SLJIT_ASSERT(arg & SLJIT_MEM);
+ SLJIT_ASSERT((arg & REG_MASK) != tmp_reg);
+ flags &= ~UPDATE;
+ arg &= ~SLJIT_MEM;
+
+ if (SLJIT_UNLIKELY(!(arg & REG_MASK))) {
+ tmp = get_imm(argw & ~0xfff);
+ if (tmp != INVALID_IMM) {
+ FAIL_IF(push_inst32(compiler, MOV_WI | RD4(tmp_reg) | tmp));
+ return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg) | (argw & 0xfff));
+ }
+
+ FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+ if (IS_2_LO_REGS(reg, tmp_reg) && sljit_mem16_imm5[flags])
+ return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(tmp_reg));
+ return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg));
+ }
- if (SLJIT_UNLIKELY(flags & UPDATE)) {
- if ((arg & REG_MASK) && !(arg & OFFS_REG_MASK) && argw <= 0xff && argw >= -0xff) {
- if (SLJIT_UNLIKELY(flags & ARG_TEST))
- return 1;
+ if (SLJIT_UNLIKELY(update)) {
+ SLJIT_ASSERT(reg != arg);
- flags &= ~UPDATE;
+ if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+ other_r = OFFS_REG(arg);
arg &= 0xf;
+
+ if (IS_3_LO_REGS(reg, arg, other_r))
+ FAIL_IF(push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r)));
+ else
+ FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r)));
+ return push_inst16(compiler, ADD | SET_REGS44(arg, other_r));
+ }
+
+ if (argw > 0xff) {
+ tmp = get_imm(argw & ~0xff);
+ if (tmp != INVALID_IMM) {
+ push_inst32(compiler, ADD_WI | RD4(arg) | RN4(arg) | tmp);
+ argw = argw & 0xff;
+ }
+ }
+ else if (argw < -0xff) {
+ tmp = get_imm(-argw & ~0xff);
+ if (tmp != INVALID_IMM) {
+ push_inst32(compiler, SUB_WI | RD4(arg) | RN4(arg) | tmp);
+ argw = -(-argw & 0xff);
+ }
+ }
+
+ if (argw == 0) {
+ if (IS_2_LO_REGS(reg, arg) && sljit_mem16_imm5[flags])
+ return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg));
+ return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg));
+ }
+
+ if (argw <= 0xff && argw >= -0xff) {
if (argw >= 0)
argw |= 0x200;
else {
}
SLJIT_ASSERT(argw >= 0 && (argw & 0xff) <= 0xff);
- FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | 0x100 | argw));
- return -1;
+ return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | 0x100 | argw);
}
- return 0;
+
+ FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+
+ SLJIT_ASSERT(reg != tmp_reg);
+
+ if (IS_3_LO_REGS(reg, arg, tmp_reg))
+ FAIL_IF(push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(tmp_reg)));
+ else
+ FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(tmp_reg)));
+ return push_inst16(compiler, ADD | SET_REGS44(arg, tmp_reg));
}
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
- if (SLJIT_UNLIKELY(flags & ARG_TEST))
- return 1;
-
argw &= 0x3;
other_r = OFFS_REG(arg);
arg &= 0xf;
if (!argw && IS_3_LO_REGS(reg, arg, other_r))
- FAIL_IF(push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r)));
- else
- FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r) | (argw << 4)));
- return -1;
+ return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r));
+ return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r) | (argw << 4));
}
- if (!(arg & REG_MASK) || argw > 0xfff || argw < -0xff)
- return 0;
-
- if (SLJIT_UNLIKELY(flags & ARG_TEST))
- return 1;
+ if (argw > 0xfff) {
+ tmp = get_imm(argw & ~0xfff);
+ if (tmp != INVALID_IMM) {
+ push_inst32(compiler, ADD_WI | RD4(tmp_reg) | RN4(arg) | tmp);
+ arg = tmp_reg;
+ argw = argw & 0xfff;
+ }
+ }
+ else if (argw < -0xff) {
+ tmp = get_imm(-argw & ~0xff);
+ if (tmp != INVALID_IMM) {
+ push_inst32(compiler, SUB_WI | RD4(tmp_reg) | RN4(arg) | tmp);
+ arg = tmp_reg;
+ argw = -(-argw & 0xff);
+ }
+ }
- arg &= 0xf;
if (IS_2_LO_REGS(reg, arg) && sljit_mem16_imm5[flags]) {
- shift = 3;
+ tmp = 3;
if (IS_WORD_SIZE(flags)) {
if (OFFSET_CHECK(0x1f, 2))
- shift = 2;
+ tmp = 2;
}
else if (flags & BYTE_SIZE)
{
if (OFFSET_CHECK(0x1f, 0))
- shift = 0;
+ tmp = 0;
}
else {
SLJIT_ASSERT(flags & HALF_SIZE);
if (OFFSET_CHECK(0x1f, 1))
- shift = 1;
- }
-
- if (shift != 3) {
- FAIL_IF(push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg) | (argw << (6 - shift))));
- return -1;
- }
- }
-
- /* SP based immediate. */
- if (SLJIT_UNLIKELY(arg == SLJIT_SP) && OFFSET_CHECK(0xff, 2) && IS_WORD_SIZE(flags) && reg_map[reg] <= 7) {
- FAIL_IF(push_inst16(compiler, STR_SP | ((flags & STORE) ? 0 : 0x800) | RDN3(reg) | (argw >> 2)));
- return -1;
- }
-
- if (argw >= 0)
- FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg) | argw));
- else
- FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | -argw));
- return -1;
-}
-
-/* see getput_arg below.
- Note: can_cache is called only for binary operators. Those
- operators always uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
-{
- sljit_sw diff;
- if ((arg & OFFS_REG_MASK) || !(next_arg & SLJIT_MEM))
- return 0;
-
- if (!(arg & REG_MASK)) {
- diff = argw - next_argw;
- if (diff <= 0xfff && diff >= -0xfff)
- return 1;
- return 0;
- }
-
- if (argw == next_argw)
- return 1;
-
- diff = argw - next_argw;
- if (arg == next_arg && diff <= 0xfff && diff >= -0xfff)
- return 1;
-
- return 0;
-}
-
-/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg,
- sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
-{
- sljit_si tmp_r, other_r;
- sljit_sw diff;
-
- SLJIT_ASSERT(arg & SLJIT_MEM);
- if (!(next_arg & SLJIT_MEM)) {
- next_arg = 0;
- next_argw = 0;
- }
-
- tmp_r = (flags & STORE) ? TMP_REG3 : reg;
-
- if (SLJIT_UNLIKELY((flags & UPDATE) && (arg & REG_MASK))) {
- /* Update only applies if a base register exists. */
- /* There is no caching here. */
- other_r = OFFS_REG(arg);
- arg &= 0xf;
- flags &= ~UPDATE;
-
- if (!other_r) {
- if (!(argw & ~0xfff)) {
- FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg) | argw));
- return push_inst32(compiler, ADDWI | RD4(arg) | RN4(arg) | IMM12(argw));
- }
-
- if (compiler->cache_arg == SLJIT_MEM) {
- if (argw == compiler->cache_argw) {
- other_r = TMP_REG3;
- argw = 0;
- }
- else if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, argw - compiler->cache_argw) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- compiler->cache_argw = argw;
- other_r = TMP_REG3;
- argw = 0;
- }
- }
-
- if (argw) {
- FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
- compiler->cache_arg = SLJIT_MEM;
- compiler->cache_argw = argw;
- other_r = TMP_REG3;
- argw = 0;
- }
- }
-
- argw &= 0x3;
- if (!argw && IS_3_LO_REGS(reg, arg, other_r)) {
- FAIL_IF(push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r)));
- return push_inst16(compiler, ADD | SET_REGS44(arg, other_r));
- }
- FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r) | (argw << 4)));
- return push_inst32(compiler, ADD_W | RD4(arg) | RN4(arg) | RM4(other_r) | (argw << 6));
- }
- flags &= ~UPDATE;
-
- SLJIT_ASSERT(!(arg & OFFS_REG_MASK));
-
- if (compiler->cache_arg == arg) {
- diff = argw - compiler->cache_argw;
- if (!(diff & ~0xfff))
- return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(TMP_REG3) | diff);
- if (!((compiler->cache_argw - argw) & ~0xff))
- return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(TMP_REG3) | (compiler->cache_argw - argw));
- if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, diff) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(TMP_REG3) | 0);
- }
- }
-
- next_arg = (arg & REG_MASK) && (arg == next_arg) && (argw != next_argw);
- arg &= 0xf;
- if (arg && compiler->cache_arg == SLJIT_MEM) {
- if (compiler->cache_argw == argw)
- return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(TMP_REG3));
- if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, argw - compiler->cache_argw) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- compiler->cache_argw = argw;
- return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(TMP_REG3));
+ tmp = 1;
}
- }
- compiler->cache_argw = argw;
- if (next_arg && emit_set_delta(compiler, TMP_REG3, arg, argw) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- compiler->cache_arg = SLJIT_MEM | arg;
- arg = 0;
+ if (tmp < 3)
+ return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg) | (argw << (6 - tmp)));
}
- else {
- FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
- compiler->cache_arg = SLJIT_MEM;
-
- diff = argw - next_argw;
- if (next_arg && diff <= 0xfff && diff >= -0xfff) {
- FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG3, arg)));
- compiler->cache_arg = SLJIT_MEM | arg;
- arg = 0;
- }
+ else if (SLJIT_UNLIKELY(arg == SLJIT_SP) && IS_WORD_SIZE(flags) && OFFSET_CHECK(0xff, 2) && reg_map[reg] <= 7) {
+ /* SP based immediate. */
+ return push_inst16(compiler, STR_SP | ((flags & STORE) ? 0 : 0x800) | RDN3(reg) | (argw >> 2));
}
- if (arg)
- return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(TMP_REG3));
- return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(TMP_REG3) | 0);
-}
+ if (argw >= 0 && argw <= 0xfff)
+ return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg) | argw);
+ else if (argw < 0 && argw >= -0xff)
+ return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | -argw);
-static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
-{
- if (getput_arg_fast(compiler, flags, reg, arg, argw))
- return compiler->error;
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
-}
+ SLJIT_ASSERT(arg != tmp_reg);
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
-{
- if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
- return compiler->error;
- return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
+ FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+ if (IS_3_LO_REGS(reg, arg, tmp_reg))
+ return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(tmp_reg));
+ return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(tmp_reg));
}
/* --------------------------------------------------------------------- */
/* Entry, exit */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si size, i, tmp;
- sljit_ins push;
+ sljit_s32 size, i, tmp;
+ sljit_ins push = 0;
CHECK_ERROR();
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);
- push = (1 << 4);
-
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
for (i = SLJIT_S0; i >= tmp; i--)
push |= 1 << reg_map[i];
: push_inst16(compiler, PUSH | (1 << 8) | push));
/* Stack must be aligned to 8 bytes: (LR, R4) */
- size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 2);
+ size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
local_size = ((size + local_size + 7) & ~7) - size;
compiler->local_size = local_size;
if (local_size > 0) {
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si size;
+ sljit_s32 size;
CHECK_ERROR();
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);
- size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 2);
+ size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
compiler->local_size = ((size + local_size + 7) & ~7) - size;
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si i, tmp;
- sljit_ins pop;
+ sljit_s32 i, tmp;
+ sljit_ins pop = 0;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
FAIL_IF(emit_op_imm(compiler, SLJIT_ADD | ARG2_IMM, SLJIT_SP, SLJIT_SP, compiler->local_size));
}
- pop = (1 << 4);
-
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
for (i = SLJIT_S0; i >= tmp; i--)
pop |= 1 << reg_map[i];
}
#endif
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
sljit_sw saved_reg_list[3];
sljit_sw saved_reg_count;
return push_inst16(compiler, BKPT);
case SLJIT_NOP:
return push_inst16(compiler, NOP);
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
- return push_inst32(compiler, (op == SLJIT_LUMUL ? UMULL : SMULL)
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
+ return push_inst32(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL)
| (reg_map[SLJIT_R1] << 8)
| (reg_map[SLJIT_R0] << 12)
| (reg_map[SLJIT_R0] << 16)
| reg_map[SLJIT_R1]);
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
- SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 12, bad_register_mapping);
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
+ SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+ SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 12);
saved_reg_count = 0;
if (compiler->scratches >= 4)
saved_reg_list[saved_reg_count++] = 12;
if (compiler->scratches >= 3)
saved_reg_list[saved_reg_count++] = 2;
- if (op >= SLJIT_UDIVI)
+ if (op >= SLJIT_DIV_UW)
saved_reg_list[saved_reg_count++] = 1;
if (saved_reg_count > 0) {
#if defined(__GNUC__)
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
- ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
+ ((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
#else
#error "Software divmod functions are needed"
#endif
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
- sljit_si dst_r, flags;
- sljit_si op_flags = GET_ALL_FLAGS(op);
+ sljit_s32 dst_r, flags;
+ sljit_s32 op_flags = GET_ALL_FLAGS(op);
CHECK_ERROR();
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src, srcw);
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
+ if (dst == SLJIT_UNUSED && !HAS_FLAGS(op)) {
+ /* Since TMP_PC has index 15, IS_2_LO_REGS and IS_3_LO_REGS checks always fail. */
+ if (op <= SLJIT_MOV_P && (src & SLJIT_MEM))
+ return emit_op_mem(compiler, PRELOAD, TMP_PC, src, srcw, TMP_REG1);
+ return SLJIT_SUCCESS;
+ }
dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_P) {
switch (op) {
case SLJIT_MOV:
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
case SLJIT_MOV_P:
flags = WORD_SIZE;
break;
- case SLJIT_MOV_UB:
+ case SLJIT_MOV_U8:
flags = BYTE_SIZE;
if (src & SLJIT_IMM)
- srcw = (sljit_ub)srcw;
+ srcw = (sljit_u8)srcw;
break;
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_S8:
flags = BYTE_SIZE | SIGNED;
if (src & SLJIT_IMM)
- srcw = (sljit_sb)srcw;
+ srcw = (sljit_s8)srcw;
break;
- case SLJIT_MOV_UH:
+ case SLJIT_MOV_U16:
flags = HALF_SIZE;
if (src & SLJIT_IMM)
- srcw = (sljit_uh)srcw;
+ srcw = (sljit_u16)srcw;
break;
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_S16:
flags = HALF_SIZE | SIGNED;
if (src & SLJIT_IMM)
- srcw = (sljit_sh)srcw;
+ srcw = (sljit_s16)srcw;
break;
case SLJIT_MOVU:
- case SLJIT_MOVU_UI:
- case SLJIT_MOVU_SI:
+ case SLJIT_MOVU_U32:
+ case SLJIT_MOVU_S32:
case SLJIT_MOVU_P:
flags = WORD_SIZE | UPDATE;
break;
- case SLJIT_MOVU_UB:
+ case SLJIT_MOVU_U8:
flags = BYTE_SIZE | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_ub)srcw;
+ srcw = (sljit_u8)srcw;
break;
- case SLJIT_MOVU_SB:
+ case SLJIT_MOVU_S8:
flags = BYTE_SIZE | SIGNED | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_sb)srcw;
+ srcw = (sljit_s8)srcw;
break;
- case SLJIT_MOVU_UH:
+ case SLJIT_MOVU_U16:
flags = HALF_SIZE | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_uh)srcw;
+ srcw = (sljit_u16)srcw;
break;
- case SLJIT_MOVU_SH:
+ case SLJIT_MOVU_S16:
flags = HALF_SIZE | SIGNED | UPDATE;
if (src & SLJIT_IMM)
- srcw = (sljit_sh)srcw;
+ srcw = (sljit_s16)srcw;
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
flags = 0;
break;
}
if (src & SLJIT_IMM)
- FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG1, srcw));
+ FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG2, srcw));
else if (src & SLJIT_MEM) {
- if (getput_arg_fast(compiler, flags, dst_r, src, srcw))
- FAIL_IF(compiler->error);
- else
- FAIL_IF(getput_arg(compiler, flags, dst_r, src, srcw, dst, dstw));
+ FAIL_IF(emit_op_mem(compiler, flags, dst_r, src, srcw, ((flags & UPDATE) && dst_r == TMP_REG1) ? TMP_REG2 : TMP_REG1));
} else {
if (dst_r != TMP_REG1)
- return emit_op_imm(compiler, op, dst_r, TMP_REG1, src);
+ return emit_op_imm(compiler, op, dst_r, TMP_REG2, src);
dst_r = src;
}
- if (dst & SLJIT_MEM) {
- if (getput_arg_fast(compiler, flags | STORE, dst_r, dst, dstw))
- return compiler->error;
- else
- return getput_arg(compiler, flags | STORE, dst_r, dst, dstw, 0, 0);
- }
- return SLJIT_SUCCESS;
+ if (!(dst & SLJIT_MEM))
+ return SLJIT_SUCCESS;
+
+ return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, (dst_r == TMP_REG1) ? TMP_REG2 : TMP_REG1);
}
if (op == SLJIT_NEG) {
return sljit_emit_op2(compiler, SLJIT_SUB | op_flags, dst, dstw, SLJIT_IMM, 0, src, srcw);
}
- flags = (GET_FLAGS(op_flags) ? SET_FLAGS : 0) | ((op_flags & SLJIT_KEEP_FLAGS) ? KEEP_FLAGS : 0);
- if (src & SLJIT_MEM) {
- if (getput_arg_fast(compiler, WORD_SIZE, TMP_REG2, src, srcw))
- FAIL_IF(compiler->error);
- else
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG2, src, srcw, dst, dstw));
- src = TMP_REG2;
- }
+ flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
if (src & SLJIT_IMM)
flags |= ARG2_IMM;
+ else if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
+ srcw = TMP_REG1;
+ }
else
srcw = src;
- emit_op_imm(compiler, flags | op, dst_r, TMP_REG1, srcw);
+ emit_op_imm(compiler, flags | op, dst_r, TMP_REG2, srcw);
- if (dst & SLJIT_MEM) {
- if (getput_arg_fast(compiler, flags | STORE, dst_r, dst, dstw))
- return compiler->error;
- else
- return getput_arg(compiler, flags | STORE, dst_r, dst, dstw, 0, 0);
- }
- return SLJIT_SUCCESS;
+ if (!(dst & SLJIT_MEM))
+ return SLJIT_SUCCESS;
+ return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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_si dst_r, flags;
+ sljit_s32 dst_reg, flags, src2_reg;
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
-
- dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
- flags = (GET_FLAGS(op) ? SET_FLAGS : 0) | ((op & SLJIT_KEEP_FLAGS) ? KEEP_FLAGS : 0);
-
- if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, WORD_SIZE | STORE | ARG_TEST, TMP_REG1, dst, dstw))
- flags |= SLOW_DEST;
-
- if (src1 & SLJIT_MEM) {
- if (getput_arg_fast(compiler, WORD_SIZE, TMP_REG1, src1, src1w))
- FAIL_IF(compiler->error);
- else
- flags |= SLOW_SRC1;
- }
- if (src2 & SLJIT_MEM) {
- if (getput_arg_fast(compiler, WORD_SIZE, TMP_REG2, src2, src2w))
- FAIL_IF(compiler->error);
- else
- flags |= SLOW_SRC2;
- }
-
- if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG2, src2, src2w, src1, src1w));
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG1, src1, src1w, dst, dstw));
- }
- else {
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG1, src1, src1w, src2, src2w));
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG2, src2, src2w, dst, dstw));
- }
- }
- else if (flags & SLOW_SRC1)
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG1, src1, src1w, dst, dstw));
- else if (flags & SLOW_SRC2)
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG2, src2, src2w, dst, dstw));
+ if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+ return SLJIT_SUCCESS;
- if (src1 & SLJIT_MEM)
- src1 = TMP_REG1;
- if (src2 & SLJIT_MEM)
- src2 = TMP_REG2;
+ dst_reg = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+ flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
if (src1 & SLJIT_IMM)
flags |= ARG1_IMM;
+ else if (src1 & SLJIT_MEM) {
+ emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1);
+ src1w = TMP_REG1;
+ }
else
src1w = src1;
+
if (src2 & SLJIT_IMM)
flags |= ARG2_IMM;
+ else if (src2 & SLJIT_MEM) {
+ src2_reg = (!(flags & ARG1_IMM) && (src1w == TMP_REG1)) ? TMP_REG2 : TMP_REG1;
+ emit_op_mem(compiler, WORD_SIZE, src2_reg, src2, src2w, src2_reg);
+ src2w = src2_reg;
+ }
else
src2w = src2;
if (dst == SLJIT_UNUSED)
flags |= UNUSED_RETURN;
- emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src1w, src2w);
+ emit_op_imm(compiler, flags | GET_OPCODE(op), dst_reg, src1w, src2w);
- if (dst & SLJIT_MEM) {
- if (!(flags & SLOW_DEST)) {
- getput_arg_fast(compiler, WORD_SIZE | STORE, dst_r, dst, dstw);
- return compiler->error;
- }
- return getput_arg(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, 0, 0);
- }
- return SLJIT_SUCCESS;
+ if (!(dst & SLJIT_MEM))
+ return SLJIT_SUCCESS;
+ return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG2);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg << 1;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
if (size == 2)
- return push_inst16(compiler, *(sljit_uh*)instruction);
+ return push_inst16(compiler, *(sljit_u16*)instruction);
return push_inst32(compiler, *(sljit_ins*)instruction);
}
/* Floating point operators */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
-{
-#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
-#else
- /* Available by default. */
- return 1;
-#endif
-}
-
#define FPU_LOAD (1 << 20)
-static sljit_si emit_fop_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
- sljit_sw tmp;
sljit_uw imm;
- sljit_sw inst = VSTR_F32 | (flags & (SLJIT_SINGLE_OP | FPU_LOAD));
+ sljit_sw inst = VSTR_F32 | (flags & (SLJIT_F32_OP | FPU_LOAD));
SLJIT_ASSERT(arg & SLJIT_MEM);
/* Fast loads and stores. */
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
- FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG2) | RN4(arg & REG_MASK) | RM4(OFFS_REG(arg)) | ((argw & 0x3) << 6)));
- arg = SLJIT_MEM | TMP_REG2;
+ FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(arg & REG_MASK) | RM4(OFFS_REG(arg)) | ((argw & 0x3) << 6)));
+ arg = SLJIT_MEM | TMP_REG1;
argw = 0;
}
return push_inst32(compiler, inst | RN4(arg & REG_MASK) | DD4(reg) | (-argw >> 2));
}
- /* Slow cases */
- SLJIT_ASSERT(!(arg & OFFS_REG_MASK));
- if (compiler->cache_arg == arg) {
- tmp = argw - compiler->cache_argw;
- if (!(tmp & ~0x3fc))
- return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG3) | DD4(reg) | (tmp >> 2));
- if (!(-tmp & ~0x3fc))
- return push_inst32(compiler, inst | RN4(TMP_REG3) | DD4(reg) | (-tmp >> 2));
- if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, tmp) != SLJIT_ERR_UNSUPPORTED) {
- FAIL_IF(compiler->error);
- compiler->cache_argw = argw;
- return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG3) | DD4(reg));
- }
- }
-
if (arg & REG_MASK) {
if (emit_set_delta(compiler, TMP_REG1, arg & REG_MASK, argw) != SLJIT_ERR_UNSUPPORTED) {
FAIL_IF(compiler->error);
}
}
- compiler->cache_arg = arg;
- compiler->cache_argw = argw;
-
- FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
+ FAIL_IF(load_immediate(compiler, TMP_REG1, argw));
if (arg & REG_MASK)
- FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG3, (arg & REG_MASK))));
- return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG3) | DD4(reg));
+ FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, (arg & REG_MASK))));
+ return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg));
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
+ op ^= SLJIT_F32_OP;
+
if (src & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src, srcw));
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src, srcw));
src = TMP_FREG1;
}
- FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_SINGLE_OP) | DD4(TMP_FREG1) | DM4(src)));
-
- if (dst == SLJIT_UNUSED)
- return SLJIT_SUCCESS;
+ FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_F32_OP) | DD4(TMP_FREG1) | DM4(src)));
if (FAST_IS_REG(dst))
return push_inst32(compiler, VMOV | (1 << 20) | RT4(dst) | DN4(TMP_FREG1));
return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ op ^= SLJIT_F32_OP;
if (FAST_IS_REG(src))
FAIL_IF(push_inst32(compiler, VMOV | RT4(src) | DN4(TMP_FREG1)));
FAIL_IF(push_inst32(compiler, VMOV | RT4(TMP_REG1) | DN4(TMP_FREG1)));
}
- FAIL_IF(push_inst32(compiler, VCVT_F32_S32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(TMP_FREG1)));
+ FAIL_IF(push_inst32(compiler, VCVT_F32_S32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(TMP_FREG1)));
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
+ op ^= SLJIT_F32_OP;
+
if (src1 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src1, src1w);
+ emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w);
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src2, src2w);
+ emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w);
src2 = TMP_FREG2;
}
- FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_SINGLE_OP) | DD4(src1) | DM4(src2)));
+ FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_F32_OP) | DD4(src1) | DM4(src2)));
return push_inst32(compiler, VMRS);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- if (GET_OPCODE(op) != SLJIT_CONVD_FROMS)
- op ^= SLJIT_SINGLE_OP;
- SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100), float_transfer_bit_error);
+ SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100), float_transfer_bit_error);
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32)
+ op ^= SLJIT_F32_OP;
+
if (src & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, dst_r, src, srcw);
+ emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, dst_r, src, srcw);
src = dst_r;
}
switch (GET_OPCODE(op)) {
- case SLJIT_DMOV:
+ case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
- FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src)));
+ FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
else
dst_r = src;
}
break;
- case SLJIT_DNEG:
- FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src)));
+ case SLJIT_NEG_F64:
+ FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
break;
- case SLJIT_DABS:
- FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src)));
+ case SLJIT_ABS_F64:
+ FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
break;
- case SLJIT_CONVD_FROMS:
- FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src)));
- op ^= SLJIT_SINGLE_OP;
+ case SLJIT_CONV_F64_FROM_F32:
+ FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
+ op ^= SLJIT_F32_OP;
break;
}
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), dst_r, dst, dstw);
+ return emit_fop_mem(compiler, (op & SLJIT_F32_OP), dst_r, dst, dstw);
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- op ^= SLJIT_SINGLE_OP;
+ op ^= SLJIT_F32_OP;
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src1 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src1, src1w);
+ emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w);
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src2, src2w);
+ emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w);
src2 = TMP_FREG2;
}
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
- FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ case SLJIT_ADD_F64:
+ FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
break;
- case SLJIT_DSUB:
- FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ case SLJIT_SUB_F64:
+ FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
break;
- case SLJIT_DMUL:
- FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ case SLJIT_MUL_F64:
+ FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
break;
- case SLJIT_DDIV:
- FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ case SLJIT_DIV_F64:
+ FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
break;
}
if (!(dst & SLJIT_MEM))
return SLJIT_SUCCESS;
- return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw);
}
#undef FPU_LOAD
/* Other instructions */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
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;
+ SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
if (FAST_IS_REG(dst))
- return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG3));
+ return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2));
/* Memory. */
- if (getput_arg_fast(compiler, WORD_SIZE | STORE, TMP_REG3, dst, dstw))
- return compiler->error;
- /* TMP_REG3 is used for caching. */
- FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, TMP_REG3)));
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- return getput_arg(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, 0, 0);
+ return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, TMP_REG1);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
+ SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
if (FAST_IS_REG(src))
- FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG3, src)));
+ FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, src)));
else if (src & SLJIT_MEM) {
- if (getput_arg_fast(compiler, WORD_SIZE, TMP_REG3, src, srcw))
- FAIL_IF(compiler->error);
- else {
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- FAIL_IF(getput_arg(compiler, WORD_SIZE, TMP_REG2, src, srcw, 0, 0));
- FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG3, TMP_REG2)));
- }
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2));
}
else if (src & SLJIT_IMM)
- FAIL_IF(load_immediate(compiler, TMP_REG3, srcw));
- return push_inst16(compiler, BLX | RN3(TMP_REG3));
+ FAIL_IF(load_immediate(compiler, TMP_REG2, srcw));
+ return push_inst16(compiler, BX | RN3(TMP_REG2));
}
/* --------------------------------------------------------------------- */
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(sljit_si type)
+static sljit_uw get_cc(sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
- case SLJIT_D_EQUAL:
+ case SLJIT_EQUAL_F64:
return 0x0;
case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
- case SLJIT_D_NOT_EQUAL:
+ case SLJIT_NOT_EQUAL_F64:
return 0x1;
case SLJIT_LESS:
- case SLJIT_D_LESS:
+ case SLJIT_LESS_F64:
return 0x3;
case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
+ case SLJIT_GREATER_EQUAL_F64:
return 0x2;
case SLJIT_GREATER:
- case SLJIT_D_GREATER:
+ case SLJIT_GREATER_F64:
return 0x8;
case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
+ case SLJIT_LESS_EQUAL_F64:
return 0x9;
case SLJIT_SIG_LESS:
return 0xd;
case SLJIT_OVERFLOW:
- case SLJIT_D_UNORDERED:
+ case SLJIT_UNORDERED_F64:
return 0x6;
case SLJIT_NOT_OVERFLOW:
- case SLJIT_D_ORDERED:
+ case SLJIT_ORDERED_F64:
return 0x7;
default: /* SLJIT_JUMP */
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return 0xe;
}
}
return label;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
sljit_ins cc;
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump;
if (FAST_IS_REG(src))
return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(src));
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, src, srcw));
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, src, srcw, TMP_REG1));
if (type >= SLJIT_FAST_CALL)
return push_inst16(compiler, BLX | RN3(TMP_REG1));
}
return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1));
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_si dst_r, flags = GET_ALL_FLAGS(op);
- sljit_ins cc, ins;
+ sljit_s32 dst_r, flags = GET_ALL_FLAGS(op);
+ 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;
op = GET_OPCODE(op);
cc = get_cc(type & 0xff);
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (op < SLJIT_ADD) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4));
FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 1));
FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 0));
} else {
+ /* The movsi (immediate) instruction does not set flags in IT block. */
FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 1));
FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 0));
}
- if (dst_r != TMP_REG2)
+ if (!(dst & SLJIT_MEM))
return SLJIT_SUCCESS;
- return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw);
+ return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2);
}
- ins = (op == SLJIT_AND ? ANDI : (op == SLJIT_OR ? ORRI : EORI));
- if ((op == SLJIT_OR || op == SLJIT_XOR) && FAST_IS_REG(dst) && dst == src) {
- /* Does not change the other bits. */
+ if (dst & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2));
+
+ if (op == SLJIT_AND) {
+ FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4));
+ FAIL_IF(push_inst32(compiler, ANDI | RN4(dst_r) | RD4(dst_r) | 1));
+ FAIL_IF(push_inst32(compiler, ANDI | RN4(dst_r) | RD4(dst_r) | 0));
+ }
+ else {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
- FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst) | 1));
- if (flags & SLJIT_SET_E) {
- /* The condition must always be set, even if the ORRI/EORI is not executed above. */
- if (reg_map[dst] <= 7)
- return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst));
- return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst));
- }
+ FAIL_IF(push_inst32(compiler, ((op == SLJIT_OR) ? ORRI : EORI) | RN4(dst_r) | RD4(dst_r) | 1));
+ }
+
+ if (dst & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2));
+
+ if (!(flags & SLJIT_SET_Z))
return SLJIT_SUCCESS;
+
+ /* The condition must always be set, even if the ORR/EORI is not executed above. */
+ if (reg_map[dst_r] <= 7)
+ return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst_r));
+ return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r));
+}
+
+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_uw cc, tmp;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+ dst_reg &= ~SLJIT_I32_OP;
+
+ cc = get_cc(type & 0xff);
+
+ if (!(src & SLJIT_IMM)) {
+ FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+ return push_inst16(compiler, MOV | SET_REGS44(dst_reg, src));
}
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- if (src & SLJIT_MEM) {
- FAIL_IF(emit_op_mem2(compiler, WORD_SIZE, TMP_REG2, src, srcw, dst, dstw));
- src = TMP_REG2;
- srcw = 0;
- } else if (src & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG2, srcw));
- src = TMP_REG2;
- srcw = 0;
+ tmp = (sljit_uw) srcw;
+
+ if (tmp < 0x10000) {
+ /* set low 16 bits, set hi 16 bits to 0. */
+ FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+ return push_inst32(compiler, MOVW | RD4(dst_reg) |
+ COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff));
}
- if (op == SLJIT_AND || src != dst_r) {
- FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4));
- FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 1));
- FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 0));
+ tmp = get_imm(srcw);
+ if (tmp != INVALID_IMM) {
+ FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+ return push_inst32(compiler, MOV_WI | RD4(dst_reg) | tmp);
}
- else {
+
+ tmp = get_imm(~srcw);
+ if (tmp != INVALID_IMM) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
- FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 1));
+ return push_inst32(compiler, MVN_WI | RD4(dst_reg) | tmp);
}
- if (dst_r == TMP_REG2)
- FAIL_IF(emit_op_mem2(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, 0, 0));
+ FAIL_IF(push_inst16(compiler, IT | (cc << 4) | ((cc & 0x1) << 3) | 0x4));
- if (flags & SLJIT_SET_E) {
- /* The condition must always be set, even if the ORR/EORI is not executed above. */
- if (reg_map[dst_r] <= 7)
- return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst_r));
- return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r));
- }
- return SLJIT_SUCCESS;
+ tmp = (sljit_uw) srcw;
+ FAIL_IF(push_inst32(compiler, MOVW | RD4(dst_reg) |
+ COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff)));
+ return push_inst32(compiler, MOVT | RD4(dst_reg) |
+ COPY_BITS(tmp, 12 + 16, 16, 4) | COPY_BITS(tmp, 11 + 16, 26, 1) | COPY_BITS(tmp, 8 + 16, 12, 3) | ((tmp & 0xff0000) >> 16));
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
- sljit_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
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_imm32_const(compiler, dst_r, init_value));
if (dst & SLJIT_MEM)
- PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw));
+ PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
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_uh *inst = (sljit_uh*)addr;
- modify_imm32_const(inst, new_addr);
+ sljit_u16 *inst = (sljit_u16*)addr;
+ modify_imm32_const(inst, new_target);
+ inst = (sljit_u16 *)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_uh *inst = (sljit_uh*)addr;
+ sljit_u16 *inst = (sljit_u16*)addr;
modify_imm32_const(inst, new_constant);
+ inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 4);
}
/*
* 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:
/* mips 32-bit arch dependent functions. */
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
{
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
#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_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_si src1, sljit_sw src2)
+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_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SB) {
+ if (op == SLJIT_MOV_S8) {
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
#else
}
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_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SH) {
+ if (op == SLJIT_MOV_S16) {
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
#else
}
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)) {
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 (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;
+ }
+ 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 (!(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 (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))
- FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_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) {
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
#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);
return SLJIT_SUCCESS;
}
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
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;
+ 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;
+ 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);
}
/*
* 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:
/* mips 64-bit arch dependent functions. */
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
{
- sljit_si shift = 32;
- sljit_si shift2;
- sljit_si inv = 0;
+ sljit_s32 shift = 32;
+ sljit_s32 shift2;
+ sljit_s32 inv = 0;
sljit_ins ins;
sljit_uw uimm;
}
#define SELECT_OP(a, b) \
- (!(op & SLJIT_INT_OP) ? a : b)
+ (!(op & SLJIT_I32_OP) ? a : b)
#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_dimm, op_dimm32, op_imm, op_dv, op_v) \
if (flags & SRC2_IMM) { \
if (src2 >= 32) { \
- SLJIT_ASSERT(!(op & SLJIT_INT_OP)); \
+ SLJIT_ASSERT(!(op & SLJIT_I32_OP)); \
ins = op_dimm32; \
src2 -= 32; \
} \
else \
- ins = (op & SLJIT_INT_OP) ? op_imm : op_dimm; \
- if (op & SLJIT_SET_E) \
+ ins = (op & SLJIT_I32_OP) ? op_imm : op_dimm; \
+ 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_INT_OP) ? op_v : op_dv; \
- if (op & SLJIT_SET_E) \
+ ins = (op & SLJIT_I32_OP) ? op_v : op_dv; \
+ 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))); \
}
-static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_si src1, sljit_sw src2)
+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_ins ins;
+ sljit_s32 is_overflow, is_carry, is_handled;
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SB) {
+ if (op == SLJIT_MOV_S8) {
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
}
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_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SH) {
+ if (op == SLJIT_MOV_S16) {
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
}
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_UI:
- SLJIT_ASSERT(!(op & SLJIT_INT_OP));
+ case SLJIT_MOV_U32:
+ SLJIT_ASSERT(!(op & SLJIT_I32_OP));
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_S32:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
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)) {
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
/* Check zero. */
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
- FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_INT_OP) ? 32 : 64), UNMOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_I32_OP) ? 32 : 64), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
/* Loop for searching the highest bit. */
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 (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;
+ }
+ 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 (!(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(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))
- FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_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) {
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_INT_OP)
+ if (op & SLJIT_I32_OP)
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
return push_inst(compiler, MFLO | D(dst), DR(dst));
#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);
return SLJIT_SUCCESS;
}
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
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;
+ 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;
+ sljit_ins *inst = (sljit_ins *)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
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);
}
/*
* 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:
/* Latest MIPS architecture. */
/* Automatically detect SLJIT_MIPS_R1 */
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
/* Length of an instruction word
Both for mips-32 and mips-64 */
-typedef sljit_ui sljit_ins;
+typedef sljit_u32 sljit_ins;
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
#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 SLJIT_CONST sljit_ub 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
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+ 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
};
/* --------------------------------------------------------------------- */
#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
/* dest_reg is the absolute name of the register
Useful for reordering instructions in the delay slot. */
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_si delay_slot)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot)
{
SLJIT_ASSERT(delay_slot == MOVABLE_INS || delay_slot >= UNMOVABLE_INS
|| delay_slot == ((ins >> 11) & 0x1f) || delay_slot == ((ins >> 16) & 0x1f));
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_ins invert_branch(sljit_si flags)
+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;
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;
+
+ inst = (sljit_ins *)jump->addr;
if (jump->flags & IS_COND)
inst--;
/* 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;
}
}
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;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
+ sljit_sw executable_offset;
sljit_uw addr;
struct sljit_label *label;
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);
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;
}
#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) {
while (jump) {
do {
addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
- buf_ptr = (sljit_ins*)jump->addr;
+ 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;
}
}
compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+ 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
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 */
/* --------------------------------------------------------------------- */
#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
#include "sljitNativeMIPS_64.c"
#endif
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
sljit_ins base;
- sljit_si i, tmp, offs;
+ sljit_s32 i, tmp, offs;
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
for (i = SLJIT_S0; i >= tmp; i--) {
- offs -= (sljit_si)(sizeof(sljit_sw));
+ offs -= (sljit_s32)(sizeof(sljit_sw));
FAIL_IF(push_inst(compiler, STACK_STORE | base | T(i) | IMM(offs), MOVABLE_INS));
}
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
- offs -= (sljit_si)(sizeof(sljit_sw));
+ offs -= (sljit_s32)(sizeof(sljit_sw));
FAIL_IF(push_inst(compiler, STACK_STORE | base | T(i) | IMM(offs), MOVABLE_INS));
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si local_size, i, tmp, offs;
+ sljit_s32 local_size, i, tmp, offs;
sljit_ins base;
CHECK_ERROR();
local_size = 0;
}
- FAIL_IF(push_inst(compiler, STACK_LOAD | base | TA(RETURN_ADDR_REG) | IMM(local_size - (sljit_si)sizeof(sljit_sw)), RETURN_ADDR_REG));
- offs = local_size - (sljit_si)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
+ FAIL_IF(push_inst(compiler, STACK_LOAD | base | TA(RETURN_ADDR_REG) | IMM(local_size - (sljit_s32)sizeof(sljit_sw)), RETURN_ADDR_REG));
+ offs = local_size - (sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
tmp = compiler->scratches;
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(i) | IMM(offs), DR(i)));
- offs += (sljit_si)(sizeof(sljit_sw));
+ offs += (sljit_s32)(sizeof(sljit_sw));
}
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
for (i = tmp; i <= SLJIT_S0; i++) {
FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(i) | IMM(offs), DR(i)));
- offs += (sljit_si)(sizeof(sljit_sw));
+ offs += (sljit_s32)(sizeof(sljit_sw));
}
SLJIT_ASSERT(offs == local_size - (sljit_sw)(sizeof(sljit_sw)));
#define ARCH_32_64(a, b) b
#endif
-static SLJIT_CONST sljit_ins data_transfer_insts[16 + 4] = {
+static const sljit_ins data_transfer_insts[16 + 4] = {
/* u w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */),
/* u w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */),
/* u b s */ HI(40) /* sb */,
/* reg_ar is an absoulute register! */
/* Can perform an operation using at most 1 instruction. */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw)
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
{
SLJIT_ASSERT(arg & SLJIT_MEM);
/* See getput_arg below.
Note: can_cache is called only for binary operators. Those
operators always uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
}
/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
- sljit_si tmp_ar, base, delay_slot;
+ sljit_s32 tmp_ar, base, delay_slot;
SLJIT_ASSERT(arg & SLJIT_MEM);
if (!(next_arg & SLJIT_MEM)) {
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)
+ 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;
+ compiler->cache_argw = argw;
+ FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(TMP_REG3), DR(TMP_REG3)));
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;
- compiler->cache_argw = argw;
- FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(TMP_REG3), DR(TMP_REG3)));
- return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
- }
- FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(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);
- }
- }
- 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);
}
+ FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(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, 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;
- FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | D(TMP_REG3), DR(TMP_REG3)));
- tmp_ar = DR(TMP_REG3);
- }
- else
- 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);
+ if (arg == next_arg && argw == (next_argw & 0x3)) {
+ compiler->cache_arg = arg;
+ compiler->cache_argw = argw;
+ FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | D(TMP_REG3), DR(TMP_REG3)));
+ tmp_ar = DR(TMP_REG3);
}
- 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);
+ else
+ 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);
}
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)));
return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
}
-static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw)
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
{
if (getput_arg_fast(compiler, flags, reg_ar, arg, argw))
return compiler->error;
return getput_arg(compiler, flags, reg_ar, arg, argw, 0, 0);
}
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
{
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
return compiler->error;
return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
}
-static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
/* arg1 goes to TMP_REG1 or src reg
arg2 goes to TMP_REG2, imm or src reg
TMP_REG3 can be used for caching
result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
- sljit_si dst_r = TMP_REG2;
- sljit_si src1_r;
+ sljit_s32 dst_r = TMP_REG2;
+ sljit_s32 src1_r;
sljit_sw src2_r = 0;
- sljit_si sugg_src2_r = TMP_REG2;
+ sljit_s32 sugg_src2_r = TMP_REG2;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
}
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
- return SLJIT_SUCCESS;
- if (GET_FLAGS(op))
- flags |= UNUSED_DEST;
+ SLJIT_ASSERT(HAS_FLAGS(op));
+ flags |= UNUSED_DEST;
}
else if (FAST_IS_REG(dst)) {
dst_r = dst;
flags |= REG_DEST;
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
sugg_src2_r = dst_r;
}
else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, DR(TMP_REG1), dst, dstw))
if (FAST_IS_REG(src2)) {
src2_r = src2;
flags |= REG2_SOURCE;
- if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
dst_r = src2_r;
}
else if (src2 & SLJIT_IMM) {
}
else {
src2_r = 0;
- if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) && (dst & SLJIT_MEM))
+ if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_S32) && (dst & SLJIT_MEM))
dst_r = 0;
}
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
- sljit_si int_op = op & SLJIT_INT_OP;
+ sljit_s32 int_op = op & SLJIT_I32_OP;
#endif
CHECK_ERROR();
return push_inst(compiler, BREAK, UNMOVABLE_INS);
case SLJIT_NOP:
return push_inst(compiler, NOP, UNMOVABLE_INS);
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUMUL ? DMULTU : DMULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMULTU : DMULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
#else
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUMUL ? MULTU : MULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MULTU : MULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
#endif
FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0)));
return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
+ SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
#if !(defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
if (int_op)
- FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
else
- FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
#else
- FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
#endif
FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0)));
- return (op >= SLJIT_UDIVI) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
+ return (op >= SLJIT_DIV_UW) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+#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)
{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
# define flags 0
#else
- sljit_si flags = 0;
+ sljit_s32 flags = 0;
#endif
CHECK_ERROR();
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_INT_OP) && GET_OPCODE(op) >= SLJIT_NOT) {
+ if ((op & SLJIT_I32_OP) && GET_OPCODE(op) >= SLJIT_NOT) {
flags |= INT_DATA | SIGNED_DATA;
if (src & SLJIT_IMM)
- srcw = (sljit_si)srcw;
+ srcw = (sljit_s32)srcw;
}
#endif
case SLJIT_MOV_P:
return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_UI:
+ case SLJIT_MOV_U32:
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- return emit_op(compiler, SLJIT_MOV_UI, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
#else
- return emit_op(compiler, SLJIT_MOV_UI, INT_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ui)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u32)srcw : srcw);
#endif
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_S32:
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- return emit_op(compiler, SLJIT_MOV_SI, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
#else
- return emit_op(compiler, SLJIT_MOV_SI, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_si)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s32)srcw : srcw);
#endif
- case SLJIT_MOV_UB:
- return emit_op(compiler, SLJIT_MOV_UB, BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
+ case SLJIT_MOV_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
- case SLJIT_MOV_SB:
- return emit_op(compiler, SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
+ case SLJIT_MOV_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
- case SLJIT_MOV_UH:
- return emit_op(compiler, SLJIT_MOV_UH, HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
+ case SLJIT_MOV_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
- case SLJIT_MOV_SH:
- return emit_op(compiler, SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
+ case SLJIT_MOV_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_MOVU:
case SLJIT_MOVU_P:
return emit_op(compiler, SLJIT_MOV, WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_UI:
+ case SLJIT_MOVU_U32:
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- return emit_op(compiler, SLJIT_MOV_UI, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
#else
- return emit_op(compiler, SLJIT_MOV_UI, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ui)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u32)srcw : srcw);
#endif
- case SLJIT_MOVU_SI:
+ case SLJIT_MOVU_S32:
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- return emit_op(compiler, SLJIT_MOV_SI, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
#else
- return emit_op(compiler, SLJIT_MOV_SI, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_si)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s32)srcw : srcw);
#endif
- case SLJIT_MOVU_UB:
- return emit_op(compiler, SLJIT_MOV_UB, BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
+ case SLJIT_MOVU_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
- case SLJIT_MOVU_SB:
- return emit_op(compiler, SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
+ case SLJIT_MOVU_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
- case SLJIT_MOVU_UH:
- return emit_op(compiler, SLJIT_MOV_UH, HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
+ case SLJIT_MOVU_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
- case SLJIT_MOVU_SH:
- return emit_op(compiler, SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
+ case SLJIT_MOVU_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_NOT:
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
#endif
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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)
{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
# define flags 0
#else
- sljit_si flags = 0;
+ sljit_s32 flags = 0;
#endif
CHECK_ERROR();
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_INT_OP) {
+ if (op & SLJIT_I32_OP) {
flags |= INT_DATA | SIGNED_DATA;
if (src1 & SLJIT_IMM)
- src1w = (sljit_si)src1w;
+ src1w = (sljit_s32)src1w;
if (src2 & SLJIT_IMM)
- src2w = (sljit_si)src2w;
+ src2w = (sljit_s32)src2w;
}
#endif
src2w &= 0x1f;
#else
if (src2 & SLJIT_IMM) {
- if (op & SLJIT_INT_OP)
+ if (op & SLJIT_I32_OP)
src2w &= 0x1f;
else
src2w &= 0x3f;
#endif
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg << 1;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
/* Floating point operators */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si 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))
-#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_SINGLE_OP) >> 7))
-#define FMT(op) (((op & SLJIT_SINGLE_OP) ^ SLJIT_SINGLE_OP) << (21 - 8))
-
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
# define flags 0
#else
- sljit_si flags = (GET_OPCODE(op) == SLJIT_CONVW_FROMD) << 21;
+ sljit_s32 flags = (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64) << 21;
#endif
if (src & SLJIT_MEM) {
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);
#endif
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
# define flags 0
#else
- sljit_si flags = (GET_OPCODE(op) == SLJIT_CONVD_FROMW) << 21;
+ sljit_s32 flags = (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW) << 21;
#endif
- sljit_si dst_r = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
if (FAST_IS_REG(src))
FAIL_IF(push_inst(compiler, MTC1 | flags | T(src) | FS(TMP_FREG1), MOVABLE_INS));
}
else {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMI)
- srcw = (sljit_si)srcw;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
#endif
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG1) | FS(TMP_FREG1), MOVABLE_INS));
}
- FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | (((op & SLJIT_SINGLE_OP) ^ SLJIT_SINGLE_OP) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | (((op & SLJIT_F32_OP) ^ SLJIT_F32_OP) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
if (dst & SLJIT_MEM)
return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
#endif
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ 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;
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));
- }
- 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);
+ 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;
+ }
+
+ return push_inst(compiler, inst | FMT(op) | FT(src2) | FS(src1), UNMOVABLE_INS);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
compiler->cache_arg = 0;
compiler->cache_argw = 0;
- SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
+ SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMS)
- op ^= SLJIT_SINGLE_OP;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+ op ^= SLJIT_F32_OP;
dst_r = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
src <<= 1;
switch (GET_OPCODE(op)) {
- case SLJIT_DMOV:
+ case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
FAIL_IF(push_inst(compiler, MOV_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
dst_r = src;
}
break;
- case SLJIT_DNEG:
+ case SLJIT_NEG_F64:
FAIL_IF(push_inst(compiler, NEG_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
break;
- case SLJIT_DABS:
+ case SLJIT_ABS_F64:
FAIL_IF(push_inst(compiler, ABS_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
break;
- case SLJIT_CONVD_FROMS:
- FAIL_IF(push_inst(compiler, CVT_S_S | ((op & SLJIT_SINGLE_OP) ? 1 : (1 << 21)) | FS(src) | FD(dst_r), MOVABLE_INS));
- op ^= SLJIT_SINGLE_OP;
+ case SLJIT_CONV_F64_FROM_F32:
+ FAIL_IF(push_inst(compiler, CVT_S_S | ((op & SLJIT_F32_OP) ? 1 : (1 << 21)) | FS(src) | FD(dst_r), MOVABLE_INS));
+ op ^= SLJIT_F32_OP;
break;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r, flags = 0;
+ sljit_s32 dst_r, flags = 0;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
src2 = TMP_FREG2;
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
+ case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, ADD_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
- case SLJIT_DSUB:
+ case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, SUB_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
- case SLJIT_DMUL:
+ case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, MUL_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
- case SLJIT_DDIV:
+ case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, DIV_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
}
/* Other instructions */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
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));
return emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
flags = IS_BIT16_COND; \
delay_check = FCSR_FCC;
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
sljit_ins inst;
- sljit_si flags = 0;
- sljit_si delay_check = UNMOVABLE_INS;
+ sljit_s32 flags = 0;
+ sljit_s32 delay_check = UNMOVABLE_INS;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_jump(compiler, type));
switch (type) {
case SLJIT_EQUAL:
- case SLJIT_D_NOT_EQUAL:
BR_NZ(EQUAL_FLAG);
break;
case SLJIT_NOT_EQUAL:
- case SLJIT_D_EQUAL:
BR_Z(EQUAL_FLAG);
break;
case SLJIT_LESS:
- case SLJIT_D_LESS:
- BR_Z(ULESS_FLAG);
- break;
- case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
- BR_NZ(ULESS_FLAG);
- break;
case SLJIT_GREATER:
- case SLJIT_D_GREATER:
- BR_Z(UGREATER_FLAG);
- break;
- case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
- 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_D_UNORDERED:
- BR_F();
+ BR_NZ(OTHER_FLAG);
break;
- case SLJIT_D_ORDERED:
+ 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;
src2 = 0; \
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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)
{
struct sljit_jump *jump;
- sljit_si flags;
+ sljit_s32 flags;
sljit_ins inst;
CHECK_ERROR_PTR();
compiler->cache_arg = 0;
compiler->cache_argw = 0;
- flags = ((type & SLJIT_INT_OP) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+ flags = ((type & SLJIT_I32_OP) ? INT_DATA : WORD_DATA) | LOAD_DATA;
if (src1 & SLJIT_MEM) {
PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG1), src1, src1w, src2, src2w));
src1 = TMP_REG1;
#undef RESOLVE_IMM1
#undef RESOLVE_IMM2
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
-{
- struct sljit_jump *jump;
- sljit_ins inst;
- sljit_si if_true;
-
- CHECK_ERROR_PTR();
- 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_D_EQUAL:
- inst = C_UEQ_S;
- if_true = 1;
- break;
- case SLJIT_D_NOT_EQUAL:
- inst = C_UEQ_S;
- if_true = 0;
- break;
- case SLJIT_D_LESS:
- inst = C_ULT_S;
- if_true = 1;
- break;
- case SLJIT_D_GREATER_EQUAL:
- inst = C_ULT_S;
- if_true = 0;
- break;
- case SLJIT_D_GREATER:
- inst = C_ULE_S;
- if_true = 0;
- break;
- case SLJIT_D_LESS_EQUAL:
- inst = C_ULE_S;
- if_true = 1;
- break;
- case SLJIT_D_UNORDERED:
- inst = C_UN_S;
- if_true = 1;
- break;
- default: /* Make compilers happy. */
- SLJIT_ASSERT_STOP();
- case SLJIT_D_ORDERED:
- 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
#undef FLOAT_DATA
#undef FMT
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
- sljit_si src_r = TMP_REG2;
+ sljit_s32 src_r = TMP_REG2;
struct sljit_jump *jump = NULL;
CHECK_ERROR();
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_si sugg_dst_ar, dst_ar;
- sljit_si 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_si mem_type = (op & SLJIT_INT_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
+ 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_SI || op == SLJIT_MOV_UI)
+ 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_D_LESS:
- case SLJIT_D_GREATER_EQUAL:
- dst_ar = ULESS_FLAG;
- break;
- case SLJIT_GREATER:
- case SLJIT_LESS_EQUAL:
- case SLJIT_D_GREATER:
- case SLJIT_D_LESS_EQUAL:
- 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_D_EQUAL:
- case SLJIT_D_NOT_EQUAL:
- dst_ar = EQUAL_FLAG;
- break;
-
- case SLJIT_D_UNORDERED:
- case SLJIT_D_ORDERED:
- 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;
+ 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:
+ case SLJIT_LESS_F64:
+ case SLJIT_GREATER_EQUAL_F64:
+ case SLJIT_UNORDERED_F64:
+ case SLJIT_ORDERED_F64:
+ 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
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
- sljit_si reg;
+ sljit_s32 reg;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
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));
/*
* 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:
/* ppc 32-bit arch dependent functions. */
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
{
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
#define INS_CLEAR_LEFT(dst, src, from) \
(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
-static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_si src1, sljit_si src2)
+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_s32 src2)
{
switch (op) {
case SLJIT_MOV:
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1);
if (dst != src2)
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SB)
+ if (op == SLJIT_MOV_S8)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
}
- else if ((flags & REG_DEST) && op == SLJIT_MOV_SB)
+ else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
- case SLJIT_MOV_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SH)
+ if (op == SLJIT_MOV_S16)
return push_inst(compiler, EXTSH | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
}
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);
- return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
+
+ 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)) {
- 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;
- }
- 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;
+
+ if (flags & ALT_FORM4) {
+ if (flags & ALT_FORM5) {
+ SLJIT_ASSERT(src2 == TMP_REG2);
+ return push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm);
+ }
+ 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:
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) {
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;
}
-static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value)
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
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;
+ 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;
+ 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);
}
/*
* 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:
#define PUSH_RLDICR(reg, shift) \
push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
{
sljit_uw tmp;
sljit_uw shift;
src1 = TMP_REG1; \
}
-static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_si src1, sljit_si src2)
+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_s32 src2)
{
switch (op) {
case SLJIT_MOV:
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
return SLJIT_SUCCESS;
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SI)
+ if (op == SLJIT_MOV_S32)
return push_inst(compiler, EXTSW | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0));
}
}
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SB)
+ if (op == SLJIT_MOV_S8)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
}
- else if ((flags & REG_DEST) && op == SLJIT_MOV_SB)
+ else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
- case SLJIT_MOV_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SH)
+ if (op == SLJIT_MOV_S16)
return push_inst(compiler, EXTSH | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
}
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);
- return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
+
+ 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)) {
- 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;
- }
- 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_FORM4) {
+ if (flags & ALT_FORM5) {
+ SLJIT_ASSERT(src2 == TMP_REG2);
+ return push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
+ }
+ return push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
}
+
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));
}
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) {
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));
- }
+ 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));
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));
- }
+ 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)));
- }
- 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, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
}
+ compiler->imm &= 0x3f;
+ 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;
}
-static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value)
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
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;
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);
}
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "PowerPC" SLJIT_CPUINFO;
}
/* Length of an instruction word.
Both for ppc-32 and ppc-64. */
-typedef sljit_ui sljit_ins;
+typedef sljit_u32 sljit_ins;
#if ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && (defined _AIX)) \
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#define SLJIT_PASS_ENTRY_ADDR_TO_CALL 1
#endif
+#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
+
static void ppc_cache_flush(sljit_ins *from, sljit_ins *to)
{
#ifdef _AIX
#endif /* _AIX */
}
+#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
+
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
#define TMP_FREG1 (0)
#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
0, 3, 4, 5, 6, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 8, 9, 10, 31, 12
};
/* 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)
#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))
}
#endif
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si 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;
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)
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) {
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;
jump->flags |= PATCH_ABS32;
return 1;
}
+
if (target_addr <= 0x7fffffffffffl) {
jump->flags |= PATCH_ABS48;
return 1;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
+ sljit_sw executable_offset;
sljit_uw addr;
struct sljit_label *label;
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);
/* 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;
}
#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;
} 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;
}
while (jump) {
do {
addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
- buf_ptr = (sljit_ins*)jump->addr;
+ 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);
}
}
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);
}
}
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);
}
compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
- 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++;
+#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
- sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code);
- return code_ptr;
+ 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
- return code;
+ /* Available by default. */
+ return 1;
#endif
+
+ case SLJIT_HAS_PRE_UPDATE:
+ case SLJIT_HAS_CLZ:
+ return 1;
+
+ default:
+ return 0;
+ }
}
/* --------------------------------------------------------------------- */
#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
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"
#define STACK_LOAD LD
#endif
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si i, tmp, offs;
+ sljit_s32 i, tmp, offs;
CHECK_ERROR();
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);
FAIL_IF(push_inst(compiler, MFLR | D(0)));
- offs = -(sljit_si)(sizeof(sljit_sw));
+ offs = -(sljit_s32)(sizeof(sljit_sw));
FAIL_IF(push_inst(compiler, STACK_STORE | S(TMP_ZERO) | A(SLJIT_SP) | IMM(offs)));
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
for (i = SLJIT_S0; i >= tmp; i--) {
- offs -= (sljit_si)(sizeof(sljit_sw));
+ offs -= (sljit_s32)(sizeof(sljit_sw));
FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(SLJIT_SP) | IMM(offs)));
}
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
- offs -= (sljit_si)(sizeof(sljit_sw));
+ offs -= (sljit_s32)(sizeof(sljit_sw));
FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(SLJIT_SP) | IMM(offs)));
}
- SLJIT_ASSERT(offs == -(sljit_si)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1));
+ SLJIT_ASSERT(offs == -(sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1));
#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_SP) | IMM(2 * sizeof(sljit_sw))));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si i, tmp, offs;
+ sljit_s32 i, tmp, offs;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_SP) | IMM(sizeof(sljit_sw))));
#endif
- offs = -(sljit_si)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
+ offs = -(sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
tmp = compiler->scratches;
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
FAIL_IF(push_inst(compiler, STACK_LOAD | D(i) | A(SLJIT_SP) | IMM(offs)));
- offs += (sljit_si)(sizeof(sljit_sw));
+ offs += (sljit_s32)(sizeof(sljit_sw));
}
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
for (i = tmp; i <= SLJIT_S0; i++) {
FAIL_IF(push_inst(compiler, STACK_LOAD | D(i) | A(SLJIT_SP) | IMM(offs)));
- offs += (sljit_si)(sizeof(sljit_sw));
+ offs += (sljit_s32)(sizeof(sljit_sw));
}
FAIL_IF(push_inst(compiler, STACK_LOAD | D(TMP_ZERO) | A(SLJIT_SP) | IMM(offs)));
(((inst) & ~(INT_ALIGNED | UPDATE_REQ)) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
#endif
-static SLJIT_CONST sljit_ins data_transfer_insts[64 + 8] = {
+static const sljit_ins data_transfer_insts[64 + 8] = {
/* -------- Unsigned -------- */
#undef ARCH_32_64
/* Simple cases, (no caching is required). */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
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) {
/* See getput_arg below.
Note: can_cache is called only for binary operators. Those operator always
uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
sljit_sw high_short, next_high_short;
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#endif
/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
- sljit_si tmp_r;
+ sljit_s32 tmp_r;
sljit_ins inst;
sljit_sw high_short, next_high_short;
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#endif
arg &= REG_MASK;
- high_short = (sljit_si)(argw + ((argw & 0x8000) << 1)) & ~0xffff;
+ high_short = (sljit_s32)(argw + ((argw & 0x8000) << 1)) & ~0xffff;
/* The getput_arg_fast should handle this otherwise. */
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
SLJIT_ASSERT(high_short && high_short <= 0x7fffffffl && high_short >= -0x80000000l);
#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)));
}
else if (compiler->cache_arg != (SLJIT_MEM | arg) || high_short != compiler->cache_argw) {
if ((next_arg & SLJIT_MEM) && !(next_arg & OFFS_REG_MASK)) {
- next_high_short = (sljit_si)(next_argw + ((next_argw & 0x8000) << 1)) & ~0xffff;
+ next_high_short = (sljit_s32)(next_argw + ((next_argw & 0x8000) << 1)) & ~0xffff;
if (high_short == next_high_short) {
compiler->cache_arg = SLJIT_MEM | arg;
compiler->cache_argw = high_short;
#endif
}
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
{
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
return compiler->error;
return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
}
-static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si input_flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 input_flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
/* arg1 goes to TMP_REG1 or src reg
arg2 goes to TMP_REG2, imm or src reg
TMP_REG3 can be used for caching
result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
- sljit_si dst_r;
- sljit_si src1_r;
- sljit_si src2_r;
- sljit_si sugg_src2_r = TMP_REG2;
- sljit_si flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_FORM6 | ALT_SIGN_EXT | ALT_SET_FLAGS);
+ sljit_s32 dst_r;
+ 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_SIGN_EXT | ALT_SET_FLAGS);
if (!(input_flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
/* Destination check. */
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
- return SLJIT_SUCCESS;
dst_r = TMP_REG2;
}
else if (FAST_IS_REG(dst)) {
dst_r = dst;
flags |= REG_DEST;
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
sugg_src2_r = dst_r;
}
else {
if (FAST_IS_REG(src2)) {
src2_r = src2;
flags |= REG2_SOURCE;
- if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
dst_r = src2_r;
}
else if (src2 & SLJIT_IMM) {
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- sljit_si int_op = op & SLJIT_INT_OP;
+ sljit_s32 int_op = op & SLJIT_I32_OP;
#endif
CHECK_ERROR();
case SLJIT_BREAKPOINT:
case SLJIT_NOP:
return push_inst(compiler, NOP);
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
- return push_inst(compiler, (op == SLJIT_LUMUL ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
+ return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
#else
FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
- return push_inst(compiler, (op == SLJIT_LUMUL ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
+ return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
#endif
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_UDIVMOD ? DIVWU : DIVW) : (op == SLJIT_UDIVMOD ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
+ FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) : (op == SLJIT_DIVMOD_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
#else
- FAIL_IF(push_inst(compiler, (op == SLJIT_UDIVMOD ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
+ FAIL_IF(push_inst(compiler, (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
#endif
return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- return push_inst(compiler, (int_op ? (op == SLJIT_UDIVI ? DIVWU : DIVW) : (op == SLJIT_UDIVI ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
+ return push_inst(compiler, (int_op ? (op == SLJIT_DIV_UW ? DIVWU : DIVW) : (op == SLJIT_DIV_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
#else
- return push_inst(compiler, (op == SLJIT_UDIVI ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
+ return push_inst(compiler, (op == SLJIT_DIV_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
#endif
}
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)
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
- sljit_si flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0;
- sljit_si op_flags = GET_ALL_FLAGS(op);
+ sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
+ sljit_s32 op_flags = GET_ALL_FLAGS(op);
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)) {
+ 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_INT_OP) {
+ if (op_flags & SLJIT_I32_OP) {
if (op < SLJIT_NOT) {
if (FAST_IS_REG(src) && src == dst) {
if (!TYPE_CAST_NEEDED(op))
return SLJIT_SUCCESS;
}
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- if (op == SLJIT_MOV_SI && (src & SLJIT_MEM))
- op = SLJIT_MOV_UI;
- if (op == SLJIT_MOVU_SI && (src & SLJIT_MEM))
- op = SLJIT_MOVU_UI;
- if (op == SLJIT_MOV_UI && (src & SLJIT_IMM))
- op = SLJIT_MOV_SI;
- if (op == SLJIT_MOVU_UI && (src & SLJIT_IMM))
- op = SLJIT_MOVU_SI;
+ if (op == SLJIT_MOV_S32 && (src & SLJIT_MEM))
+ op = SLJIT_MOV_U32;
+ if (op == SLJIT_MOVU_S32 && (src & SLJIT_MEM))
+ op = SLJIT_MOVU_U32;
+ if (op == SLJIT_MOV_U32 && (src & SLJIT_IMM))
+ op = SLJIT_MOV_S32;
+ if (op == SLJIT_MOVU_U32 && (src & SLJIT_IMM))
+ op = SLJIT_MOVU_S32;
#endif
}
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
/* Most operations expect sign extended arguments. */
flags |= INT_DATA | SIGNED_DATA;
if (src & SLJIT_IMM)
- srcw = (sljit_si)srcw;
+ srcw = (sljit_s32)srcw;
+ if (HAS_FLAGS(op_flags))
+ flags |= ALT_SIGN_EXT;
}
#endif
}
case SLJIT_MOV:
case SLJIT_MOV_P:
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
#endif
return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- case SLJIT_MOV_UI:
- return EMIT_MOV(SLJIT_MOV_UI, INT_DATA, (sljit_ui));
+ case SLJIT_MOV_U32:
+ return EMIT_MOV(SLJIT_MOV_U32, INT_DATA, (sljit_u32));
- case SLJIT_MOV_SI:
- return EMIT_MOV(SLJIT_MOV_SI, INT_DATA | SIGNED_DATA, (sljit_si));
+ case SLJIT_MOV_S32:
+ return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, (sljit_s32));
#endif
- case SLJIT_MOV_UB:
- return EMIT_MOV(SLJIT_MOV_UB, BYTE_DATA, (sljit_ub));
+ case SLJIT_MOV_U8:
+ return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA, (sljit_u8));
- case SLJIT_MOV_SB:
- return EMIT_MOV(SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA, (sljit_sb));
+ case SLJIT_MOV_S8:
+ return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, (sljit_s8));
- case SLJIT_MOV_UH:
- return EMIT_MOV(SLJIT_MOV_UH, HALF_DATA, (sljit_uh));
+ case SLJIT_MOV_U16:
+ return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA, (sljit_u16));
- case SLJIT_MOV_SH:
- return EMIT_MOV(SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA, (sljit_sh));
+ case SLJIT_MOV_S16:
+ return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16));
case SLJIT_MOVU:
case SLJIT_MOVU_P:
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- case SLJIT_MOVU_UI:
- case SLJIT_MOVU_SI:
+ case SLJIT_MOVU_U32:
+ case SLJIT_MOVU_S32:
#endif
return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- case SLJIT_MOVU_UI:
- return EMIT_MOV(SLJIT_MOV_UI, INT_DATA | WRITE_BACK, (sljit_ui));
+ case SLJIT_MOVU_U32:
+ return EMIT_MOV(SLJIT_MOV_U32, INT_DATA | WRITE_BACK, (sljit_u32));
- case SLJIT_MOVU_SI:
- return EMIT_MOV(SLJIT_MOV_SI, INT_DATA | SIGNED_DATA | WRITE_BACK, (sljit_si));
+ case SLJIT_MOVU_S32:
+ return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | WRITE_BACK, (sljit_s32));
#endif
- case SLJIT_MOVU_UB:
- return EMIT_MOV(SLJIT_MOV_UB, BYTE_DATA | WRITE_BACK, (sljit_ub));
+ case SLJIT_MOVU_U8:
+ return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA | WRITE_BACK, (sljit_u8));
- case SLJIT_MOVU_SB:
- return EMIT_MOV(SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA | WRITE_BACK, (sljit_sb));
+ case SLJIT_MOVU_S8:
+ return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA | WRITE_BACK, (sljit_s8));
- case SLJIT_MOVU_UH:
- return EMIT_MOV(SLJIT_MOV_UH, HALF_DATA | WRITE_BACK, (sljit_uh));
+ case SLJIT_MOVU_U16:
+ return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA | WRITE_BACK, (sljit_u16));
- case SLJIT_MOVU_SH:
- return EMIT_MOV(SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA | WRITE_BACK, (sljit_sh));
+ case SLJIT_MOVU_S16:
+ return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA | WRITE_BACK, (sljit_s16));
case SLJIT_NOT:
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)
- return emit_op(compiler, SLJIT_CLZ, flags | (!(op_flags & SLJIT_INT_OP) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_CLZ, flags | (!(op_flags & SLJIT_I32_OP) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw);
#else
return emit_op(compiler, SLJIT_CLZ, flags, dst, dstw, TMP_REG1, 0, src, srcw);
#endif
((src) & SLJIT_IMM)
#endif
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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_si 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));
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)
src2 = TMP_ZERO;
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- if (op & SLJIT_INT_OP) {
+ if (op & SLJIT_I32_OP) {
/* Most operations expect sign extended arguments. */
flags |= INT_DATA | SIGNED_DATA;
if (src1 & SLJIT_IMM)
- src1w = (sljit_si)(src1w);
+ src1w = (sljit_s32)(src1w);
if (src2 & SLJIT_IMM)
- src2w = (sljit_si)(src2w);
- if (GET_FLAGS(op))
+ src2w = (sljit_s32)(src2w);
+ 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);
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_INT_OP on 64 bit systems. */
- 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_INT_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, 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);
+
+ 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_FORM4 | ALT_FORM5, 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);
+ return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, 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);
- }
+
+ 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_INT_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);
+ /* 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 | ((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_INT_OP)
+ 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);
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);
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);
}
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_INT_OP)
+ if (op & SLJIT_I32_OP)
flags |= ALT_FORM2;
#endif
if (src2 & SLJIT_IMM) {
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
/* Floating point operators */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si 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_SINGLE_OP) >> 6))
-#define SELECT_FOP(op, single, double) ((op & SLJIT_SINGLE_OP) ? single : double)
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 6))
+#define SELECT_FOP(op, single, double) ((op & SLJIT_F32_OP) ? single : double)
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#define FLOAT_TMP_MEM_OFFSET (6 * sizeof(sljit_sw))
#endif /* SLJIT_CONFIG_PPC_64 */
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
if (src & SLJIT_MEM) {
/* We can ignore the temporary data store on the stack from caching point of view. */
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
op = GET_OPCODE(op);
- FAIL_IF(push_inst(compiler, (op == SLJIT_CONVI_FROMD ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));
-
- if (dst == SLJIT_UNUSED)
- return SLJIT_SUCCESS;
+ FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));
- if (op == SLJIT_CONVW_FROMD) {
+ 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));
return emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, 0, 0);
}
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)) {
return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw));
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- sljit_si dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src & SLJIT_IMM) {
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMI)
- srcw = (sljit_si)srcw;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
src = TMP_REG1;
}
- else if (GET_OPCODE(op) == SLJIT_CONVD_FROMI) {
+ else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
if (FAST_IS_REG(src))
FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
else
if (dst & SLJIT_MEM)
return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
- if (op & SLJIT_SINGLE_OP)
+ if (op & SLJIT_F32_OP)
return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
return SLJIT_SUCCESS;
#else
- sljit_si dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- sljit_si invert_sign = 1;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ sljit_s32 invert_sign = 1;
if (src & SLJIT_IMM) {
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ 0x80000000));
if (dst & SLJIT_MEM)
return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
- if (op & SLJIT_SINGLE_OP)
+ if (op & SLJIT_F32_OP)
return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
return SLJIT_SUCCESS;
#endif
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
if (src1 & SLJIT_MEM) {
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
return push_inst(compiler, FCMPU | CRD(4) | FA(src1) | FB(src2));
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
compiler->cache_arg = 0;
compiler->cache_argw = 0;
- SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error);
+ SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error);
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMS)
- op ^= SLJIT_SINGLE_OP;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+ op ^= SLJIT_F32_OP;
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
}
switch (GET_OPCODE(op)) {
- case SLJIT_CONVD_FROMS:
- op ^= SLJIT_SINGLE_OP;
- if (op & SLJIT_SINGLE_OP) {
+ case SLJIT_CONV_F64_FROM_F32:
+ op ^= SLJIT_F32_OP;
+ if (op & SLJIT_F32_OP) {
FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src)));
break;
}
/* Fall through. */
- case SLJIT_DMOV:
+ case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src)));
dst_r = src;
}
break;
- case SLJIT_DNEG:
+ case SLJIT_NEG_F64:
FAIL_IF(push_inst(compiler, FNEG | FD(dst_r) | FB(src)));
break;
- case SLJIT_DABS:
+ case SLJIT_ABS_F64:
FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src)));
break;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r, flags = 0;
+ sljit_s32 dst_r, flags = 0;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
src2 = TMP_FREG2;
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
+ case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2)));
break;
- case SLJIT_DSUB:
+ case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2)));
break;
- case SLJIT_DMUL:
+ case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */));
break;
- case SLJIT_DDIV:
+ case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2)));
break;
}
/* Other instructions */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
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));
return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
return label;
}
-static sljit_ins get_bo_bi_flags(sljit_si type)
+static sljit_ins get_bo_bi_flags(sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
return (4 << 21) | (2 << 16);
case SLJIT_LESS:
- case SLJIT_D_LESS:
- return (12 << 21) | ((4 + 0) << 16);
-
- case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
- return (4 << 21) | ((4 + 0) << 16);
-
- case SLJIT_GREATER:
- case SLJIT_D_GREATER:
- return (12 << 21) | ((4 + 1) << 16);
-
- case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
- 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);
case SLJIT_MUL_NOT_OVERFLOW:
return (4 << 21) | (3 << 16);
- case SLJIT_D_EQUAL:
+ case SLJIT_EQUAL_F64:
return (12 << 21) | ((4 + 2) << 16);
- case SLJIT_D_NOT_EQUAL:
+ case SLJIT_NOT_EQUAL_F64:
return (4 << 21) | ((4 + 2) << 16);
- case SLJIT_D_UNORDERED:
+ case SLJIT_UNORDERED_F64:
return (12 << 21) | ((4 + 3) << 16);
- case SLJIT_D_ORDERED:
+ case SLJIT_ORDERED_F64:
return (4 << 21) | ((4 + 3) << 16);
default:
}
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
sljit_ins bo_bi_flags;
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump = NULL;
- sljit_si src_r;
+ sljit_s32 src_r;
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
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_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_si reg, input_flags;
- sljit_si 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_INT_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;
- }
- switch (type & 0xff) {
- case SLJIT_EQUAL:
- GET_CR_BIT(2, reg);
- break;
+ if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
+ FAIL_IF(emit_op_mem2(compiler, input_flags | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
- case SLJIT_NOT_EQUAL:
- GET_CR_BIT(2, reg);
- INVERT_BIT(reg);
- break;
+ invert = 0;
+ switch (type & 0xff) {
case SLJIT_LESS:
- case SLJIT_D_LESS:
- GET_CR_BIT(4 + 0, reg);
+ case SLJIT_SIG_LESS:
+ cr_bit = 0;
break;
case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
- 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_D_GREATER:
- GET_CR_BIT(4 + 1, reg);
+ case SLJIT_SIG_GREATER:
+ cr_bit = 1;
break;
case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
- 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);
+ case SLJIT_SIG_LESS_EQUAL:
+ cr_bit = 1;
+ invert = 1;
break;
- case SLJIT_SIG_GREATER:
- GET_CR_BIT(1, reg);
+ case SLJIT_EQUAL:
+ cr_bit = 2;
break;
- case SLJIT_SIG_LESS_EQUAL:
- GET_CR_BIT(1, reg);
- INVERT_BIT(reg);
+ 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_D_EQUAL:
- GET_CR_BIT(4 + 2, reg);
+ case SLJIT_GREATER_EQUAL_F64:
+ cr_bit = 4 + 0;
+ invert = 1;
break;
- case SLJIT_D_NOT_EQUAL:
- GET_CR_BIT(4 + 2, reg);
- INVERT_BIT(reg);
+ case SLJIT_GREATER_F64:
+ cr_bit = 4 + 1;
break;
- case SLJIT_D_UNORDERED:
- GET_CR_BIT(4 + 3, reg);
+ case SLJIT_LESS_EQUAL_F64:
+ cr_bit = 4 + 1;
+ invert = 1;
break;
- case SLJIT_D_ORDERED:
- GET_CR_BIT(4 + 3, reg);
- INVERT_BIT(reg);
+ case SLJIT_EQUAL_F64:
+ cr_bit = 4 + 2;
+ break;
+
+ case SLJIT_NOT_EQUAL_F64:
+ cr_bit = 4 + 2;
+ invert = 1;
+ break;
+
+ case SLJIT_UNORDERED_F64:
+ cr_bit = 4 + 3;
+ break;
+
+ case SLJIT_ORDERED_F64:
+ 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_UI;
- 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_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
- sljit_si reg;
+ sljit_s32 reg;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
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));
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst, sljit_sw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw imm)
{
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
-static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_si src1, sljit_sw src2)
+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_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
switch (op) {
case SLJIT_MOV:
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_UB)
+ if (op == SLJIT_MOV_U8)
return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
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_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
- return push_inst(compiler, (op == SLJIT_MOV_SH ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
+ 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:
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));
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;
}
-static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
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;
+ 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;
+ 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);
}
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "SPARC" SLJIT_CPUINFO;
}
/* Length of an instruction word
Both for sparc-32 and sparc-64 */
-typedef sljit_ui sljit_ins;
+typedef sljit_u32 sljit_ins;
+
+#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
static void sparc_cache_flush(sljit_ins *from, sljit_ins *to)
{
#endif
}
+#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
+
/* TMP_REG2 is not used by getput_arg */
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
#define TMP_FREG1 (0)
#define TMP_FREG2 ((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) << 1)
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
0, 8, 9, 10, 13, 29, 28, 27, 23, 22, 21, 20, 19, 18, 17, 16, 26, 25, 24, 14, 1, 11, 12, 15
};
/* dest_reg is the absolute name of the register
Useful for reordering instructions in the delay slot. */
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_si delay_slot)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot)
{
sljit_ins *ptr;
SLJIT_ASSERT((delay_slot & DST_INS_MASK) == UNMOVABLE_INS
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;
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--;
+ 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--;
}
}
- 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)
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
+ sljit_sw executable_offset;
sljit_uw addr;
struct sljit_label *label;
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);
/* 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;
}
#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) {
} 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;
}
SLJIT_ASSERT(!label);
SLJIT_ASSERT(!jump);
SLJIT_ASSERT(!const_);
- SLJIT_ASSERT(code_ptr - code <= (sljit_si)compiler->size);
+ SLJIT_ASSERT(code_ptr - code <= (sljit_s32)compiler->size);
jump = compiler->jumps;
while (jump) {
do {
addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
- buf_ptr = (sljit_ins*)jump->addr;
+ 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;
compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+ 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 */
/* --------------------------------------------------------------------- */
#include "sljitNativeSPARC_64.c"
#endif
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
#define ARCH_32_64(a, b) b
#endif
-static SLJIT_CONST sljit_ins data_transfer_insts[16 + 4] = {
+static const sljit_ins data_transfer_insts[16 + 4] = {
/* u w s */ ARCH_32_64(OPC1(3) | OPC3(0x04) /* stw */, OPC1(3) | OPC3(0x0e) /* stx */),
/* u w l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x0b) /* ldx */),
/* u b s */ OPC1(3) | OPC3(0x05) /* stb */,
#undef ARCH_32_64
/* Can perform an operation using at most 1 instruction. */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
SLJIT_ASSERT(arg & SLJIT_MEM);
/* See getput_arg below.
Note: can_cache is called only for binary operators. Those
operators always uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
}
/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
- sljit_si base, arg2, delay_slot;
+ sljit_s32 base, arg2, delay_slot;
sljit_ins dest;
SLJIT_ASSERT(arg & SLJIT_MEM);
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))
return push_inst(compiler, ADD | D(base) | S1(base) | S2(arg2), DR(base));
}
-static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
if (getput_arg_fast(compiler, flags, reg, arg, argw))
return compiler->error;
return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
}
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
{
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
return compiler->error;
return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
}
-static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
/* arg1 goes to TMP_REG1 or src reg
arg2 goes to TMP_REG2, imm or src reg
TMP_REG3 can be used for caching
result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
- sljit_si dst_r = TMP_REG2;
- sljit_si src1_r;
+ sljit_s32 dst_r = TMP_REG2;
+ sljit_s32 src1_r;
sljit_sw src2_r = 0;
- sljit_si sugg_src2_r = TMP_REG2;
+ sljit_s32 sugg_src2_r = TMP_REG2;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
compiler->cache_argw = 0;
}
- if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
- return SLJIT_SUCCESS;
- }
- else if (FAST_IS_REG(dst)) {
- dst_r = dst;
- flags |= REG_DEST;
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
- sugg_src2_r = dst_r;
+ if (dst != SLJIT_UNUSED) {
+ if (FAST_IS_REG(dst)) {
+ dst_r = dst;
+ flags |= REG_DEST;
+ if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
+ sugg_src2_r = dst_r;
+ }
+ else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
+ flags |= SLOW_DEST;
}
- 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) {
if (FAST_IS_REG(src2)) {
src2_r = src2;
flags |= REG2_SOURCE;
- if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
dst_r = src2_r;
}
else if (src2 & SLJIT_IMM) {
}
else {
src2_r = 0;
- if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) && (dst & SLJIT_MEM))
+ if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_S32) && (dst & SLJIT_MEM))
dst_r = 0;
}
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op0(compiler, op));
return push_inst(compiler, TA, UNMOVABLE_INS);
case SLJIT_NOP:
return push_inst(compiler, NOP, UNMOVABLE_INS);
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- FAIL_IF(push_inst(compiler, (op == SLJIT_LUMUL ? UMUL : SMUL) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
+ FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? UMUL : SMUL) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
return push_inst(compiler, RDY | D(SLJIT_R1), DR(SLJIT_R1));
#else
#error "Implementation required"
#endif
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
+ SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- if ((op | 0x2) == SLJIT_UDIVI)
+ if ((op | 0x2) == SLJIT_DIV_UW)
FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS));
else {
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_R0) | IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS));
}
- if (op <= SLJIT_SDIVMOD)
+ if (op <= SLJIT_DIVMOD_SW)
FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
- if (op >= SLJIT_UDIVI)
+ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
+ if (op >= SLJIT_DIV_UW)
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_R1) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R1)));
return push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
- sljit_si 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:
case SLJIT_MOV_P:
return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_UI:
- return emit_op(compiler, SLJIT_MOV_UI, flags | INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOV_U32:
+ return emit_op(compiler, SLJIT_MOV_U32, flags | INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_SI:
- return emit_op(compiler, SLJIT_MOV_SI, flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOV_S32:
+ return emit_op(compiler, SLJIT_MOV_S32, flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_UB:
- return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
+ case SLJIT_MOV_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
- case SLJIT_MOV_SB:
- return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
+ case SLJIT_MOV_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
- case SLJIT_MOV_UH:
- return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
+ case SLJIT_MOV_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
- case SLJIT_MOV_SH:
- return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
+ case SLJIT_MOV_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_MOVU:
case SLJIT_MOVU_P:
return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_UI:
- return emit_op(compiler, SLJIT_MOV_UI, flags | INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOVU_U32:
+ return emit_op(compiler, SLJIT_MOV_U32, flags | INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_SI:
- return emit_op(compiler, SLJIT_MOV_SI, flags | INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOVU_S32:
+ return emit_op(compiler, SLJIT_MOV_S32, flags | INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_UB:
- return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
+ case SLJIT_MOVU_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
- case SLJIT_MOVU_SB:
- return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
+ case SLJIT_MOVU_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
- case SLJIT_MOVU_UH:
- return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
+ case SLJIT_MOVU_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
- case SLJIT_MOVU_SH:
- return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
+ case SLJIT_MOVU_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_NOT:
case SLJIT_CLZ:
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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_si 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));
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:
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);
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg << 1;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
/* Floating point operators */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si 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_SINGLE_OP) >> 7))
-#define SELECT_FOP(op, single, double) ((op & SLJIT_SINGLE_OP) ? single : double)
+#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))
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
if (src & SLJIT_MEM) {
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
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);
return emit_op_mem2(compiler, SINGLE_DATA, TMP_FREG1, dst, dstw, 0, 0);
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
if (src & SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMI)
- srcw = (sljit_si)srcw;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
#endif
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
src = TMP_REG1;
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
if (src1 & SLJIT_MEM) {
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
return push_inst(compiler, SELECT_FOP(op, FCMPS, FCMPD) | S1A(src1) | S2A(src2), FCC_IS_SET | MOVABLE_INS);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
compiler->cache_arg = 0;
compiler->cache_argw = 0;
- SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
+ SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMS)
- op ^= SLJIT_SINGLE_OP;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+ op ^= SLJIT_F32_OP;
dst_r = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
src <<= 1;
switch (GET_OPCODE(op)) {
- case SLJIT_DMOV:
+ case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1) {
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_r) | S2A(src), MOVABLE_INS));
- if (!(op & SLJIT_SINGLE_OP))
+ if (!(op & SLJIT_F32_OP))
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_r | 1) | S2A(src | 1), MOVABLE_INS));
}
else
dst_r = src;
}
break;
- case SLJIT_DNEG:
+ case SLJIT_NEG_F64:
FAIL_IF(push_inst(compiler, FNEGS | DA(dst_r) | S2A(src), MOVABLE_INS));
- if (dst_r != src && !(op & SLJIT_SINGLE_OP))
+ if (dst_r != src && !(op & SLJIT_F32_OP))
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_r | 1) | S2A(src | 1), MOVABLE_INS));
break;
- case SLJIT_DABS:
+ case SLJIT_ABS_F64:
FAIL_IF(push_inst(compiler, FABSS | DA(dst_r) | S2A(src), MOVABLE_INS));
- if (dst_r != src && !(op & SLJIT_SINGLE_OP))
+ if (dst_r != src && !(op & SLJIT_F32_OP))
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_r | 1) | S2A(src | 1), MOVABLE_INS));
break;
- case SLJIT_CONVD_FROMS:
+ case SLJIT_CONV_F64_FROM_F32:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSTOD, FDTOS) | DA(dst_r) | S2A(src), MOVABLE_INS));
- op ^= SLJIT_SINGLE_OP;
+ op ^= SLJIT_F32_OP;
break;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r, flags = 0;
+ sljit_s32 dst_r, flags = 0;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
src2 = TMP_FREG2;
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
+ case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADDD) | DA(dst_r) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
- case SLJIT_DSUB:
+ case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUBD) | DA(dst_r) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
- case SLJIT_DMUL:
+ case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMULD) | DA(dst_r) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
- case SLJIT_DDIV:
+ case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIVD) | DA(dst_r) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
}
/* Other instructions */
/* --------------------------------------------------------------------- */
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
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));
return emit_op_mem(compiler, WORD_DATA, TMP_LINK, dst, dstw);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
return label;
}
-static sljit_ins get_cc(sljit_si type)
+static sljit_ins get_cc(sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
- case SLJIT_D_NOT_EQUAL: /* Unordered. */
+ case SLJIT_NOT_EQUAL_F64: /* Unordered. */
return DA(0x1);
case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
- case SLJIT_D_EQUAL:
+ case SLJIT_EQUAL_F64:
return DA(0x9);
case SLJIT_LESS:
- case SLJIT_D_GREATER: /* Unordered. */
+ case SLJIT_GREATER_F64: /* Unordered. */
return DA(0x5);
case SLJIT_GREATER_EQUAL:
- case SLJIT_D_LESS_EQUAL:
+ case SLJIT_LESS_EQUAL_F64:
return DA(0xd);
case SLJIT_GREATER:
- case SLJIT_D_GREATER_EQUAL: /* Unordered. */
+ case SLJIT_GREATER_EQUAL_F64: /* Unordered. */
return DA(0xc);
case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS:
+ case SLJIT_LESS_F64:
return DA(0x4);
case SLJIT_SIG_LESS:
return DA(0x2);
case SLJIT_OVERFLOW:
- case SLJIT_D_UNORDERED:
+ case SLJIT_UNORDERED_F64:
return DA(0x7);
case SLJIT_NOT_OVERFLOW:
- case SLJIT_D_ORDERED:
+ case SLJIT_ORDERED_F64:
return DA(0xf);
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return DA(0x8);
}
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
type &= 0xff;
- if (type < SLJIT_D_EQUAL) {
+ if (type < SLJIT_EQUAL_F64) {
jump->flags |= IS_COND;
if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & ICC_IS_SET))
jump->flags |= IS_MOVABLE;
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump = NULL;
- sljit_si src_r;
+ sljit_s32 src_r;
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
return push_inst(compiler, NOP, UNMOVABLE_INS);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_si 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_D_EQUAL)
+ if (type < SLJIT_EQUAL_F64)
FAIL_IF(push_inst(compiler, BICC | get_cc(type) | 3, UNMOVABLE_INS));
else
FAIL_IF(push_inst(compiler, FBFCC | get_cc(type) | 3, UNMOVABLE_INS));
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);
+ }
+
+ 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));
- return (reg == TMP_REG2) ? emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw) : SLJIT_SUCCESS;
+#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
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
- sljit_si reg;
+ sljit_s32 reg;
struct sljit_const *const_;
CHECK_ERROR_PTR();
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));
* 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:
* 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:
#define ADDR_TMP (SLJIT_NUMBER_OF_REGISTERS + 5)
#define PIC_ADDR_REG TMP_REG2
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
63, 0, 1, 2, 3, 4, 30, 31, 32, 33, 34, 54, 5, 16, 6, 7
};
*/
#define CHECK_FLAGS(list) (!(flags & UNUSED_DEST) || (op & GET_FLAGS(~(list))))
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char *sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char *sljit_get_platform_name(void)
{
return "TileGX" SLJIT_CPUINFO;
}
#define JOFF_X1(x) create_JumpOff_X1(x)
#define BOFF_X1(x) create_BrOff_X1(x)
-static SLJIT_CONST tilegx_mnemonic data_transfer_insts[16] = {
+static const tilegx_mnemonic data_transfer_insts[16] = {
/* u w s */ TILEGX_OPC_ST /* st */,
/* u w l */ TILEGX_OPC_LD /* ld */,
/* u b s */ TILEGX_OPC_ST1 /* st1 */,
};
#ifdef TILEGX_JIT_DEBUG
-static sljit_si push_inst_debug(struct sljit_compiler *compiler, sljit_ins ins, int line)
+static sljit_s32 push_inst_debug(struct sljit_compiler *compiler, sljit_ins ins, int line)
{
sljit_ins *ptr = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
return SLJIT_SUCCESS;
}
-static sljit_si push_inst_nodebug(struct sljit_compiler *compiler, sljit_ins ins)
+static sljit_s32 push_inst_nodebug(struct sljit_compiler *compiler, sljit_ins ins)
{
sljit_ins *ptr = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
#define push_inst(a, b) push_inst_debug(a, b, __LINE__)
#else
-static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
sljit_ins *ptr = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
return match;
}
-sljit_si assign_pipes()
+sljit_s32 assign_pipes()
{
unsigned long output_registers = 0;
unsigned int i = 0;
return bits;
}
-static sljit_si update_buffer(struct sljit_compiler *compiler)
+static sljit_s32 update_buffer(struct sljit_compiler *compiler)
{
int i;
int orig_index = inst_buf_index;
inst_buf[0] = inst1;
inst_buf_index = 1;
} else
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
#ifdef TILEGX_JIT_DEBUG
return push_inst_nodebug(compiler, bits);
return push_inst(compiler, bits);
#endif
} else
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
-static sljit_si flush_buffer(struct sljit_compiler *compiler)
+static sljit_s32 flush_buffer(struct sljit_compiler *compiler)
{
while (inst_buf_index != 0) {
FAIL_IF(update_buffer(compiler));
return SLJIT_SUCCESS;
}
-static sljit_si push_4_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int op3, int line)
+static sljit_s32 push_4_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int op3, int line)
{
if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
FAIL_IF(update_buffer(compiler));
return SLJIT_SUCCESS;
}
-static sljit_si push_3_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int line)
+static sljit_s32 push_3_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int line)
{
if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
FAIL_IF(update_buffer(compiler));
break;
default:
printf("unrecoginzed opc: %s\n", opcode->name);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
inst_buf_index++;
return SLJIT_SUCCESS;
}
-static sljit_si push_2_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int line)
+static sljit_s32 push_2_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int line)
{
if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
FAIL_IF(update_buffer(compiler));
break;
default:
printf("unrecoginzed opc: %s\n", opcode->name);
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
}
inst_buf_index++;
return SLJIT_SUCCESS;
}
-static sljit_si push_0_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int line)
+static sljit_s32 push_0_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int line)
{
if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
FAIL_IF(update_buffer(compiler));
return SLJIT_SUCCESS;
}
-static sljit_si push_jr_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int line)
+static sljit_s32 push_jr_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int line)
{
if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
FAIL_IF(update_buffer(compiler));
return code;
}
-static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
{
if (imm <= SIMM_16BIT_MAX && imm >= SIMM_16BIT_MIN)
return SHL16INSLI(dst_ar, dst_ar, imm);
}
-static sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm, int flush)
+static sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm, int flush)
{
/* Should *not* be optimized as load_immediate, as pcre relocation
mechanism will match this fixed 4-instruction pattern. */
return SHL16INSLI(dst_ar, dst_ar, imm);
}
-static sljit_si emit_const_64(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm, int flush)
+static sljit_s32 emit_const_64(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm, int flush)
{
/* Should *not* be optimized as load_immediate, as pcre relocation
mechanism will match this fixed 4-instruction pattern. */
return SHL16INSLI(reg_map[dst_ar], reg_map[dst_ar], imm);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
sljit_ins base;
- sljit_si i, tmp;
+ sljit_s32 i, tmp;
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si local_size;
+ sljit_s32 local_size;
sljit_ins base;
- sljit_si i, tmp;
- sljit_si saveds;
+ sljit_s32 i, tmp;
+ sljit_s32 saveds;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
/* reg_ar is an absoulute register! */
/* Can perform an operation using at most 1 instruction. */
-static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw)
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
{
SLJIT_ASSERT(arg & SLJIT_MEM);
/* See getput_arg below.
Note: can_cache is called only for binary operators. Those
operators always uses word arguments without write back. */
-static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
}
/* Emit the necessary instructions. See can_cache above. */
-static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
- sljit_si tmp_ar, base;
+ sljit_s32 tmp_ar, base;
SLJIT_ASSERT(arg & SLJIT_MEM);
if (!(next_arg & SLJIT_MEM)) {
return PB2(data_transfer_insts[flags & MEM_MASK], tmp_ar, reg_ar);
}
-static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw)
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
{
if (getput_arg_fast(compiler, flags, reg_ar, arg, argw))
return compiler->error;
return getput_arg(compiler, flags, reg_ar, arg, argw, 0, 0);
}
-static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
{
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
return compiler->error;
return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
return emit_op_mem(compiler, WORD_DATA, RA, dst, dstw);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
return JR(RA);
}
-static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, sljit_si dst, sljit_si src1, sljit_sw src2)
+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_si overflow_ra = 0;
+ sljit_s32 overflow_ra = 0;
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
return ADD(reg_map[dst], reg_map[src2], ZERO);
return SLJIT_SUCCESS;
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SI)
+ if (op == SLJIT_MOV_S32)
return BFEXTS(reg_map[dst], reg_map[src2], 0, 31);
return BFEXTU(reg_map[dst], reg_map[src2], 0, 31);
return SLJIT_SUCCESS;
- case SLJIT_MOV_UB:
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_U8:
+ case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SB)
+ if (op == SLJIT_MOV_S8)
return BFEXTS(reg_map[dst], reg_map[src2], 0, 7);
return BFEXTU(reg_map[dst], reg_map[src2], 0, 7);
return SLJIT_SUCCESS;
- case SLJIT_MOV_UH:
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_U16:
+ case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_SH)
+ if (op == SLJIT_MOV_S16)
return BFEXTS(reg_map[dst], reg_map[src2], 0, 15);
return BFEXTU(reg_map[dst], reg_map[src2], 0, 15);
return SLJIT_SUCCESS;
}
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
}
-static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, sljit_si dst, sljit_sw dstw, sljit_si src1, sljit_sw src1w, sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_sw dstw, sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w)
{
/* arg1 goes to TMP_REG1 or src reg.
arg2 goes to TMP_REG2, imm or src reg.
TMP_REG3 can be used for caching.
result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
- sljit_si dst_r = TMP_REG2;
- sljit_si src1_r;
+ sljit_s32 dst_r = TMP_REG2;
+ sljit_s32 src1_r;
sljit_sw src2_r = 0;
- sljit_si sugg_src2_r = TMP_REG2;
+ sljit_s32 sugg_src2_r = TMP_REG2;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
}
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
+ if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
return SLJIT_SUCCESS;
if (GET_FLAGS(op))
flags |= UNUSED_DEST;
} else if (FAST_IS_REG(dst)) {
dst_r = dst;
flags |= REG_DEST;
- if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
sugg_src2_r = dst_r;
} else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1_mapped, dst, dstw))
flags |= SLOW_DEST;
if (FAST_IS_REG(src2)) {
src2_r = src2;
flags |= REG2_SOURCE;
- if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
+ if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
dst_r = src2_r;
} else if (src2 & SLJIT_IMM) {
if (!(flags & SRC2_IMM)) {
src2_r = sugg_src2_r;
} else {
src2_r = 0;
- if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) && (dst & SLJIT_MEM))
+ if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_S32) && (dst & SLJIT_MEM))
dst_r = 0;
}
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src, sljit_sw srcw, sljit_si type)
+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_si sugg_dst_ar, dst_ar;
- sljit_si flags = GET_ALL_FLAGS(op);
- sljit_si mem_type = (op & SLJIT_INT_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
+ sljit_s32 sugg_dst_ar, dst_ar;
+ sljit_s32 flags = GET_ALL_FLAGS(op);
+ sljit_s32 mem_type = (op & SLJIT_I32_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
CHECK_ERROR();
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_SI || op == SLJIT_MOV_UI)
+ if (op == SLJIT_MOV_S32 || op == SLJIT_MOV_U32)
mem_type = INT_DATA | SIGNED_DATA;
sugg_dst_ar = reg_map[(op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2];
break;
default:
- SLJIT_ASSERT_STOP();
+ SLJIT_UNREACHABLE();
dst_ar = sugg_dst_ar;
break;
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) {
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) {
CHECK_ERROR();
CHECK(check_sljit_emit_op0(compiler, op));
case SLJIT_BREAKPOINT:
return PI(BPT);
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- SLJIT_ASSERT_STOP();
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
+ SLJIT_UNREACHABLE();
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src, sljit_sw srcw)
+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)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
case SLJIT_MOV_P:
return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_UI:
- return emit_op(compiler, SLJIT_MOV_UI, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOV_U32:
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_SI:
- return emit_op(compiler, SLJIT_MOV_SI, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOV_S32:
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOV_UB:
- return emit_op(compiler, SLJIT_MOV_UB, BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub) srcw : srcw);
+ case SLJIT_MOV_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8) srcw : srcw);
- case SLJIT_MOV_SB:
- return emit_op(compiler, SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb) srcw : srcw);
+ case SLJIT_MOV_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8) srcw : srcw);
- case SLJIT_MOV_UH:
- return emit_op(compiler, SLJIT_MOV_UH, HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh) srcw : srcw);
+ case SLJIT_MOV_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16) srcw : srcw);
- case SLJIT_MOV_SH:
- return emit_op(compiler, SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh) srcw : srcw);
+ case SLJIT_MOV_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16) srcw : srcw);
case SLJIT_MOVU:
case SLJIT_MOVU_P:
return emit_op(compiler, SLJIT_MOV, WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_UI:
- return emit_op(compiler, SLJIT_MOV_UI, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOVU_U32:
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_SI:
- return emit_op(compiler, SLJIT_MOV_SI, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+ case SLJIT_MOVU_S32:
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
- case SLJIT_MOVU_UB:
- return emit_op(compiler, SLJIT_MOV_UB, BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub) srcw : srcw);
+ case SLJIT_MOVU_U8:
+ return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8) srcw : srcw);
- case SLJIT_MOVU_SB:
- return emit_op(compiler, SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb) srcw : srcw);
+ case SLJIT_MOVU_S8:
+ return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8) srcw : srcw);
- case SLJIT_MOVU_UH:
- return emit_op(compiler, SLJIT_MOV_UH, HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh) srcw : srcw);
+ case SLJIT_MOVU_U16:
+ return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16) srcw : srcw);
- case SLJIT_MOVU_SH:
- return emit_op(compiler, SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh) srcw : srcw);
+ case SLJIT_MOVU_S16:
+ return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16) srcw : srcw);
case SLJIT_NOT:
return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);
return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
case SLJIT_CLZ:
- return emit_op(compiler, op, (op & SLJIT_INT_OP) ? INT_DATA : WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, op, (op & SLJIT_I32_OP) ? INT_DATA : WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src1, sljit_sw src1w, sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
case SLJIT_ASHR:
if (src2 & SLJIT_IMM)
src2w &= 0x3f;
- if (op & SLJIT_INT_OP)
+ if (op & SLJIT_I32_OP)
src2w &= 0x1f;
return emit_op(compiler, op, IMM_OP, dst, dstw, src1, src1w, src2, src2w);
return label;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
- sljit_si src_r = TMP_REG2;
+ sljit_s32 src_r = TMP_REG2;
struct sljit_jump *jump = NULL;
flush_buffer(compiler);
inst = BNEZ_X1 | SRCA_X1(src); \
flags = IS_COND;
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
struct sljit_jump *jump;
sljit_ins inst;
- sljit_si flags = 0;
+ sljit_s32 flags = 0;
flush_buffer(compiler);
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
-{
- return 0;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src, sljit_sw srcw)
+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_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src1, sljit_sw src1w, sljit_si src2, sljit_sw src2w)
+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_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
- sljit_si reg;
+ sljit_s32 reg;
flush_buffer(compiler);
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);
}
SLJIT_CACHE_FLUSH(inst, inst + 4);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
/*
* 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:
/* x86 32-bit arch dependent functions. */
-static sljit_si emit_do_imm(struct sljit_compiler *compiler, sljit_ub opcode, sljit_sw imm)
+static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, sljit_sw imm)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
FAIL_IF(!inst);
INC_SIZE(1 + sizeof(sljit_sw));
*inst++ = opcode;
- *(sljit_sw*)inst = imm;
+ sljit_unaligned_store_sw(inst, imm);
return SLJIT_SUCCESS;
}
-static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si 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;
if (jump->flags & JUMP_LABEL)
jump->flags |= PATCH_MW;
else
- *(sljit_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;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si size;
- sljit_ub *inst;
+ sljit_s32 size;
+ sljit_u8 *inst;
CHECK_ERROR();
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->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
size += (args > 0 ? (2 + args * 3) : 0);
#endif
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
*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)
}
#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_ub*)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_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_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);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
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;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si size;
- sljit_ub *inst;
+ sljit_s32 size;
+ sljit_u8 *inst;
CHECK_ERROR();
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_ub*)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) +
if (compiler->args > 0)
size += 2;
#endif
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
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)
/* --------------------------------------------------------------------- */
/* Size contains the flags as well. */
-static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size,
+static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
/* The register or immediate operand. */
- sljit_si a, sljit_sw imma,
+ sljit_s32 a, sljit_sw imma,
/* The general operand (not immediate). */
- sljit_si b, sljit_sw immb)
+ sljit_s32 b, sljit_sw immb)
{
- sljit_ub *inst;
- sljit_ub *buf_ptr;
- sljit_si flags = size & ~0xf;
- sljit_si inst_size;
+ sljit_u8 *inst;
+ sljit_u8 *buf_ptr;
+ sljit_s32 flags = size & ~0xf;
+ sljit_s32 inst_size;
/* Both cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
else if (immb != 0 && !(b & OFFS_REG_MASK)) {
/* Immediate operand. */
if (immb <= 127 && immb >= -128)
- inst_size += sizeof(sljit_sb);
+ inst_size += sizeof(sljit_s8);
else
inst_size += sizeof(sljit_sw);
}
else
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
- inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!inst);
/* Encoding the byte. */
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
- *(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */
+ sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
}
}
else {
*buf_ptr++ |= 0x05;
- *(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */
+ sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
if (flags & EX86_BYTE_ARG)
*buf_ptr = imma;
else if (flags & EX86_HALF_ARG)
- *(short*)buf_ptr = imma;
+ sljit_unaligned_store_s16(buf_ptr, imma);
else if (!(flags & EX86_SHIFT_INS))
- *(sljit_sw*)buf_ptr = imma;
+ sljit_unaligned_store_sw(buf_ptr, imma);
}
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
/* Call / return instructions */
/* --------------------------------------------------------------------- */
-static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type)
+static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
- inst = (sljit_ub*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2);
+ inst = (sljit_u8*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2);
FAIL_IF(!inst);
INC_SIZE(type >= SLJIT_CALL3 ? 2 + 1 : 2);
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_R2] << 3) | reg_map[SLJIT_R0];
#else
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 * (type - SLJIT_CALL0));
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 * (type - SLJIT_CALL0));
FAIL_IF(!inst);
INC_SIZE(4 * (type - SLJIT_CALL0));
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
if (FAST_IS_REG(dst)) {
/* Unused dest is possible here. */
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
CHECK_EXTRA_REGS(src, srcw, (void)0);
if (FAST_IS_REG(src)) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 1);
*inst++ = GROUP_FF;
*inst |= PUSH_rm;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
}
else {
/* SLJIT_IMM. */
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 5 + 1);
FAIL_IF(!inst);
INC_SIZE(5 + 1);
*inst++ = PUSH_i32;
- *(sljit_sw*)inst = srcw;
+ sljit_unaligned_store_sw(inst, srcw);
inst += sizeof(sljit_sw);
}
/*
* 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:
/* x86 64-bit arch dependent functions. */
-static sljit_si emit_load_imm64(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
+static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
FAIL_IF(!inst);
INC_SIZE(2 + sizeof(sljit_sw));
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
- *(sljit_sw*)inst = imm;
+ sljit_unaligned_store_sw(inst, imm);
return SLJIT_SUCCESS;
}
-static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type)
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type)
{
if (type < SLJIT_JUMP) {
/* Invert type. */
*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)
jump->flags |= PATCH_MD;
else
- *(sljit_sw*)code_ptr = jump->u.target;
+ sljit_unaligned_store_sw(code_ptr, jump->u.target);
code_ptr += sizeof(sljit_sw);
- *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_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_sw addr, sljit_si type)
-{
- sljit_sw delta = addr - ((sljit_sw)code_ptr + 1 + sizeof(sljit_si));
-
- if (delta <= HALFWORD_MAX && delta >= HALFWORD_MIN) {
- *code_ptr++ = (type == 2) ? CALL_i32 : JMP_i32;
- *(sljit_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_sw*)code_ptr = addr;
- code_ptr += sizeof(sljit_sw);
+ if (reg_map[TMP_REG2] >= 8)
*code_ptr++ = REX_B;
- *code_ptr++ = GROUP_FF;
- *code_ptr++ = (type == 2) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
- }
+ *code_ptr++ = GROUP_FF;
+ *code_ptr++ = MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2];
return code_ptr;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si i, tmp, size, saved_register_size;
- sljit_ub *inst;
+ sljit_s32 i, tmp, size, saved_register_size;
+ sljit_u8 *inst;
CHECK_ERROR();
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);
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
for (i = SLJIT_S0; i >= tmp; i--) {
size = reg_map[i] >= 8 ? 2 : 1;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
size = reg_map[i] >= 8 ? 2 : 1;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
if (args > 0) {
size = args * 3;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
#ifdef _WIN64
if (local_size > 1024) {
/* Allocate stack for the callback, which grows the stack. */
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_si)));
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_s32)));
FAIL_IF(!inst);
- INC_SIZE(4 + (3 + sizeof(sljit_si)));
+ 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. */
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];
- *(sljit_si*)inst = local_size;
+ sljit_unaligned_store_s32(inst, local_size);
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
}
#endif
- SLJIT_ASSERT(local_size > 0);
- if (local_size <= 127) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
- FAIL_IF(!inst);
- INC_SIZE(4);
- *inst++ = REX_W;
- *inst++ = GROUP_BINARY_83;
- *inst++ = MOD_REG | SUB | 4;
- *inst++ = local_size;
- }
- else {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 7);
- FAIL_IF(!inst);
- INC_SIZE(7);
- *inst++ = REX_W;
- *inst++ = GROUP_BINARY_81;
- *inst++ = MOD_REG | SUB | 4;
- *(sljit_si*)inst = local_size;
- inst += sizeof(sljit_si);
+ 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 | reg_map[SLJIT_SP];
+ *inst++ = local_size;
+ }
+ else {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
+ FAIL_IF(!inst);
+ INC_SIZE(7);
+ *inst++ = REX_W;
+ *inst++ = GROUP_BINARY_81;
+ *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 */
if (fscratches >= 6 || fsaveds >= 1) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
- *(sljit_si*)inst = 0x20247429;
+ sljit_unaligned_store_s32(inst, 0x20247429);
}
#endif
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
- sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
- sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
- sljit_si saved_register_size;
+ sljit_s32 saved_register_size;
CHECK_ERROR();
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;
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
- sljit_si i, tmp, size;
- sljit_ub *inst;
+ sljit_s32 i, tmp, size;
+ sljit_u8 *inst;
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
/* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */
if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
- *(sljit_si*)inst = 0x20247428;
+ sljit_unaligned_store_s32(inst, 0x20247428);
}
#endif
- SLJIT_ASSERT(compiler->local_size > 0);
- if (compiler->local_size <= 127) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
- FAIL_IF(!inst);
- INC_SIZE(4);
- *inst++ = REX_W;
- *inst++ = GROUP_BINARY_83;
- *inst++ = MOD_REG | ADD | 4;
- *inst = compiler->local_size;
- }
- else {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 7);
- FAIL_IF(!inst);
- INC_SIZE(7);
- *inst++ = REX_W;
- *inst++ = GROUP_BINARY_81;
- *inst++ = MOD_REG | ADD | 4;
- *(sljit_si*)inst = compiler->local_size;
+ if (compiler->local_size > 0) {
+ if (compiler->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 | ADD | 4;
+ *inst = compiler->local_size;
+ }
+ else {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
+ FAIL_IF(!inst);
+ INC_SIZE(7);
+ *inst++ = REX_W;
+ *inst++ = GROUP_BINARY_81;
+ *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++) {
size = reg_map[i] >= 8 ? 2 : 1;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
for (i = tmp; i <= SLJIT_S0; i++) {
size = reg_map[i] >= 8 ? 2 : 1;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
POP_REG(reg_lmap[i]);
}
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
RET();
/* Operators */
/* --------------------------------------------------------------------- */
-static sljit_si emit_do_imm32(struct sljit_compiler *compiler, sljit_ub rex, sljit_ub opcode, sljit_sw imm)
+static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sljit_u8 opcode, sljit_sw imm)
{
- sljit_ub *inst;
- sljit_si length = 1 + (rex ? 1 : 0) + sizeof(sljit_si);
+ sljit_u8 *inst;
+ sljit_s32 length = 1 + (rex ? 1 : 0) + sizeof(sljit_s32);
- inst = (sljit_ub*)ensure_buf(compiler, 1 + length);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + length);
FAIL_IF(!inst);
INC_SIZE(length);
if (rex)
*inst++ = rex;
*inst++ = opcode;
- *(sljit_si*)inst = imm;
+ sljit_unaligned_store_s32(inst, imm);
return SLJIT_SUCCESS;
}
-static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size,
+static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
/* The register or immediate operand. */
- sljit_si a, sljit_sw imma,
+ sljit_s32 a, sljit_sw imma,
/* The general operand (not immediate). */
- sljit_si b, sljit_sw immb)
+ sljit_s32 b, sljit_sw immb)
{
- sljit_ub *inst;
- sljit_ub *buf_ptr;
- sljit_ub rex = 0;
- sljit_si flags = size & ~0xf;
- sljit_si inst_size;
+ sljit_u8 *inst;
+ sljit_u8 *buf_ptr;
+ sljit_u8 rex = 0;
+ sljit_s32 flags = size & ~0xf;
+ sljit_s32 inst_size;
/* The immediate operand must be 32 bit. */
SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
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);
}
if ((b & REG_MASK) == SLJIT_UNUSED)
- inst_size += 1 + sizeof(sljit_si); /* SIB byte required to avoid RIP based addressing. */
+ inst_size += 1 + sizeof(sljit_s32); /* SIB byte required to avoid RIP based addressing. */
else {
if (reg_map[b & REG_MASK] >= 8)
rex |= REX_B;
if (immb != 0 && (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP))) {
/* Immediate operand. */
if (immb <= 127 && immb >= -128)
- inst_size += sizeof(sljit_sb);
+ inst_size += sizeof(sljit_s8);
else
- inst_size += sizeof(sljit_si);
+ inst_size += sizeof(sljit_s32);
}
else if (reg_lmap[b & REG_MASK] == 5)
- inst_size += sizeof(sljit_sb);
+ inst_size += sizeof(sljit_s8);
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
inst_size += 1; /* SIB byte. */
else if (flags & EX86_HALF_ARG)
inst_size += sizeof(short);
else
- inst_size += sizeof(sljit_si);
+ inst_size += sizeof(sljit_s32);
}
else {
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
if (rex)
inst_size++;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!inst);
/* Encoding the byte. */
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
- *(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */
- buf_ptr += sizeof(sljit_si);
+ sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
+ buf_ptr += sizeof(sljit_s32);
}
}
}
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = 0x25;
- *(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */
- buf_ptr += sizeof(sljit_si);
+ sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
+ buf_ptr += sizeof(sljit_s32);
}
if (a & SLJIT_IMM) {
if (flags & EX86_BYTE_ARG)
*buf_ptr = imma;
else if (flags & EX86_HALF_ARG)
- *(short*)buf_ptr = imma;
+ sljit_unaligned_store_s16(buf_ptr, imma);
else if (!(flags & EX86_SHIFT_INS))
- *(sljit_si*)buf_ptr = imma;
+ sljit_unaligned_store_s32(buf_ptr, imma);
}
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
/* Call / return instructions */
/* --------------------------------------------------------------------- */
-static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type)
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
{
- sljit_ub *inst;
+ 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_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
+ 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];
*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_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
+ 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];
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
if (FAST_IS_REG(dst)) {
if (reg_map[dst] < 8) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
POP_REG(reg_lmap[dst]);
return SLJIT_SUCCESS;
}
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
*inst++ = REX_B;
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
if (FAST_IS_REG(src)) {
if (reg_map[src] < 8) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 1);
PUSH_REG(reg_lmap[src]);
}
else {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 1);
FAIL_IF(!inst);
INC_SIZE(2 + 1);
*inst++ = GROUP_FF;
*inst |= PUSH_rm;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
}
else {
SLJIT_ASSERT(IS_HALFWORD(srcw));
/* SLJIT_IMM. */
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 5 + 1);
FAIL_IF(!inst);
INC_SIZE(5 + 1);
*inst++ = PUSH_i32;
- *(sljit_si*)inst = srcw;
- inst += sizeof(sljit_si);
+ sljit_unaligned_store_s32(inst, srcw);
+ inst += sizeof(sljit_s32);
}
RET();
/* Extend input */
/* --------------------------------------------------------------------- */
-static sljit_si emit_mov_int(struct sljit_compiler *compiler, sljit_si sign,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
- sljit_si dst_r;
+ sljit_u8* inst;
+ sljit_s32 dst_r;
compiler->mode32 = 0;
if (src & SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw);
+ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_i32;
return SLJIT_SUCCESS;
return emit_load_imm64(compiler, dst, srcw);
}
compiler->mode32 = 1;
- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw);
+ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_i32;
compiler->mode32 = 0;
/*
* 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:
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void)
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "x86" SLJIT_CPUINFO;
}
/* Last register + 1. */
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = {
- 0, 0, 2, 1, 0, 0, 0, 0, 7, 6, 3, 4, 5
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = {
+ 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 7, 6, 3, 4, 5
};
#define CHECK_EXTRA_REGS(p, w, do) \
- if (p >= SLJIT_R3 && p <= SLJIT_R6) { \
- w = SLJIT_LOCALS_OFFSET + ((p) - (SLJIT_R3 + 4)) * sizeof(sljit_sw); \
+ if (p >= SLJIT_R3 && p <= SLJIT_S3) { \
+ if (p <= compiler->scratches) \
+ w = compiler->saveds_offset - ((p) - SLJIT_R2) * (sljit_sw)sizeof(sljit_sw); \
+ else \
+ w = compiler->locals_offset + ((p) - SLJIT_S2) * (sljit_sw)sizeof(sljit_sw); \
p = SLJIT_MEM1(SLJIT_SP); \
do; \
}
/* Last register + 1. */
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
-#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
/* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present
Note: avoid to use r12 and r13 for memory addessing
- therefore r12 is better for SAVED_EREG than SAVED_REG. */
+ therefore r12 is better to be a higher saved register. */
#ifndef _WIN64
-/* 1st passed in rdi, 2nd argument passed in rsi, 3rd in rdx. */
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
- 0, 0, 6, 1, 8, 11, 10, 12, 5, 13, 14, 15, 3, 4, 2, 7, 9
+/* Args: rdi(=7), rsi(=6), rdx(=2), rcx(=1), r8, r9. Scratches: rax(=0), r10, r11 */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+ 0, 0, 6, 1, 7, 8, 11, 10, 12, 5, 13, 14, 15, 3, 4, 2, 9
};
/* low-map. reg_map & 0x7. */
-static SLJIT_CONST sljit_ub reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 5] = {
- 0, 0, 6, 1, 0, 3, 2, 4, 5, 5, 6, 7, 3, 4, 2, 7, 1
+static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+ 0, 0, 6, 1, 7, 0, 3, 2, 4, 5, 5, 6, 7, 3, 4, 2, 1
};
#else
-/* 1st passed in rcx, 2nd argument passed in rdx, 3rd in r8. */
-static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
- 0, 0, 2, 1, 11, 12, 5, 13, 14, 15, 7, 6, 3, 4, 10, 8, 9
+/* Args: rcx(=1), rdx(=2), r8, r9. Scratches: rax(=0), r10, r11 */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+ 0, 0, 2, 1, 10, 11, 12, 5, 13, 14, 15, 7, 6, 3, 4, 8, 9
};
/* low-map. reg_map & 0x7. */
-static SLJIT_CONST sljit_ub reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 5] = {
- 0, 0, 2, 1, 3, 4, 5, 5, 6, 7, 7, 6, 3, 4, 2, 0, 1
+static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+ 0, 0, 2, 1, 2, 3, 4, 5, 5, 6, 7, 7, 6, 3, 4, 0, 1
};
#endif
#define CALL_i32 0xe8
#define CALL_rm (/* GROUP_FF */ 2 << 3)
#define CDQ 0x99
-#define CMOVNE_r_rm (/* GROUP_0F */ 0x45)
+#define CMOVE_r_rm (/* GROUP_0F */ 0x44)
#define CMP (/* BINARY */ 7 << 3)
#define CMP_EAX_i32 0x3d
#define CMP_r_rm 0x3b
#define POP_r 0x58
#define POP_rm 0x8f
#define POPF 0x9d
+#define PREFETCH 0x18
#define PUSH_i32 0x68
#define PUSH_r 0x50
#define PUSH_rm (/* GROUP_FF */ 6 << 3)
built-in CPU features. Therefore they can be overwritten by different threads
if they detect the CPU features in the same time. */
#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
-static sljit_si cpu_has_sse2 = -1;
+static sljit_s32 cpu_has_sse2 = -1;
#endif
-static sljit_si cpu_has_cmov = -1;
+static sljit_s32 cpu_has_cmov = -1;
#ifdef _WIN32_WCE
#include <cmnintrin.h>
#include <intrin.h>
#endif
+/******************************************************/
+/* Unaligned-store functions */
+/******************************************************/
+
+static SLJIT_INLINE void sljit_unaligned_store_s16(void *addr, sljit_s16 value)
+{
+ SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+static SLJIT_INLINE void sljit_unaligned_store_s32(void *addr, sljit_s32 value)
+{
+ SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+static SLJIT_INLINE void sljit_unaligned_store_sw(void *addr, sljit_sw value)
+{
+ SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+/******************************************************/
+/* Utility functions */
+/******************************************************/
+
static void get_cpu_features(void)
{
- sljit_ui features;
+ sljit_u32 features;
#if defined(_MSC_VER) && _MSC_VER >= 1400
int CPUInfo[4];
__cpuid(CPUInfo, 1);
- features = (sljit_ui)CPUInfo[3];
+ features = (sljit_u32)CPUInfo[3];
#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C)
cpu_has_cmov = (features >> 15) & 0x1;
}
-static sljit_ub get_jump_code(sljit_si type)
+static sljit_u8 get_jump_code(sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
- case SLJIT_D_EQUAL:
+ case SLJIT_EQUAL_F64:
return 0x84 /* je */;
case SLJIT_NOT_EQUAL:
- case SLJIT_D_NOT_EQUAL:
+ case SLJIT_NOT_EQUAL_F64:
return 0x85 /* jne */;
case SLJIT_LESS:
- case SLJIT_D_LESS:
+ case SLJIT_LESS_F64:
return 0x82 /* jc */;
case SLJIT_GREATER_EQUAL:
- case SLJIT_D_GREATER_EQUAL:
+ case SLJIT_GREATER_EQUAL_F64:
return 0x83 /* jae */;
case SLJIT_GREATER:
- case SLJIT_D_GREATER:
+ case SLJIT_GREATER_F64:
return 0x87 /* jnbe */;
case SLJIT_LESS_EQUAL:
- case SLJIT_D_LESS_EQUAL:
+ case SLJIT_LESS_EQUAL_F64:
return 0x86 /* jbe */;
case SLJIT_SIG_LESS:
case SLJIT_MUL_NOT_OVERFLOW:
return 0x81 /* jno */;
- case SLJIT_D_UNORDERED:
+ case SLJIT_UNORDERED_F64:
return 0x8a /* jp */;
- case SLJIT_D_ORDERED:
+ case SLJIT_ORDERED_F64:
return 0x8b /* jpo */;
}
return 0;
}
-static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type);
-
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
-static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_sw addr, sljit_si type);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type, sljit_sw executable_offset);
+#else
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type);
#endif
-static sljit_ub* generate_near_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_ub *code, sljit_si type)
+static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_s32 type, sljit_sw executable_offset)
{
- sljit_si short_jump;
+ sljit_s32 short_jump;
sljit_uw label_addr;
if (jump->flags & JUMP_LABEL)
label_addr = (sljit_uw)(code + jump->u.label->size);
else
- label_addr = jump->u.target;
+ label_addr = jump->u.target - executable_offset;
+
short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (short_jump) {
jump->flags |= PATCH_MB;
- code_ptr += sizeof(sljit_sb);
+ code_ptr += sizeof(sljit_s8);
} else {
jump->flags |= PATCH_MW;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
code_ptr += sizeof(sljit_sw);
#else
- code_ptr += sizeof(sljit_si);
+ code_ptr += sizeof(sljit_s32);
#endif
}
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
{
struct sljit_memory_fragment *buf;
- sljit_ub *code;
- sljit_ub *code_ptr;
- sljit_ub *buf_ptr;
- sljit_ub *buf_end;
- sljit_ub len;
+ sljit_u8 *code;
+ sljit_u8 *code_ptr;
+ sljit_u8 *buf_ptr;
+ sljit_u8 *buf_end;
+ sljit_u8 len;
+ sljit_sw executable_offset;
+ sljit_sw jump_addr;
struct sljit_label *label;
struct sljit_jump *jump;
reverse_buf(compiler);
/* Second code generation pass. */
- code = (sljit_ub*)SLJIT_MALLOC_EXEC(compiler->size);
+ code = (sljit_u8*)SLJIT_MALLOC_EXEC(compiler->size);
PTR_FAIL_WITH_EXEC_IF(code);
buf = compiler->buf;
label = compiler->labels;
jump = compiler->jumps;
const_ = compiler->consts;
+ executable_offset = SLJIT_EXEC_OFFSET(code);
+
do {
buf_ptr = buf->memory;
buf_end = buf_ptr + buf->used_size;
len = *buf_ptr++;
if (len > 0) {
/* The code is already generated. */
- SLJIT_MEMMOVE(code_ptr, buf_ptr, len);
+ SLJIT_MEMCPY(code_ptr, buf_ptr, len);
code_ptr += len;
buf_ptr += len;
}
else {
- if (*buf_ptr >= 4) {
+ if (*buf_ptr >= 2) {
jump->addr = (sljit_uw)code_ptr;
if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
- code_ptr = generate_near_jump_code(jump, code_ptr, code, *buf_ptr - 4);
- else
- code_ptr = generate_far_jump_code(jump, code_ptr, *buf_ptr - 4);
+ code_ptr = generate_near_jump_code(jump, code_ptr, code, *buf_ptr - 2, executable_offset);
+ else {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ code_ptr = generate_far_jump_code(jump, code_ptr, *buf_ptr - 2, executable_offset);
+#else
+ code_ptr = generate_far_jump_code(jump, code_ptr, *buf_ptr - 2);
+#endif
+ }
jump = jump->next;
}
else if (*buf_ptr == 0) {
- label->addr = (sljit_uw)code_ptr;
+ label->addr = ((sljit_uw)code_ptr) + executable_offset;
label->size = code_ptr - code;
label = label->next;
}
- else if (*buf_ptr == 1) {
+ else { /* *buf_ptr is 1 */
const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw);
const_ = const_->next;
}
- else {
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *code_ptr++ = (*buf_ptr == 2) ? CALL_i32 : JMP_i32;
- buf_ptr++;
- *(sljit_sw*)code_ptr = *(sljit_sw*)buf_ptr - ((sljit_sw)code_ptr + sizeof(sljit_sw));
- code_ptr += sizeof(sljit_sw);
- buf_ptr += sizeof(sljit_sw) - 1;
-#else
- code_ptr = generate_fixed_jump(code_ptr, *(sljit_sw*)(buf_ptr + 1), *buf_ptr);
- buf_ptr += sizeof(sljit_sw);
-#endif
- }
buf_ptr++;
}
} while (buf_ptr < buf_end);
jump = compiler->jumps;
while (jump) {
+ jump_addr = jump->addr + executable_offset;
+
if (jump->flags & PATCH_MB) {
- SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sb))) >= -128 && (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sb))) <= 127);
- *(sljit_ub*)jump->addr = (sljit_ub)(jump->u.label->addr - (jump->addr + sizeof(sljit_sb)));
+ SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))) >= -128 && (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))) <= 127);
+ *(sljit_u8*)jump->addr = (sljit_u8)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8)));
} else if (jump->flags & PATCH_MW) {
if (jump->flags & JUMP_LABEL) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *(sljit_sw*)jump->addr = (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sw)));
+ sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_sw))));
#else
- SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_si))) >= HALFWORD_MIN && (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_si))) <= HALFWORD_MAX);
- *(sljit_si*)jump->addr = (sljit_si)(jump->u.label->addr - (jump->addr + sizeof(sljit_si)));
+ SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))) <= HALFWORD_MAX);
+ sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))));
#endif
}
else {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *(sljit_sw*)jump->addr = (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_sw)));
+ sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_sw))));
#else
- SLJIT_ASSERT((sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_si))) >= HALFWORD_MIN && (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_si))) <= HALFWORD_MAX);
- *(sljit_si*)jump->addr = (sljit_si)(jump->u.target - (jump->addr + sizeof(sljit_si)));
+ SLJIT_ASSERT((sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_s32))) <= HALFWORD_MAX);
+ sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.target - (jump_addr + sizeof(sljit_s32))));
#endif
}
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
else if (jump->flags & PATCH_MD)
- *(sljit_sw*)jump->addr = jump->u.label->addr;
+ sljit_unaligned_store_sw((void*)jump->addr, jump->u.label->addr);
#endif
jump = jump->next;
}
- /* Maybe we waste some space because of short jumps. */
+ /* Some space may be wasted because of short jumps. */
SLJIT_ASSERT(code_ptr <= code + compiler->size);
compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
compiler->executable_size = code_ptr - code;
- return (void*)code;
+ return (void*)(code + executable_offset);
}
-/* --------------------------------------------------------------------- */
-/* Operators */
-/* --------------------------------------------------------------------- */
-
-static sljit_si emit_cum_binary(struct sljit_compiler *compiler,
- sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+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 SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+ if (cpu_has_sse2 == -1)
+ get_cpu_features();
+ return cpu_has_sse2;
+#else /* SLJIT_DETECT_SSE2 */
+ return 1;
+#endif /* SLJIT_DETECT_SSE2 */
-static sljit_si emit_non_cum_binary(struct sljit_compiler *compiler,
- sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ case SLJIT_HAS_VIRTUAL_REGISTERS:
+ return 1;
+#endif
-static sljit_si emit_mov(struct sljit_compiler *compiler,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw);
+ case SLJIT_HAS_CLZ:
+ case SLJIT_HAS_CMOV:
+ if (cpu_has_cmov == -1)
+ get_cpu_features();
+ return cpu_has_cmov;
-static SLJIT_INLINE sljit_si emit_save_flags(struct sljit_compiler *compiler)
-{
- sljit_ub *inst;
+ case SLJIT_HAS_PREF_SHIFT_REG:
+ return 1;
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
- FAIL_IF(!inst);
- INC_SIZE(5);
+ case SLJIT_HAS_SSE2:
+#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+ if (cpu_has_sse2 == -1)
+ get_cpu_features();
+ return cpu_has_sse2;
#else
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 6);
- FAIL_IF(!inst);
- INC_SIZE(6);
- *inst++ = REX_W;
-#endif
- *inst++ = LEA_r_m; /* lea esp/rsp, [esp/rsp + sizeof(sljit_sw)] */
- *inst++ = 0x64;
- *inst++ = 0x24;
- *inst++ = (sljit_ub)sizeof(sljit_sw);
- *inst++ = PUSHF;
- compiler->flags_saved = 1;
- return SLJIT_SUCCESS;
+ return 1;
+#endif
+
+ default:
+ return 0;
+ }
}
-static SLJIT_INLINE sljit_si emit_restore_flags(struct sljit_compiler *compiler, sljit_si keep_flags)
-{
- sljit_ub *inst;
+/* --------------------------------------------------------------------- */
+/* Operators */
+/* --------------------------------------------------------------------- */
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
- FAIL_IF(!inst);
- INC_SIZE(5);
- *inst++ = POPF;
-#else
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 6);
- FAIL_IF(!inst);
- INC_SIZE(6);
- *inst++ = POPF;
- *inst++ = REX_W;
-#endif
- *inst++ = LEA_r_m; /* lea esp/rsp, [esp/rsp - sizeof(sljit_sw)] */
- *inst++ = 0x64;
- *inst++ = 0x24;
- *inst++ = (sljit_ub)-(sljit_sb)sizeof(sljit_sw);
- compiler->flags_saved = keep_flags;
- return SLJIT_SUCCESS;
-}
+static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
+ sljit_u8 op_rm, sljit_u8 op_mr, sljit_u8 op_imm, sljit_u8 op_eax_imm,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w);
+
+static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
+ sljit_u8 op_rm, sljit_u8 op_mr, sljit_u8 op_imm, sljit_u8 op_eax_imm,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w);
+
+static sljit_s32 emit_mov(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw);
+
+#define EMIT_MOV(compiler, dst, dstw, src, srcw) \
+ FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw));
#ifdef _WIN32
#include <malloc.h>
CPU cycles if the stack is large enough. However, you don't know it in
advance, so it must always be called. I think this is a bad design in
general even if it has some reasons. */
- *(volatile sljit_si*)alloca(local_size) = 0;
+ *(volatile sljit_s32*)alloca(local_size) = 0;
}
#endif
#include "sljitNativeX86_64.c"
#endif
-static sljit_si emit_mov(struct sljit_compiler *compiler,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static sljit_s32 emit_mov(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
+ sljit_u8* inst;
+
+ SLJIT_ASSERT(dst != SLJIT_UNUSED);
- if (dst == SLJIT_UNUSED) {
- /* No destination, doesn't need to setup flags. */
- if (src & SLJIT_MEM) {
- inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src, srcw);
- FAIL_IF(!inst);
- *inst = MOV_r_rm;
- }
- return SLJIT_SUCCESS;
- }
if (FAST_IS_REG(src)) {
inst = emit_x86_instruction(compiler, 1, src, 0, dst, dstw);
FAIL_IF(!inst);
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (!compiler->mode32 && NOT_HALFWORD(srcw)) {
- FAIL_IF(emit_load_imm64(compiler, TMP_REG2, srcw));
- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, dst, dstw);
+ /* Immediate to memory move. Only SLJIT_MOV operation copies
+ an immediate directly into memory so TMP_REG1 can be used. */
+ FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
+ inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_r;
return SLJIT_SUCCESS;
return SLJIT_SUCCESS;
}
- /* Memory to memory move. Requires two instruction. */
+ /* Memory to memory move. Only SLJIT_MOV operation copies
+ data from memory to memory so TMP_REG1 can be used. */
inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src, srcw);
FAIL_IF(!inst);
*inst = MOV_r_rm;
return SLJIT_SUCCESS;
}
-#define EMIT_MOV(compiler, dst, dstw, src, srcw) \
- FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw));
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- sljit_si size;
+ sljit_s32 size;
#endif
CHECK_ERROR();
switch (GET_OPCODE(op)) {
case SLJIT_BREAKPOINT:
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
*inst = INT3;
break;
case SLJIT_NOP:
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
*inst = NOP;
break;
- case SLJIT_LUMUL:
- case SLJIT_LSMUL:
- case SLJIT_UDIVMOD:
- case SLJIT_SDIVMOD:
- case SLJIT_UDIVI:
- case SLJIT_SDIVI:
- compiler->flags_saved = 0;
+ case SLJIT_LMUL_UW:
+ case SLJIT_LMUL_SW:
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_UW:
+ case SLJIT_DIV_SW:
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
#ifdef _WIN64
- SLJIT_COMPILE_ASSERT(
+ SLJIT_ASSERT(
reg_map[SLJIT_R0] == 0
&& reg_map[SLJIT_R1] == 2
- && reg_map[TMP_REG1] > 7,
- invalid_register_assignment_for_div_mul);
+ && reg_map[TMP_REG1] > 7);
#else
- SLJIT_COMPILE_ASSERT(
+ SLJIT_ASSERT(
reg_map[SLJIT_R0] == 0
&& reg_map[SLJIT_R1] < 7
- && reg_map[TMP_REG1] == 2,
- invalid_register_assignment_for_div_mul);
+ && reg_map[TMP_REG1] == 2);
#endif
- compiler->mode32 = op & SLJIT_INT_OP;
+ compiler->mode32 = op & SLJIT_I32_OP;
#endif
- SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments);
+ SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
op = GET_OPCODE(op);
- if ((op | 0x2) == SLJIT_UDIVI) {
+ if ((op | 0x2) == SLJIT_DIV_UW) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64)
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0);
inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0);
*inst = XOR_r_rm;
}
- if ((op | 0x2) == SLJIT_SDIVI) {
+ if ((op | 0x2) == SLJIT_DIV_SW) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64)
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0);
#endif
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
*inst = CDQ;
#else
if (compiler->mode32) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
*inst = CDQ;
} else {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
*inst++ = REX_W;
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
*inst++ = GROUP_F7;
- *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
+ *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
#else
#ifdef _WIN64
- size = (!compiler->mode32 || op >= SLJIT_UDIVMOD) ? 3 : 2;
+ size = (!compiler->mode32 || op >= SLJIT_DIVMOD_UW) ? 3 : 2;
#else
size = (!compiler->mode32) ? 3 : 2;
#endif
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
#ifdef _WIN64
if (!compiler->mode32)
- *inst++ = REX_W | ((op >= SLJIT_UDIVMOD) ? REX_B : 0);
- else if (op >= SLJIT_UDIVMOD)
+ *inst++ = REX_W | ((op >= SLJIT_DIVMOD_UW) ? REX_B : 0);
+ else if (op >= SLJIT_DIVMOD_UW)
*inst++ = REX_B;
*inst++ = GROUP_F7;
- *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
+ *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
#else
if (!compiler->mode32)
*inst++ = REX_W;
#endif
#endif
switch (op) {
- case SLJIT_LUMUL:
+ case SLJIT_LMUL_UW:
*inst |= MUL;
break;
- case SLJIT_LSMUL:
+ case SLJIT_LMUL_SW:
*inst |= IMUL;
break;
- case SLJIT_UDIVMOD:
- case SLJIT_UDIVI:
+ case SLJIT_DIVMOD_UW:
+ case SLJIT_DIV_UW:
*inst |= DIV;
break;
- case SLJIT_SDIVMOD:
- case SLJIT_SDIVI:
+ case SLJIT_DIVMOD_SW:
+ case SLJIT_DIV_SW:
*inst |= IDIV;
break;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64)
- if (op <= SLJIT_SDIVMOD)
+ if (op <= SLJIT_DIVMOD_SW)
EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
#else
- if (op >= SLJIT_UDIVI)
+ if (op >= SLJIT_DIV_UW)
EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
#endif
break;
#define ENCODE_PREFIX(prefix) \
do { \
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); \
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); \
FAIL_IF(!inst); \
INC_SIZE(1); \
*inst = (prefix); \
} while (0)
-static sljit_si emit_mov_byte(struct sljit_compiler *compiler, sljit_si sign,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static sljit_s32 emit_mov_byte(struct sljit_compiler *compiler, sljit_s32 sign,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
- sljit_si dst_r;
+ sljit_u8* inst;
+ sljit_s32 dst_r;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_si work_r;
+ sljit_s32 work_r;
#endif
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
#endif
- if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
- return SLJIT_SUCCESS; /* Empty instruction. */
-
if (src & SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
return SLJIT_SUCCESS;
}
-static sljit_si emit_mov_half(struct sljit_compiler *compiler, sljit_si sign,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static sljit_s32 emit_prefetch(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
- sljit_si dst_r;
+ sljit_u8* inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = 0;
+ compiler->mode32 = 1;
#endif
- if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
- return SLJIT_SUCCESS; /* Empty instruction. */
+ inst = emit_x86_instruction(compiler, 2, 0, 0, src, srcw);
+ FAIL_IF(!inst);
+ *inst++ = GROUP_0F;
+ *inst++ = PREFETCH;
+
+ if (op >= SLJIT_MOV_U8 && op <= SLJIT_MOV_S8)
+ *inst |= (3 << 3);
+ else if (op >= SLJIT_MOV_U16 && op <= SLJIT_MOV_S16)
+ *inst |= (2 << 3);
+ else
+ *inst |= (1 << 3);
+
+ return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_mov_half(struct sljit_compiler *compiler, sljit_s32 sign,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_u8* inst;
+ sljit_s32 dst_r;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 0;
+#endif
if (src & SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
return SLJIT_SUCCESS;
}
-static sljit_si emit_unary(struct sljit_compiler *compiler, sljit_ub opcode,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static sljit_s32 emit_unary(struct sljit_compiler *compiler, sljit_u8 opcode,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
+ sljit_u8* inst;
- if (dst == SLJIT_UNUSED) {
- EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= opcode;
- return SLJIT_SUCCESS;
- }
if (dst == src && dstw == srcw) {
/* Same input and output */
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
*inst |= opcode;
return SLJIT_SUCCESS;
}
+
+ if (dst == SLJIT_UNUSED)
+ dst = TMP_REG1;
+
if (FAST_IS_REG(dst)) {
EMIT_MOV(compiler, dst, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
+ inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0);
FAIL_IF(!inst);
*inst++ = GROUP_F7;
*inst |= opcode;
return SLJIT_SUCCESS;
}
+
EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
FAIL_IF(!inst);
return SLJIT_SUCCESS;
}
-static sljit_si emit_not_with_flags(struct sljit_compiler *compiler,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static sljit_s32 emit_not_with_flags(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
+ sljit_u8* inst;
+
+ if (dst == SLJIT_UNUSED)
+ dst = TMP_REG1;
- if (dst == SLJIT_UNUSED) {
- EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= NOT_rm;
- inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG1, 0);
- FAIL_IF(!inst);
- *inst = OR_r_rm;
- return SLJIT_SUCCESS;
- }
if (FAST_IS_REG(dst)) {
EMIT_MOV(compiler, dst, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
+ inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0);
FAIL_IF(!inst);
*inst++ = GROUP_F7;
*inst |= NOT_rm;
*inst = OR_r_rm;
return SLJIT_SUCCESS;
}
+
EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
FAIL_IF(!inst);
return SLJIT_SUCCESS;
}
-static sljit_si emit_clz(struct sljit_compiler *compiler, sljit_si op_flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+static const sljit_sw emit_clz_arg = 32 + 31;
+#endif
+
+static sljit_s32 emit_clz(struct sljit_compiler *compiler, sljit_s32 op_flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_ub* inst;
- sljit_si dst_r;
+ sljit_u8* inst;
+ sljit_s32 dst_r;
SLJIT_UNUSED_ARG(op_flags);
- if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
- /* Just set the zero flag. */
- EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= NOT_rm;
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 31, TMP_REG1, 0);
-#else
- inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, !(op_flags & SLJIT_INT_OP) ? 63 : 31, TMP_REG1, 0);
-#endif
- FAIL_IF(!inst);
- *inst |= SHR;
- return SLJIT_SUCCESS;
- }
if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw);
srcw = 0;
}
- inst = emit_x86_instruction(compiler, 2, TMP_REG1, 0, src, srcw);
+ if (cpu_has_cmov == -1)
+ get_cpu_features();
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+ inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = GROUP_0F;
*inst = BSR_r_rm;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (FAST_IS_REG(dst))
- dst_r = dst;
- else {
- /* Find an unused temporary register. */
- if ((dst & REG_MASK) != SLJIT_R0 && (dst & OFFS_REG_MASK) != TO_OFFS_REG(SLJIT_R0))
- dst_r = SLJIT_R0;
- else if ((dst & REG_MASK) != SLJIT_R1 && (dst & OFFS_REG_MASK) != TO_OFFS_REG(SLJIT_R1))
- dst_r = SLJIT_R1;
+ if (cpu_has_cmov) {
+ if (dst_r != TMP_REG1) {
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 32 + 31);
+ inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG1, 0);
+ }
else
- dst_r = SLJIT_R2;
- EMIT_MOV(compiler, dst, dstw, dst_r, 0);
- }
- EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, 32 + 31);
-#else
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
- compiler->mode32 = 0;
- EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, !(op_flags & SLJIT_INT_OP) ? 64 + 63 : 32 + 31);
- compiler->mode32 = op_flags & SLJIT_INT_OP;
-#endif
-
- if (cpu_has_cmov == -1)
- get_cpu_features();
+ inst = emit_x86_instruction(compiler, 2, dst_r, 0, SLJIT_MEM0(), (sljit_sw)&emit_clz_arg);
- if (cpu_has_cmov) {
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG1, 0);
FAIL_IF(!inst);
*inst++ = GROUP_0F;
- *inst = CMOVNE_r_rm;
- } else {
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
- FAIL_IF(!inst);
- INC_SIZE(4);
+ *inst = CMOVE_r_rm;
+ }
+ else
+ FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, 32 + 31));
- *inst++ = JE_i8;
- *inst++ = 2;
- *inst++ = MOV_r_rm;
- *inst++ = MOD_REG | (reg_map[dst_r] << 3) | reg_map[TMP_REG1];
+ inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0);
#else
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
- FAIL_IF(!inst);
- INC_SIZE(5);
+ if (cpu_has_cmov) {
+ EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, !(op_flags & SLJIT_I32_OP) ? (64 + 63) : (32 + 31));
- *inst++ = JE_i8;
- *inst++ = 3;
- *inst++ = REX_W | (reg_map[dst_r] >= 8 ? REX_R : 0) | (reg_map[TMP_REG1] >= 8 ? REX_B : 0);
- *inst++ = MOV_r_rm;
- *inst++ = MOD_REG | (reg_lmap[dst_r] << 3) | reg_lmap[TMP_REG1];
-#endif
+ inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
+ FAIL_IF(!inst);
+ *inst++ = GROUP_0F;
+ *inst = CMOVE_r_rm;
}
+ else
+ FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, !(op_flags & SLJIT_I32_OP) ? (64 + 63) : (32 + 31)));
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0);
-#else
- inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, !(op_flags & SLJIT_INT_OP) ? 63 : 31, dst_r, 0);
+ inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, !(op_flags & SLJIT_I32_OP) ? 63 : 31, dst_r, 0);
#endif
+
FAIL_IF(!inst);
*(inst + 1) |= XOR;
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (dst & SLJIT_MEM) {
- inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
- FAIL_IF(!inst);
- *inst = XCHG_r_rm;
- }
-#else
if (dst & SLJIT_MEM)
- EMIT_MOV(compiler, dst, dstw, TMP_REG2, 0);
-#endif
+ EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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)
{
- sljit_ub* inst;
- sljit_si update = 0;
- sljit_si op_flags = GET_ALL_FLAGS(op);
+ sljit_s32 update = 0;
+ sljit_s32 op_flags = GET_ALL_FLAGS(op);
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_si dst_is_ereg = 0;
- sljit_si src_is_ereg = 0;
+ sljit_s32 dst_is_ereg = 0;
+ sljit_s32 src_is_ereg = 0;
#else
# define src_is_ereg 0
#endif
CHECK_EXTRA_REGS(dst, dstw, dst_is_ereg = 1);
CHECK_EXTRA_REGS(src, srcw, src_is_ereg = 1);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = op_flags & SLJIT_INT_OP;
+ compiler->mode32 = op_flags & SLJIT_I32_OP;
#endif
+ if (dst == SLJIT_UNUSED && !HAS_FLAGS(op)) {
+ if (op <= SLJIT_MOV_P && (src & SLJIT_MEM))
+ return emit_prefetch(compiler, op, src, srcw);
+ return SLJIT_SUCCESS;
+ }
+
op = GET_OPCODE(op);
+
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_P) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
#endif
- if (op_flags & SLJIT_INT_OP) {
+ if (op_flags & SLJIT_I32_OP) {
if (FAST_IS_REG(src) && src == dst) {
if (!TYPE_CAST_NEEDED(op))
return SLJIT_SUCCESS;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (op == SLJIT_MOV_SI && (src & SLJIT_MEM))
- op = SLJIT_MOV_UI;
- if (op == SLJIT_MOVU_SI && (src & SLJIT_MEM))
- op = SLJIT_MOVU_UI;
- if (op == SLJIT_MOV_UI && (src & SLJIT_IMM))
- op = SLJIT_MOV_SI;
- if (op == SLJIT_MOVU_UI && (src & SLJIT_IMM))
- op = SLJIT_MOVU_SI;
+ if (op == SLJIT_MOV_S32 && (src & SLJIT_MEM))
+ op = SLJIT_MOV_U32;
+ if (op == SLJIT_MOVU_S32 && (src & SLJIT_MEM))
+ op = SLJIT_MOVU_U32;
+ if (op == SLJIT_MOV_U32 && (src & SLJIT_IMM))
+ op = SLJIT_MOV_S32;
+ if (op == SLJIT_MOVU_U32 && (src & SLJIT_IMM))
+ op = SLJIT_MOVU_S32;
#endif
}
if (src & SLJIT_IMM) {
switch (op) {
- case SLJIT_MOV_UB:
- srcw = (sljit_ub)srcw;
+ case SLJIT_MOV_U8:
+ srcw = (sljit_u8)srcw;
break;
- case SLJIT_MOV_SB:
- srcw = (sljit_sb)srcw;
+ case SLJIT_MOV_S8:
+ srcw = (sljit_s8)srcw;
break;
- case SLJIT_MOV_UH:
- srcw = (sljit_uh)srcw;
+ case SLJIT_MOV_U16:
+ srcw = (sljit_u16)srcw;
break;
- case SLJIT_MOV_SH:
- srcw = (sljit_sh)srcw;
+ case SLJIT_MOV_S16:
+ srcw = (sljit_s16)srcw;
break;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- case SLJIT_MOV_UI:
- srcw = (sljit_ui)srcw;
+ case SLJIT_MOV_U32:
+ srcw = (sljit_u32)srcw;
break;
- case SLJIT_MOV_SI:
- srcw = (sljit_si)srcw;
+ case SLJIT_MOV_S32:
+ srcw = (sljit_s32)srcw;
break;
#endif
}
#endif
}
- if (SLJIT_UNLIKELY(update) && (src & SLJIT_MEM) && !src_is_ereg && (src & REG_MASK) && (srcw != 0 || (src & OFFS_REG_MASK) != 0)) {
- inst = emit_x86_instruction(compiler, 1, src & REG_MASK, 0, src, srcw);
- FAIL_IF(!inst);
- *inst = LEA_r_m;
- src &= SLJIT_MEM | 0xf;
- srcw = 0;
- }
-
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (SLJIT_UNLIKELY(dst_is_ereg) && (!(op == SLJIT_MOV || op == SLJIT_MOV_UI || op == SLJIT_MOV_SI || op == SLJIT_MOV_P) || (src & SLJIT_MEM))) {
+ if (SLJIT_UNLIKELY(dst_is_ereg) && (!(op == SLJIT_MOV || op == SLJIT_MOV_U32 || op == SLJIT_MOV_S32 || op == SLJIT_MOV_P) || (src & SLJIT_MEM))) {
SLJIT_ASSERT(dst == SLJIT_MEM1(SLJIT_SP));
dst = TMP_REG1;
}
case SLJIT_MOV:
case SLJIT_MOV_P:
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- case SLJIT_MOV_UI:
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
#endif
FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw));
break;
- case SLJIT_MOV_UB:
+ case SLJIT_MOV_U8:
FAIL_IF(emit_mov_byte(compiler, 0, dst, dstw, src, srcw));
break;
- case SLJIT_MOV_SB:
+ case SLJIT_MOV_S8:
FAIL_IF(emit_mov_byte(compiler, 1, dst, dstw, src, srcw));
break;
- case SLJIT_MOV_UH:
+ case SLJIT_MOV_U16:
FAIL_IF(emit_mov_half(compiler, 0, dst, dstw, src, srcw));
break;
- case SLJIT_MOV_SH:
+ case SLJIT_MOV_S16:
FAIL_IF(emit_mov_half(compiler, 1, dst, dstw, src, srcw));
break;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- case SLJIT_MOV_UI:
+ case SLJIT_MOV_U32:
FAIL_IF(emit_mov_int(compiler, 0, dst, dstw, src, srcw));
break;
- case SLJIT_MOV_SI:
+ case SLJIT_MOV_S32:
FAIL_IF(emit_mov_int(compiler, 1, dst, dstw, src, srcw));
break;
#endif
return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), dstw, TMP_REG1, 0);
#endif
- if (SLJIT_UNLIKELY(update) && (dst & SLJIT_MEM) && (dst & REG_MASK) && (dstw != 0 || (dst & OFFS_REG_MASK) != 0)) {
- inst = emit_x86_instruction(compiler, 1, dst & REG_MASK, 0, dst, dstw);
- FAIL_IF(!inst);
- *inst = LEA_r_m;
+ if (SLJIT_UNLIKELY(update) && (src & SLJIT_MEM) && !src_is_ereg && (src & REG_MASK)) {
+ if ((src & OFFS_REG_MASK) != 0) {
+ FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
+ (src & REG_MASK), 0, (src & REG_MASK), 0, OFFS_REG(dst), 0));
+ }
+ else if (srcw != 0) {
+ FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
+ (src & REG_MASK), 0, (src & REG_MASK), 0, SLJIT_IMM, srcw));
+ }
+ }
+
+ if (SLJIT_UNLIKELY(update) && (dst & SLJIT_MEM) && (dst & REG_MASK)) {
+ if ((dst & OFFS_REG_MASK) != 0) {
+ FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
+ (dst & REG_MASK), 0, (dst & REG_MASK), 0, OFFS_REG(dst), 0));
+ }
+ else if (dstw != 0) {
+ FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
+ (dst & REG_MASK), 0, (dst & REG_MASK), 0, SLJIT_IMM, dstw));
+ }
}
return SLJIT_SUCCESS;
}
- if (SLJIT_UNLIKELY(GET_FLAGS(op_flags)))
- compiler->flags_saved = 0;
-
switch (op) {
case SLJIT_NOT:
- if (SLJIT_UNLIKELY(op_flags & SLJIT_SET_E))
+ if (SLJIT_UNLIKELY(op_flags & SLJIT_SET_Z))
return emit_not_with_flags(compiler, dst, dstw, src, srcw);
return emit_unary(compiler, NOT_rm, dst, dstw, src, srcw);
case SLJIT_NEG:
- if (SLJIT_UNLIKELY(op_flags & SLJIT_KEEP_FLAGS) && !compiler->flags_saved)
- FAIL_IF(emit_save_flags(compiler));
return emit_unary(compiler, NEG_rm, dst, dstw, src, srcw);
case SLJIT_CLZ:
- if (SLJIT_UNLIKELY(op_flags & SLJIT_KEEP_FLAGS) && !compiler->flags_saved)
- FAIL_IF(emit_save_flags(compiler));
return emit_clz(compiler, op_flags, dst, dstw, src, srcw);
}
*(inst + 1) |= (op_imm); \
} \
else { \
- FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immw)); \
- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, arg, argw); \
+ FAIL_IF(emit_load_imm64(compiler, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, immw)); \
+ inst = emit_x86_instruction(compiler, 1, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, 0, arg, argw); \
FAIL_IF(!inst); \
*inst = (op_mr); \
}
#endif
-static sljit_si emit_cum_binary(struct sljit_compiler *compiler,
- sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
+ sljit_u8 op_rm, sljit_u8 op_mr, sljit_u8 op_imm, sljit_u8 op_eax_imm,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
+ sljit_u8* inst;
if (dst == SLJIT_UNUSED) {
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
return SLJIT_SUCCESS;
}
-static sljit_si emit_non_cum_binary(struct sljit_compiler *compiler,
- sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
+ sljit_u8 op_rm, sljit_u8 op_mr, sljit_u8 op_imm, sljit_u8 op_eax_imm,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
+ sljit_u8* inst;
if (dst == SLJIT_UNUSED) {
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
return SLJIT_SUCCESS;
}
-static sljit_si emit_mul(struct sljit_compiler *compiler,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_mul(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
- sljit_si dst_r;
+ sljit_u8* inst;
+ sljit_s32 dst_r;
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
/* Register destination. */
if (dst_r == src1 && !(src2 & SLJIT_IMM)) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i8;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
- *inst = (sljit_sb)src1w;
+ *inst = (sljit_s8)src1w;
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
else {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i32;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_sw*)inst = src1w;
+ sljit_unaligned_store_sw(inst, src1w);
}
#else
else if (IS_HALFWORD(src1w)) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i32;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_si*)inst = (sljit_si)src1w;
+ sljit_unaligned_store_s32(inst, (sljit_s32)src1w);
}
else {
- EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, src1w);
if (dst_r != src2)
EMIT_MOV(compiler, dst_r, 0, src2, src2w);
+ FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w));
inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
FAIL_IF(!inst);
*inst++ = GROUP_0F;
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i8;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
- *inst = (sljit_sb)src2w;
+ *inst = (sljit_s8)src2w;
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
else {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i32;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_sw*)inst = src2w;
+ sljit_unaligned_store_sw(inst, src2w);
}
#else
else if (IS_HALFWORD(src2w)) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i32;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_si*)inst = (sljit_si)src2w;
+ sljit_unaligned_store_s32(inst, (sljit_s32)src2w);
}
else {
- EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, src2w);
if (dst_r != src1)
EMIT_MOV(compiler, dst_r, 0, src1, src1w);
+ FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w));
inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
FAIL_IF(!inst);
*inst++ = GROUP_0F;
*inst = IMUL_r_rm;
}
- if (dst_r == TMP_REG1)
+ if (dst & SLJIT_MEM)
EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
-static sljit_si emit_lea_binary(struct sljit_compiler *compiler, sljit_si keep_flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_lea_binary(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
- sljit_si dst_r, done = 0;
+ sljit_u8* inst;
+ sljit_s32 dst_r, done = 0;
/* These cases better be left to handled by normal way. */
- if (!keep_flags) {
- if (dst == src1 && dstw == src1w)
- return SLJIT_ERR_UNSUPPORTED;
- if (dst == src2 && dstw == src2w)
- return SLJIT_ERR_UNSUPPORTED;
- }
+ if (dst == src1 && dstw == src1w)
+ return SLJIT_ERR_UNSUPPORTED;
+ if (dst == src2 && dstw == src2w)
+ return SLJIT_ERR_UNSUPPORTED;
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if ((src2 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src2w))) {
- inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (sljit_si)src2w);
+ inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (sljit_s32)src2w);
#else
if (src2 & SLJIT_IMM) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), src2w);
else if (FAST_IS_REG(src2)) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if ((src1 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src1w))) {
- inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (sljit_si)src1w);
+ inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (sljit_s32)src1w);
#else
if (src1 & SLJIT_IMM) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), src1w);
return SLJIT_ERR_UNSUPPORTED;
}
-static sljit_si emit_cmp_binary(struct sljit_compiler *compiler,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
+ sljit_u8* inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
return SLJIT_SUCCESS;
}
-static sljit_si emit_test_binary(struct sljit_compiler *compiler,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_test_binary(struct sljit_compiler *compiler,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
+ sljit_u8* inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (src2 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
+ if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
#else
if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128)) {
#endif
*inst = GROUP_F7;
}
else {
- FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w));
- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, src1w);
+ FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src2w));
+ inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src1, src1w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
}
*inst = GROUP_F7;
}
else {
- FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w));
- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, src2w);
+ FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src1w));
+ inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
}
return SLJIT_SUCCESS;
}
-static sljit_si emit_shift(struct sljit_compiler *compiler,
- sljit_ub mode,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_shift(struct sljit_compiler *compiler,
+ sljit_u8 mode,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- sljit_ub* inst;
+ sljit_u8* inst;
if ((src2 & SLJIT_IMM) || (src2 == SLJIT_PREF_SHIFT_REG)) {
if (dst == src1 && dstw == src1w) {
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
}
else {
- /* This case is really difficult, since ecx itself may used for
- addressing, and we must ensure to work even in that case. */
+ /* This case is complex since ecx itself may be used for
+ addressing, and this case must be supported as well. */
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0);
-#else
- /* [esp+0] contains the flags. */
- EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_sw), SLJIT_PREF_SHIFT_REG, 0);
-#endif
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_PREF_SHIFT_REG, 0);
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
FAIL_IF(!inst);
*inst |= mode;
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0);
+ EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), 0);
+ EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
#else
- EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_sw));
-#endif
+ EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+ EMIT_MOV(compiler, TMP_REG2, 0, src2, src2w);
+ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0);
+ FAIL_IF(!inst);
+ *inst = XCHG_r_rm;
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+ FAIL_IF(!inst);
+ *inst |= mode;
+ EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0);
EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+#endif
}
return SLJIT_SUCCESS;
}
-static sljit_si emit_shift_with_flags(struct sljit_compiler *compiler,
- sljit_ub mode, sljit_si set_flags,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static sljit_s32 emit_shift_with_flags(struct sljit_compiler *compiler,
+ sljit_u8 mode, sljit_s32 set_flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
/* The CPU does not set flags if the shift count is 0. */
if (src2 & SLJIT_IMM) {
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(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)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
CHECK_EXTRA_REGS(src1, src1w, (void)0);
CHECK_EXTRA_REGS(src2, src2w, (void)0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = op & SLJIT_INT_OP;
+ compiler->mode32 = op & SLJIT_I32_OP;
#endif
- if (GET_OPCODE(op) >= SLJIT_MUL) {
- if (SLJIT_UNLIKELY(GET_FLAGS(op)))
- compiler->flags_saved = 0;
- else if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS) && !compiler->flags_saved)
- FAIL_IF(emit_save_flags(compiler));
- }
+ if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+ return SLJIT_SUCCESS;
switch (GET_OPCODE(op)) {
case SLJIT_ADD:
- if (!GET_FLAGS(op)) {
- if (emit_lea_binary(compiler, op & SLJIT_KEEP_FLAGS, dst, dstw, src1, src1w, src2, src2w) != SLJIT_ERR_UNSUPPORTED)
+ if (!HAS_FLAGS(op)) {
+ if (emit_lea_binary(compiler, dst, dstw, src1, src1w, src2, src2w) != SLJIT_ERR_UNSUPPORTED)
return compiler->error;
}
- else
- compiler->flags_saved = 0;
- if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS) && !compiler->flags_saved)
- FAIL_IF(emit_save_flags(compiler));
return emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_ADDC:
- if (SLJIT_UNLIKELY(compiler->flags_saved)) /* C flag must be restored. */
- FAIL_IF(emit_restore_flags(compiler, 1));
- else if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS))
- FAIL_IF(emit_save_flags(compiler));
- if (SLJIT_UNLIKELY(GET_FLAGS(op)))
- compiler->flags_saved = 0;
return emit_cum_binary(compiler, ADC_r_rm, ADC_rm_r, ADC, ADC_EAX_i32,
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SUB:
- if (!GET_FLAGS(op)) {
- if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, op & SLJIT_KEEP_FLAGS, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED)
+ if (!HAS_FLAGS(op)) {
+ if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED)
return compiler->error;
}
- else
- compiler->flags_saved = 0;
- if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS) && !compiler->flags_saved)
- FAIL_IF(emit_save_flags(compiler));
+
if (dst == SLJIT_UNUSED)
return emit_cmp_binary(compiler, src1, src1w, src2, src2w);
return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SUBC:
- if (SLJIT_UNLIKELY(compiler->flags_saved)) /* C flag must be restored. */
- FAIL_IF(emit_restore_flags(compiler, 1));
- else if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS))
- FAIL_IF(emit_save_flags(compiler));
- if (SLJIT_UNLIKELY(GET_FLAGS(op)))
- compiler->flags_saved = 0;
return emit_non_cum_binary(compiler, SBB_r_rm, SBB_rm_r, SBB, SBB_EAX_i32,
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_MUL:
return emit_cum_binary(compiler, XOR_r_rm, XOR_rm_r, XOR, XOR_EAX_i32,
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SHL:
- return emit_shift_with_flags(compiler, SHL, GET_FLAGS(op),
+ return emit_shift_with_flags(compiler, SHL, HAS_FLAGS(op),
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_LSHR:
- return emit_shift_with_flags(compiler, SHR, GET_FLAGS(op),
+ return emit_shift_with_flags(compiler, SHR, HAS_FLAGS(op),
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_ASHR:
- return emit_shift_with_flags(compiler, SAR, GET_FLAGS(op),
+ return emit_shift_with_flags(compiler, SAR, HAS_FLAGS(op),
dst, dstw, src1, src1w, src2, src2w);
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (reg >= SLJIT_R3 && reg <= SLJIT_R6)
+ if (reg >= SLJIT_R3 && reg <= SLJIT_R8)
return -1;
#endif
return reg_map[reg];
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
return reg;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_si size)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_s32 size)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
- inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
- SLJIT_MEMMOVE(inst, instruction, size);
+ SLJIT_MEMCPY(inst, instruction, size);
return SLJIT_SUCCESS;
}
/* Floating point operators */
/* --------------------------------------------------------------------- */
-/* Alignment + 2 * 16 bytes. */
-static sljit_si sse2_data[3 + (4 + 4) * 2];
-static sljit_si *sse2_buffer;
+/* Alignment(3) + 4 * 16 bytes. */
+static sljit_s32 sse2_data[3 + (4 * 4)];
+static sljit_s32 *sse2_buffer;
static void init_compiler(void)
{
- sse2_buffer = (sljit_si*)(((sljit_uw)sse2_data + 15) & ~0xf);
- /* Single precision constants. */
+ /* Align to 16 bytes. */
+ sse2_buffer = (sljit_s32*)(((sljit_uw)sse2_data + 15) & ~0xf);
+
+ /* Single precision constants (each constant is 16 byte long). */
sse2_buffer[0] = 0x80000000;
sse2_buffer[4] = 0x7fffffff;
- /* Double precision constants. */
+ /* Double precision constants (each constant is 16 byte long). */
sse2_buffer[8] = 0;
sse2_buffer[9] = 0x80000000;
sse2_buffer[12] = 0xffffffff;
sse2_buffer[13] = 0x7fffffff;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
-{
-#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
-#elif (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
- if (cpu_has_sse2 == -1)
- get_cpu_features();
- return cpu_has_sse2;
-#else /* SLJIT_DETECT_SSE2 */
- return 1;
-#endif /* SLJIT_DETECT_SSE2 */
-}
-
-static sljit_si emit_sse2(struct sljit_compiler *compiler, sljit_ub opcode,
- sljit_si single, sljit_si xmm1, sljit_si xmm2, sljit_sw xmm2w)
+static sljit_s32 emit_sse2(struct sljit_compiler *compiler, sljit_u8 opcode,
+ sljit_s32 single, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
inst = emit_x86_instruction(compiler, 2 | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, xmm1, 0, xmm2, xmm2w);
FAIL_IF(!inst);
return SLJIT_SUCCESS;
}
-static sljit_si emit_sse2_logic(struct sljit_compiler *compiler, sljit_ub opcode,
- sljit_si pref66, sljit_si xmm1, sljit_si xmm2, sljit_sw xmm2w)
+static sljit_s32 emit_sse2_logic(struct sljit_compiler *compiler, sljit_u8 opcode,
+ sljit_s32 pref66, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
inst = emit_x86_instruction(compiler, 2 | (pref66 ? EX86_PREF_66 : 0) | EX86_SSE2, xmm1, 0, xmm2, xmm2w);
FAIL_IF(!inst);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si emit_sse2_load(struct sljit_compiler *compiler,
- sljit_si single, sljit_si dst, sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 emit_sse2_load(struct sljit_compiler *compiler,
+ sljit_s32 single, sljit_s32 dst, sljit_s32 src, sljit_sw srcw)
{
return emit_sse2(compiler, MOVSD_x_xm, single, dst, src, srcw);
}
-static SLJIT_INLINE sljit_si emit_sse2_store(struct sljit_compiler *compiler,
- sljit_si single, sljit_si dst, sljit_sw dstw, sljit_si src)
+static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler,
+ sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src)
{
return emit_sse2(compiler, MOVSD_xm_x, single, src, dst, dstw);
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convw_fromd(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
- sljit_ub *inst;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ sljit_u8 *inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONVW_FROMD)
+ if (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64)
compiler->mode32 = 0;
#endif
- inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_SINGLE_OP) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP2, dst_r, 0, src, srcw);
+ inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_F32_OP) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP2, dst_r, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = GROUP_0F;
*inst = CVTTSD2SI_r_xm;
- if (dst_r == TMP_REG1 && dst != SLJIT_UNUSED)
+ if (dst & SLJIT_MEM)
return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_convd_fromw(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- sljit_si dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
- sljit_ub *inst;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+ sljit_u8 *inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMW)
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)
compiler->mode32 = 0;
#endif
if (src & SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMI)
- srcw = (sljit_si)srcw;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
#endif
EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
src = TMP_REG1;
srcw = 0;
}
- inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_SINGLE_OP) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP1, dst_r, 0, src, srcw);
+ inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_F32_OP) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP1, dst_r, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = GROUP_0F;
*inst = CVTSI2SD_x_rm;
compiler->mode32 = 1;
#endif
if (dst_r == TMP_FREG)
- return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG);
+ return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_si sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_si op,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
{
- compiler->flags_saved = 0;
if (!FAST_IS_REG(src1)) {
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src1, src1w));
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src1, src1w));
src1 = TMP_FREG;
}
- return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_SINGLE_OP), src1, src2, src2w);
+ return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_F32_OP), src1, src2, src2w);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw)
+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_si dst_r;
+ sljit_s32 dst_r;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 1;
CHECK_ERROR();
SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
- if (GET_OPCODE(op) == SLJIT_DMOV) {
+ if (GET_OPCODE(op) == SLJIT_MOV_F64) {
if (FAST_IS_REG(dst))
- return emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst, src, srcw);
+ return emit_sse2_load(compiler, op & SLJIT_F32_OP, dst, src, srcw);
if (FAST_IS_REG(src))
- return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, src);
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src, srcw));
- return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG);
+ return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, src);
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src, srcw));
+ return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
}
- if (GET_OPCODE(op) == SLJIT_CONVD_FROMS) {
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) {
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
if (FAST_IS_REG(src)) {
/* We overwrite the high bits of source. From SLJIT point of view,
this is not an issue.
Note: In SSE3, we could also use MOVDDUP and MOVSLDUP. */
- FAIL_IF(emit_sse2_logic(compiler, UNPCKLPD_x_xm, op & SLJIT_SINGLE_OP, src, src, 0));
+ FAIL_IF(emit_sse2_logic(compiler, UNPCKLPD_x_xm, op & SLJIT_F32_OP, src, src, 0));
}
else {
- FAIL_IF(emit_sse2_load(compiler, !(op & SLJIT_SINGLE_OP), TMP_FREG, src, srcw));
+ FAIL_IF(emit_sse2_load(compiler, !(op & SLJIT_F32_OP), TMP_FREG, src, srcw));
src = TMP_FREG;
}
- FAIL_IF(emit_sse2_logic(compiler, CVTPD2PS_x_xm, op & SLJIT_SINGLE_OP, dst_r, src, 0));
+ FAIL_IF(emit_sse2_logic(compiler, CVTPD2PS_x_xm, op & SLJIT_F32_OP, dst_r, src, 0));
if (dst_r == TMP_FREG)
- return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG);
+ return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
return SLJIT_SUCCESS;
}
- if (SLOW_IS_REG(dst)) {
+ if (FAST_IS_REG(dst)) {
dst_r = dst;
if (dst != src)
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, src, srcw));
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, dst_r, src, srcw));
}
else {
dst_r = TMP_FREG;
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, src, srcw));
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, dst_r, src, srcw));
}
switch (GET_OPCODE(op)) {
- case SLJIT_DNEG:
- FAIL_IF(emit_sse2_logic(compiler, XORPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_SINGLE_OP ? sse2_buffer : sse2_buffer + 8)));
+ case SLJIT_NEG_F64:
+ FAIL_IF(emit_sse2_logic(compiler, XORPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_F32_OP ? sse2_buffer : sse2_buffer + 8)));
break;
- case SLJIT_DABS:
- FAIL_IF(emit_sse2_logic(compiler, ANDPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_SINGLE_OP ? sse2_buffer + 4 : sse2_buffer + 12)));
+ case SLJIT_ABS_F64:
+ FAIL_IF(emit_sse2_logic(compiler, ANDPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_F32_OP ? sse2_buffer + 4 : sse2_buffer + 12)));
break;
}
if (dst_r == TMP_FREG)
- return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG);
+ return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src1, sljit_sw src1w,
- sljit_si src2, sljit_sw src2w)
+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_si dst_r;
+ sljit_s32 dst_r;
CHECK_ERROR();
CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
dst_r = dst;
if (dst == src1)
; /* Do nothing here. */
- else if (dst == src2 && (op == SLJIT_DADD || op == SLJIT_DMUL)) {
+ else if (dst == src2 && (op == SLJIT_ADD_F64 || op == SLJIT_MUL_F64)) {
/* Swap arguments. */
src2 = src1;
src2w = src1w;
}
else if (dst != src2)
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, src1, src1w));
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, dst_r, src1, src1w));
else {
dst_r = TMP_FREG;
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src1, src1w));
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src1, src1w));
}
}
else {
dst_r = TMP_FREG;
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src1, src1w));
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src1, src1w));
}
switch (GET_OPCODE(op)) {
- case SLJIT_DADD:
- FAIL_IF(emit_sse2(compiler, ADDSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w));
+ case SLJIT_ADD_F64:
+ FAIL_IF(emit_sse2(compiler, ADDSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
break;
- case SLJIT_DSUB:
- FAIL_IF(emit_sse2(compiler, SUBSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w));
+ case SLJIT_SUB_F64:
+ FAIL_IF(emit_sse2(compiler, SUBSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
break;
- case SLJIT_DMUL:
- FAIL_IF(emit_sse2(compiler, MULSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w));
+ case SLJIT_MUL_F64:
+ FAIL_IF(emit_sse2(compiler, MULSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
break;
- case SLJIT_DDIV:
- FAIL_IF(emit_sse2(compiler, DIVSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w));
+ case SLJIT_DIV_F64:
+ FAIL_IF(emit_sse2(compiler, DIVSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
break;
}
if (dst_r == TMP_FREG)
- return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG);
+ return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
struct sljit_label *label;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_label(compiler));
- /* We should restore the flags before the label,
- since other taken jumps has their own flags as well. */
- if (SLJIT_UNLIKELY(compiler->flags_saved))
- PTR_FAIL_IF(emit_restore_flags(compiler, 0));
-
if (compiler->last_label && compiler->last_label->size == compiler->size)
return compiler->last_label;
PTR_FAIL_IF(!label);
set_label(label, compiler);
- inst = (sljit_ub*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF(!inst);
*inst++ = 0;
return label;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
struct sljit_jump *jump;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_jump(compiler, type));
- if (SLJIT_UNLIKELY(compiler->flags_saved)) {
- if ((type & 0xff) <= SLJIT_JUMP)
- PTR_FAIL_IF(emit_restore_flags(compiler, 0));
- compiler->flags_saved = 0;
- }
-
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
PTR_FAIL_IF_NULL(jump);
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
compiler->size += (type >= SLJIT_JUMP) ? (10 + 3) : (2 + 10 + 3);
#endif
- inst = (sljit_ub*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF_NULL(inst);
*inst++ = 0;
- *inst++ = type + 4;
+ *inst++ = type + 2;
return jump;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+#ifndef _WIN64
+#define IS_REG_CHANGED_BY_CALL(src, type) ((src) == SLJIT_R3)
+#else
+#define IS_REG_CHANGED_BY_CALL(src, type) ((src) == SLJIT_R2)
+#endif
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
struct sljit_jump *jump;
CHECK_ERROR();
CHECK_EXTRA_REGS(src, srcw, (void)0);
- if (SLJIT_UNLIKELY(compiler->flags_saved)) {
- if (type <= SLJIT_JUMP)
- FAIL_IF(emit_restore_flags(compiler, 0));
- compiler->flags_saved = 0;
- }
-
if (type >= SLJIT_CALL1) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
if (src == SLJIT_MEM1(SLJIT_SP) && type >= SLJIT_CALL3)
srcw += sizeof(sljit_sw);
#endif
-#endif
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && defined(_WIN64)
- if (src == SLJIT_R2) {
- EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
- src = TMP_REG1;
+#else
+ if ((src & SLJIT_MEM) || IS_REG_CHANGED_BY_CALL(src, type)) {
+ EMIT_MOV(compiler, TMP_REG2, 0, src, srcw);
+ src = TMP_REG2;
}
#endif
FAIL_IF(call_with_args(compiler, type));
compiler->size += 10 + 3;
#endif
- inst = (sljit_ub*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 2);
FAIL_IF_NULL(inst);
*inst++ = 0;
- *inst++ = type + 4;
+ *inst++ = type + 2;
}
else {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
- sljit_si dst, sljit_sw dstw,
- sljit_si src, sljit_sw srcw,
- sljit_si type)
+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 type)
{
- sljit_ub *inst;
- sljit_ub cond_set = 0;
+ sljit_u8 *inst;
+ sljit_u8 cond_set = 0;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- sljit_si reg;
-#else
- /* CHECK_EXTRA_REGS migh overwrite these values. */
- sljit_si dst_save = dst;
- sljit_sw dstw_save = dstw;
+ sljit_s32 reg;
#endif
+ /* ADJUST_LOCAL_OFFSET and CHECK_EXTRA_REGS might overwrite these values. */
+ sljit_s32 dst_save = dst;
+ sljit_sw dstw_save = dstw;
CHECK_ERROR();
- CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
- SLJIT_UNUSED_ARG(srcw);
-
- if (dst == SLJIT_UNUSED)
- return SLJIT_SUCCESS;
+ CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
ADJUST_LOCAL_OFFSET(dst, dstw);
CHECK_EXTRA_REGS(dst, dstw, (void)0);
- if (SLJIT_UNLIKELY(compiler->flags_saved))
- FAIL_IF(emit_restore_flags(compiler, op & SLJIT_KEEP_FLAGS));
type &= 0xff;
/* setcc = jcc + 0x10. */
cond_set = get_jump_code(type) + 0x10;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && dst == src) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + 3);
+ if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst)) {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 3);
FAIL_IF(!inst);
INC_SIZE(4 + 3);
/* Set low register to conditional flag. */
return SLJIT_SUCCESS;
}
- reg = (op == SLJIT_MOV && FAST_IS_REG(dst)) ? dst : TMP_REG1;
+ reg = (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG1;
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + 4);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 4);
FAIL_IF(!inst);
INC_SIZE(4 + 4);
/* Set low register to conditional flag. */
*inst++ = cond_set;
*inst++ = MOD_REG | reg_lmap[reg];
*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R));
+ /* The movzx instruction does not affect flags. */
*inst++ = GROUP_0F;
*inst++ = MOVZX_r_rm8;
*inst = MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg];
compiler->mode32 = GET_OPCODE(op) != SLJIT_MOV;
return emit_mov(compiler, dst, dstw, TMP_REG1, 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, dst, dstw, dst, dstw, TMP_REG1, 0);
-#else /* SLJIT_CONFIG_X86_64 */
+ return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
+
+#else
+ /* The SLJIT_CONFIG_X86_32 code path starts here. */
if (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) {
if (reg_map[dst] <= 4) {
/* Low byte is accessible. */
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 3 + 3);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3);
FAIL_IF(!inst);
INC_SIZE(3 + 3);
/* Set low byte to conditional flag. */
/* a xor reg, reg operation would overwrite the flags. */
EMIT_MOV(compiler, dst, 0, SLJIT_IMM, 0);
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 3);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
FAIL_IF(!inst);
INC_SIZE(3);
return SLJIT_SUCCESS;
}
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 3 + 3 + 1);
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
return SLJIT_SUCCESS;
}
- if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && dst == src && reg_map[dst] <= 4) {
- SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R0] == 0, scratch_reg1_must_be_eax);
+ if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && reg_map[dst] <= 4) {
+ SLJIT_ASSERT(reg_map[SLJIT_R0] == 0);
+
if (dst != SLJIT_R0) {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 3 + 2 + 1);
/* Set low register to conditional flag. */
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
}
else {
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2);
FAIL_IF(!inst);
INC_SIZE(2 + 3 + 2 + 2);
/* Set low register to conditional flag. */
}
/* Set TMP_REG1 to the bit. */
- inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 3 + 3 + 1);
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
#endif /* SLJIT_CONFIG_X86_64 */
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset)
+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_u8* inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ dst_reg &= ~SLJIT_I32_OP;
+
+ if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV) || (dst_reg >= SLJIT_R3 && dst_reg <= SLJIT_S3))
+ return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+#else
+ if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+ return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+#endif
+
+ /* ADJUST_LOCAL_OFFSET is not needed. */
+ CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = dst_reg & SLJIT_I32_OP;
+ dst_reg &= ~SLJIT_I32_OP;
+#endif
+
+ if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw);
+ src = TMP_REG1;
+ srcw = 0;
+ }
+
+ inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw);
+ FAIL_IF(!inst);
+ *inst++ = GROUP_0F;
+ *inst = get_jump_code(type & 0xff) - 0x40;
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
{
CHECK_ERROR();
CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
if (NOT_HALFWORD(offset)) {
FAIL_IF(emit_load_imm64(compiler, TMP_REG1, offset));
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
- SLJIT_ASSERT(emit_lea_binary(compiler, SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0) != SLJIT_ERR_UNSUPPORTED);
+ SLJIT_ASSERT(emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0) != SLJIT_ERR_UNSUPPORTED);
return compiler->error;
#else
- return emit_lea_binary(compiler, SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0);
+ return emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0);
#endif
}
#endif
if (offset != 0)
- return emit_lea_binary(compiler, SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
+ return emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
return emit_mov(compiler, dst, dstw, SLJIT_SP, 0);
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
- sljit_ub *inst;
+ sljit_u8 *inst;
struct sljit_const *const_;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- sljit_si reg;
+ sljit_s32 reg;
#endif
CHECK_ERROR_PTR();
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
- reg = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+ reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (emit_load_imm64(compiler, reg, init_value))
return NULL;
#else
- if (dst == SLJIT_UNUSED)
- dst = TMP_REG1;
-
if (emit_mov(compiler, dst, dstw, SLJIT_IMM, init_value))
return NULL;
#endif
- inst = (sljit_ub*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF(!inst);
*inst++ = 0;
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_UNUSED_ARG(executable_offset);
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *(sljit_sw*)addr = new_addr - (addr + 4);
-#else
- *(sljit_uw*)addr = new_addr;
-#endif
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
-{
- *(sljit_sw*)addr = new_constant;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_sse2_available(void)
-{
-#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
- if (cpu_has_sse2 == -1)
- get_cpu_features();
- return cpu_has_sse2;
+ sljit_unaligned_store_sw((void*)addr, new_target - (addr + 4) - (sljit_uw)executable_offset);
#else
- return 1;
+ sljit_unaligned_store_sw((void*)addr, (sljit_sw) new_target);
#endif
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_cmov_available(void)
-{
- if (cpu_has_cmov == -1)
- get_cpu_features();
- return cpu_has_cmov;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_emit_cmov(struct sljit_compiler *compiler,
- sljit_si type,
- sljit_si dst_reg,
- sljit_si src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
{
- sljit_ub* inst;
-
- CHECK_ERROR();
-#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(sljit_x86_is_cmov_available());
- CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_INT_OP)));
- CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_D_ORDERED);
- CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg & ~SLJIT_INT_OP));
- FUNCTION_CHECK_SRC(src, srcw);
-#endif
-#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
- if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " x86_cmov%s %s%s, ",
- !(dst_reg & SLJIT_INT_OP) ? "" : ".i",
- JUMP_PREFIX(type), jump_names[type & 0xff]);
- sljit_verbose_reg(compiler, dst_reg & ~SLJIT_INT_OP);
- fprintf(compiler->verbose, ", ");
- sljit_verbose_param(compiler, src, srcw);
- fprintf(compiler->verbose, "\n");
- }
-#endif
-
- ADJUST_LOCAL_OFFSET(src, srcw);
- CHECK_EXTRA_REGS(src, srcw, (void)0);
-
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = dst_reg & SLJIT_INT_OP;
-#endif
- dst_reg &= ~SLJIT_INT_OP;
-
- if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
- EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw);
- src = TMP_REG1;
- srcw = 0;
- }
-
- inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = get_jump_code(type & 0xff) - 0x40;
- return SLJIT_SUCCESS;
+ SLJIT_UNUSED_ARG(executable_offset);
+ sljit_unaligned_store_sw((void*)addr, new_constant);
}
/*
* 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:
#include <fcntl.h>
/* Some old systems does not have MAP_ANON. */
-static sljit_si dev_zero = -1;
+static sljit_s32 dev_zero = -1;
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
-static SLJIT_INLINE sljit_si open_dev_zero(void)
+static SLJIT_INLINE sljit_s32 open_dev_zero(void)
{
dev_zero = open("/dev/zero", O_RDWR);
return dev_zero < 0;
static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
-static SLJIT_INLINE sljit_si open_dev_zero(void)
+static SLJIT_INLINE sljit_s32 open_dev_zero(void)
{
pthread_mutex_lock(&dev_zero_mutex);
- dev_zero = open("/dev/zero", O_RDWR);
+ /* The dev_zero might be initialized by another thread during the waiting. */
+ if (dev_zero < 0) {
+ dev_zero = open("/dev/zero", O_RDWR);
+ }
pthread_mutex_unlock(&dev_zero_mutex);
return dev_zero < 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;
+ void *ptr;
#ifdef _WIN32
SYSTEM_INFO si;
#endif
}
#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()) {
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;
#undef PAGE_ALIGN
-SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* stack, void *allocator_data)
+SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
{
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;
"(?|(\k'Pm')|(?'Pm'))"
abcd
+/(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[,;:])(?=.{8,16})(?!.*[\s])/
+ \ Fred:099
+
+/(?=.*X)X$/
+ \ X
+
+/X+(?#comment)?/
+ >XXX<
+
/-- End of testinput1 --/
/.((?2)(?R)\1)()/B
+/([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00](*ACCEPT)/
+
/-- End of testinput11 --/
/(.|.)*?bx/
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabax
+/((?(?!))x)(?'name')(?1)/S++
+
/-- End of testinput12 --/
/abc/89
+//8+L
+ \xf1\xad\xae\xae
+
/-- End of testinput15 --/
/s+/i8SI
SSss\x{17f}
+/[\W\p{Any}]/BZ
+ abc
+ 123
+
+/[\W\pL]/BZ
+ abc
+ ** Failers
+ 123
+
+/[\D]/8
+ \x{1d7cf}
+
+/[\D\P{Nd}]/8
+ \x{1d7cf}
+
+/[^\D]/8
+ a9b
+ ** Failers
+ \x{1d7cf}
+
+/[^\D\P{Nd}]/8
+ a9b
+ \x{1d7cf}
+ ** Failers
+ \x{10000}
+
/-- End of testinput16 --/
/s+/i8SI
SSss\x{17f}
+/[\D]/8
+ \x{1d7cf}
+
+/[\D\P{Nd}]/8
+ \x{1d7cf}
+
+/[^\D]/8
+ a9b
+ ** Failers
+ \x{1d7cf}
+
+/[^\D\P{Nd}]/8
+ a9b
+ \x{1d7cf}
+ ** Failers
+ \x{10000}
+
/-- End of testinput19 --/
/a[[:punct:]b]/BZ
+/L(?#(|++<!(2)?/BZ
+
+/L(?#(|++<!(2)?/BOZ
+
+/L(?#(|++<!(2)?/BCZ
+
+/L(?#(|++<!(2)?/BCOZ
+
+/(A*)\E+/CBZ
+
+/()\Q\E*]/BCZ
+
+/(?<A>)(?J:(?<B>)(?<B>))(?<C>)/
+ \O\CC
+
+/(?=a\K)/
+ ring bpattingbobnd $ 1,oern cou \rb\L
+
+/(?<=((?C)0))/
+ 9010
+ abcd
+
+/((?J)(?'R'(?'R'(?'R'(?'R'(?'R'(?|(\k'R'))))))))/
+
+/\N(?(?C)0?!.)*/
+
+/(?<RA>abc)(?(R)xyz)/BZ
+
+/(?<R>abc)(?(R)xyz)/BZ
+
+/(?=.*[A-Z])/I
+
/-- End of testinput2 --/
\x{200}
\x{37e}
+/[^[:^ascii:]\d]/8W
+ a
+ ~
+ 0
+ \a
+ \x{7f}
+ \x{389}
+ \x{20ac}
+
+/(?=.*b)\pL/
+ 11bb
+
+/(?(?=.*b)(?=.*b)\pL|.*c)/
+ 11bb
+
/-- End of testinput6 --/
/^s?c/mi8I
scat
-/[\W\p{Any}]/BZ
- abc
- 123
-
-/[\W\pL]/BZ
- abc
- ** Failers
- 123
-
/a[[:punct:]b]/WBZ
/a[[:punct:]b]/8WBZ
/a[b[:punct:]]/8WBZ
+/L(?#(|++<!(2)?/B8COZ
+
+/L(?#(|++<!(2)?/B8WCZ
+
/-- End of testinput7 --/
bbb
aaa
+/()()a+/O=
+ aaa\D
+ a\D
+
+/(02-)?[0-9]{3}-[0-9]{3}/
+ 02-123-123
+
/-- End of testinput8 --/
0:
1:
+/(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[,;:])(?=.{8,16})(?!.*[\s])/
+ \ Fred:099
+ 0:
+
+/(?=.*X)X$/
+ \ X
+ 0: X
+
+/X+(?#comment)?/
+ >XXX<
+ 0: X
+
/-- End of testinput1 --/
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/BM
-Memory allocation (code space): 77
+Memory allocation (code space): 93
------------------------------------------------------------------
0 24 Bra
2 5 CBra 1
25 End
------------------------------------------------------------------
+/([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00](*ACCEPT)/
+Failed: regular expression is too complicated at offset 490
+
/-- End of testinput11 --/
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/BM
-Memory allocation (code space): 157
+Memory allocation (code space): 189
------------------------------------------------------------------
0 24 Bra
2 5 CBra 1
25 End
------------------------------------------------------------------
+/([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00](*ACCEPT)/
+Failed: missing ) at offset 509
+
/-- End of testinput11 --/
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/BM
-Memory allocation (code space): 50
+Memory allocation (code space): 62
------------------------------------------------------------------
0 30 Bra
3 7 CBra 1
38 End
------------------------------------------------------------------
+/([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00](*ACCEPT)/
+Failed: missing ) at offset 509
+
/-- End of testinput11 --/
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabax
Error -8 (match limit exceeded)
+/((?(?!))x)(?'name')(?1)/S++
+
/-- End of testinput12 --/
/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 --/
SSss\x{17f}
0: SSss\x{17f}
+/[\W\p{Any}]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-/:-@[-^`{-\xff\p{Any}]
+ Ket
+ End
+------------------------------------------------------------------
+ abc
+ 0: a
+ 123
+ 0: 1
+
+/[\W\pL]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-/:-@[-^`{-\xff\p{L}]
+ Ket
+ End
+------------------------------------------------------------------
+ abc
+ 0: a
+ ** Failers
+ 0: *
+ 123
+No match
+
+/[\D]/8
+ \x{1d7cf}
+ 0: \x{1d7cf}
+
+/[\D\P{Nd}]/8
+ \x{1d7cf}
+ 0: \x{1d7cf}
+
+/[^\D]/8
+ a9b
+ 0: 9
+ ** Failers
+No match
+ \x{1d7cf}
+No match
+
+/[^\D\P{Nd}]/8
+ a9b
+ 0: 9
+ \x{1d7cf}
+ 0: \x{1d7cf}
+ ** Failers
+No match
+ \x{10000}
+No match
+
/-- End of testinput16 --/
SSss\x{17f}
0: SSss\x{17f}
+/[\D]/8
+ \x{1d7cf}
+ 0: \x{1d7cf}
+
+/[\D\P{Nd}]/8
+ \x{1d7cf}
+ 0: \x{1d7cf}
+
+/[^\D]/8
+ a9b
+ 0: 9
+ ** Failers
+No match
+ \x{1d7cf}
+No match
+
+/[^\D\P{Nd}]/8
+ a9b
+ 0: 9
+ \x{1d7cf}
+ 0: \x{1d7cf}
+ ** Failers
+No match
+ \x{10000}
+No match
+
/-- End of testinput19 --/
/(?U)<.*>/I
Capturing subpattern count = 0
-Options: ungreedy
+No options
First char = '<'
Need char = '>'
abc<def>ghi<klm>nop
/(?U)={3,}?/I
Capturing subpattern count = 0
-Options: ungreedy
+No options
First char = '='
Need char = '='
abc========def
/(?i)abc/I
Capturing subpattern count = 0
-Options: caseless
+No options
First char = 'a' (caseless)
Need char = 'c' (caseless)
/(?i)^1234/I
Capturing subpattern count = 0
-Options: anchored caseless
+Options: anchored
No first char
No need char
/(?s).*/I
Capturing subpattern count = 0
May match empty string
-Options: anchored dotall
+Options: anchored
No first char
No need char
/(?i)[abcd]/IS
Capturing subpattern count = 0
-Options: caseless
+No options
No first char
No need char
Subject length lower bound = 1
/(?m)[xy]|(b|c)/IS
Capturing subpattern count = 1
-Options: multiline
+No options
No first char
No need char
Subject length lower bound = 1
/(?i)(^a|^b)/Im
Capturing subpattern count = 1
-Options: caseless multiline
+Options: multiline
First char at start or follows newline
No need char
Failed: malformed number or name after (?( at offset 4
/(?(?i))/
-Failed: assertion expected after (?( at offset 3
+Failed: assertion expected after (?( or (?(?C) at offset 3
/(?(abc))/
Failed: reference to non-existent subpattern at offset 7
/(?(?<ab))/
-Failed: assertion expected after (?( at offset 3
+Failed: assertion expected after (?( or (?(?C) at offset 3
/((?s)blah)\s+\1/I
Capturing subpattern count = 1
End
------------------------------------------------------------------
Capturing subpattern count = 1
-Options: anchored dotall
+Options: anchored
No first char
No need char
End
------------------------------------------------------------------
Capturing subpattern count = 0
-Options: caseless extended
+Options: extended
First char = 'a' (caseless)
Need char = 'c' (caseless)
End
------------------------------------------------------------------
Capturing subpattern count = 0
-Options: caseless extended
+Options: extended
First char = 'a' (caseless)
Need char = 'c' (caseless)
End
------------------------------------------------------------------
Capturing subpattern count = 0
-Options: ungreedy
+No options
First char = 'x'
Need char = 'b'
xaaaab
/(?i)[ab]/IS
Capturing subpattern count = 0
-Options: caseless
+No options
No first char
No need char
Subject length lower bound = 1
Named capturing subpatterns:
A 2
A 3
-Options: anchored dupnames
+Options: anchored
Duplicate name status changes
No first char
No need char
Failed: malformed number or name after (?( at offset 6
/(?(''))/
-Failed: assertion expected after (?( at offset 4
+Failed: assertion expected after (?( or (?(?C) at offset 4
/(?('R')stuff)/
Failed: reference to non-existent subpattern at offset 7
/(?(?=.*b).*b|^d)/I
Capturing subpattern count = 0
No options
-First char at start or follows newline
+No first char
No need char
/xyz/C
"((?2)+)((?1))"
"(?(?<E>.*!.*)?)"
-Failed: assertion expected after (?( at offset 3
+Failed: assertion expected after (?( or (?(?C) at offset 3
"X((?2)()*+){2}+"BZ
------------------------------------------------------------------
End
------------------------------------------------------------------
+/L(?#(|++<!(2)?/BZ
+------------------------------------------------------------------
+ Bra
+ L?+
+ Ket
+ End
+------------------------------------------------------------------
+
+/L(?#(|++<!(2)?/BOZ
+------------------------------------------------------------------
+ Bra
+ L?
+ Ket
+ End
+------------------------------------------------------------------
+
+/L(?#(|++<!(2)?/BCZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 14
+ L?+
+ Callout 255 14 0
+ Ket
+ End
+------------------------------------------------------------------
+
+/L(?#(|++<!(2)?/BCOZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 14
+ L?
+ Callout 255 14 0
+ Ket
+ End
+------------------------------------------------------------------
+
+/(A*)\E+/CBZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 7
+ SCBra 1
+ Callout 255 1 2
+ A*
+ Callout 255 3 0
+ KetRmax
+ Callout 255 7 0
+ Ket
+ End
+------------------------------------------------------------------
+
+/()\Q\E*]/BCZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 7
+ Brazero
+ SCBra 1
+ Callout 255 1 0
+ KetRmax
+ Callout 255 7 1
+ ]
+ Callout 255 8 0
+ Ket
+ End
+------------------------------------------------------------------
+
+/(?<A>)(?J:(?<B>)(?<B>))(?<C>)/
+ \O\CC
+Matched, but too many substrings
+copy substring C failed -7
+
+/(?=a\K)/
+ ring bpattingbobnd $ 1,oern cou \rb\L
+Start of matched string is beyond its end - displaying from end to start.
+ 0: a
+ 0L
+
+/(?<=((?C)0))/
+ 9010
+--->9010
+ 0 ^ 0
+ 0 ^ 0
+ 0:
+ 1: 0
+ abcd
+--->abcd
+ 0 ^ 0
+ 0 ^ 0
+ 0 ^ 0
+ 0 ^ 0
+No match
+
+/((?J)(?'R'(?'R'(?'R'(?'R'(?'R'(?|(\k'R'))))))))/
+
+/\N(?(?C)0?!.)*/
+Failed: assertion expected after (?( or (?(?C) at offset 4
+
+/(?<RA>abc)(?(R)xyz)/BZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ abc
+ Ket
+ Cond
+ Cond recurse any
+ xyz
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/(?<R>abc)(?(R)xyz)/BZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ abc
+ Ket
+ Cond
+ 1 Cond ref
+ xyz
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/(?=.*[A-Z])/I
+Capturing subpattern count = 0
+May match empty string
+No options
+No first char
+No need char
+
/-- End of testinput2 --/
\x{37e}
0: \x{37e}
+/[^[:^ascii:]\d]/8W
+ a
+ 0: a
+ ~
+ 0: ~
+ 0
+No match
+ \a
+ 0: \x{07}
+ \x{7f}
+ 0: \x{7f}
+ \x{389}
+No match
+ \x{20ac}
+No match
+
+/(?=.*b)\pL/
+ 11bb
+ 0: b
+
+/(?(?=.*b)(?=.*b)\pL|.*c)/
+ 11bb
+ 0: b
+
/-- End of testinput6 --/
scat
0: sc
-/[\W\p{Any}]/BZ
+/a[[:punct:]b]/WBZ
------------------------------------------------------------------
Bra
- [\x00-/:-@[-^`{-\xff\p{Any}]
+ a
+ [b[:punct:]]
Ket
End
------------------------------------------------------------------
- abc
- 0: a
- 123
- 0: 1
-/[\W\pL]/BZ
+/a[[:punct:]b]/8WBZ
------------------------------------------------------------------
Bra
- [\x00-/:-@[-^`{-\xff\p{L}]
+ a
+ [b[:punct:]]
Ket
End
------------------------------------------------------------------
- abc
- 0: a
- ** Failers
- 0: *
- 123
-No match
-/a[[:punct:]b]/WBZ
+/a[b[:punct:]]/8WBZ
------------------------------------------------------------------
Bra
a
End
------------------------------------------------------------------
-/a[[:punct:]b]/8WBZ
+/L(?#(|++<!(2)?/B8COZ
------------------------------------------------------------------
Bra
- a
- [b[:punct:]]
+ Callout 255 0 14
+ L?
+ Callout 255 14 0
Ket
End
------------------------------------------------------------------
-/a[b[:punct:]]/8WBZ
+/L(?#(|++<!(2)?/B8WCZ
------------------------------------------------------------------
Bra
- a
- [b[:punct:]]
+ Callout 255 0 14
+ L?+
+ Callout 255 14 0
Ket
End
------------------------------------------------------------------
aaa
No match
+/()()a+/O=
+ aaa\D
+** Show all captures ignored after DFA matching
+ 0: aaa
+ 1: aa
+ 2: a
+ a\D
+** 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 --/
php_info_print_table_row(2, "PCRE JIT Support", "not compiled in" );
#endif
+#ifdef HAVE_PCRE_VALGRIND_SUPPORT
+ php_info_print_table_row(2, "PCRE Valgrind Support", "enabled" );
+#endif
+
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
$env['USE_ZEND_ALLOC'] = '0';
$env['ZEND_DONT_UNLOAD_MODULES'] = 1;
+ $valgrind_cmd = "valgrind -q --tool=memcheck --trace-children=yes";
+ if (strpos($test_file, "pcre") !== false) {
+ $valgrind_cmd .= " --smc-check=all";
+ }
+
/* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */
if (version_compare($valgrind_version, '3.8.0', '>=')) {
/* valgrind 3.3.0+ doesn't have --log-file-exactly option */
- $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd";
+ $cmd = "$valgrind_cmd --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd";
} elseif (version_compare($valgrind_version, '3.3.0', '>=')) {
- $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd";
+ $cmd = "$valgrind_cmd --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd";
} else {
- $cmd = "valgrind -q --tool=memcheck --trace-children=yes --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd";
+ $cmd = "$valgrind_cmd --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd";
}
} else {