pcre2: Update to upstream version 10.39

Changelog: https://github.com/PhilipHazel/pcre2/blob/pcre2-10.39/ChangeLog
This commit is contained in:
Rémi Verschelde 2021-11-19 12:47:40 +01:00
parent 42f8bfaff0
commit 914b7f825d
No known key found for this signature in database
GPG key ID: C3336907360768E1
35 changed files with 5851 additions and 4501 deletions

View file

@ -369,8 +369,8 @@ License: Apache-2.0
Files: ./thirdparty/pcre2/ Files: ./thirdparty/pcre2/
Comment: PCRE2 Comment: PCRE2
Copyright: 1997-2020, University of Cambridge Copyright: 1997-2021, University of Cambridge
2009-2020, Zoltan Herczeg 2009-2021, Zoltan Herczeg
License: BSD-3-clause License: BSD-3-clause
Files: ./thirdparty/pvrtccompressor/ Files: ./thirdparty/pvrtccompressor/

View file

@ -506,7 +506,7 @@ Patch files are provided in `oidn/patches/`.
## pcre2 ## pcre2
- Upstream: http://www.pcre.org - Upstream: http://www.pcre.org
- Version: 10.36 (r1288, 2020) - Version: 10.39 (35fee4193b852cb504892352bd0155de10809889, 2021)
- License: BSD-3-Clause - License: BSD-3-Clause
Files extracted from upstream source: Files extracted from upstream source:

View file

@ -5,10 +5,10 @@ Written by: Philip Hazel
Email local part: Philip.Hazel Email local part: Philip.Hazel
Email domain: gmail.com Email domain: gmail.com
University of Cambridge Computing Service, Retired from University of Cambridge Computing Service,
Cambridge, England. Cambridge, England.
Copyright (c) 1997-2020 University of Cambridge Copyright (c) 1997-2021 University of Cambridge
All rights reserved All rights reserved
@ -19,7 +19,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester Email local part: hzmester
Emain domain: freemail.hu Emain domain: freemail.hu
Copyright(c) 2010-2020 Zoltan Herczeg Copyright(c) 2010-2021 Zoltan Herczeg
All rights reserved. All rights reserved.
@ -30,7 +30,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester Email local part: hzmester
Emain domain: freemail.hu Emain domain: freemail.hu
Copyright(c) 2009-2020 Zoltan Herczeg Copyright(c) 2009-2021 Zoltan Herczeg
All rights reserved. All rights reserved.
#### ####

View file

@ -23,10 +23,10 @@ Written by: Philip Hazel
Email local part: Philip.Hazel Email local part: Philip.Hazel
Email domain: gmail.com Email domain: gmail.com
University of Cambridge Computing Service, Retired from University of Cambridge Computing Service,
Cambridge, England. Cambridge, England.
Copyright (c) 1997-2020 University of Cambridge Copyright (c) 1997-2021 University of Cambridge
All rights reserved. All rights reserved.
@ -37,7 +37,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester Email local part: hzmester
Email domain: freemail.hu Email domain: freemail.hu
Copyright(c) 2010-2020 Zoltan Herczeg Copyright(c) 2010-2021 Zoltan Herczeg
All rights reserved. All rights reserved.
@ -48,7 +48,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester Email local part: hzmester
Email domain: freemail.hu Email domain: freemail.hu
Copyright(c) 2009-2020 Zoltan Herczeg Copyright(c) 2009-2021 Zoltan Herczeg
All rights reserved. All rights reserved.

View file

@ -85,8 +85,8 @@ sure both macros are undefined; an emulation function will then be used. */
/* Define to 1 if you have the `memmove' function. */ /* Define to 1 if you have the `memmove' function. */
/* #undef HAVE_MEMMOVE */ /* #undef HAVE_MEMMOVE */
/* Define to 1 if you have the <memory.h> header file. */ /* Define to 1 if you have the <minix/config.h> header file. */
/* #undef HAVE_MEMORY_H */ /* #undef HAVE_MINIX_CONFIG_H */
/* Define to 1 if you have the `mkostemp' function. */ /* Define to 1 if you have the `mkostemp' function. */
/* #undef HAVE_MKOSTEMP */ /* #undef HAVE_MKOSTEMP */
@ -103,12 +103,18 @@ sure both macros are undefined; an emulation function will then be used. */
/* Define to 1 if you have the <readline/readline.h> header file. */ /* Define to 1 if you have the <readline/readline.h> header file. */
/* #undef HAVE_READLINE_READLINE_H */ /* #undef HAVE_READLINE_READLINE_H */
/* Define to 1 if you have the `realpath' function. */
/* #undef HAVE_REALPATH */
/* Define to 1 if you have the `secure_getenv' function. */ /* Define to 1 if you have the `secure_getenv' function. */
/* #undef HAVE_SECURE_GETENV */ /* #undef HAVE_SECURE_GETENV */
/* Define to 1 if you have the <stdint.h> header file. */ /* Define to 1 if you have the <stdint.h> header file. */
/* #undef HAVE_STDINT_H */ /* #undef HAVE_STDINT_H */
/* Define to 1 if you have the <stdio.h> header file. */
/* #undef HAVE_STDIO_H */
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
/* #undef HAVE_STDLIB_H */ /* #undef HAVE_STDLIB_H */
@ -136,6 +142,9 @@ sure both macros are undefined; an emulation function will then be used. */
/* Define to 1 if the compiler supports simple visibility declarations. */ /* Define to 1 if the compiler supports simple visibility declarations. */
/* #undef HAVE_VISIBILITY */ /* #undef HAVE_VISIBILITY */
/* Define to 1 if you have the <wchar.h> header file. */
/* #undef HAVE_WCHAR_H */
/* Define to 1 if you have the <windows.h> header file. */ /* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */ /* #undef HAVE_WINDOWS_H */
@ -224,7 +233,7 @@ sure both macros are undefined; an emulation function will then be used. */
#define PACKAGE_NAME "PCRE2" #define PACKAGE_NAME "PCRE2"
/* Define to the full name and version of this package. */ /* Define to the full name and version of this package. */
#define PACKAGE_STRING "PCRE2 10.36" #define PACKAGE_STRING "PCRE2 10.39"
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pcre2" #define PACKAGE_TARNAME "pcre2"
@ -233,7 +242,7 @@ sure both macros are undefined; an emulation function will then be used. */
#define PACKAGE_URL "" #define PACKAGE_URL ""
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION "10.36" #define PACKAGE_VERSION "10.39"
/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested /* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested
parentheses (of any kind) in a pattern. This limits the amount of system parentheses (of any kind) in a pattern. This limits the amount of system
@ -286,7 +295,9 @@ sure both macros are undefined; an emulation function will then be used. */
unless SUPPORT_JIT is also defined. */ unless SUPPORT_JIT is also defined. */
/* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */ /* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
/* #undef STDC_HEADERS */ /* #undef STDC_HEADERS */
/* Define to any value to enable support for Just-In-Time compiling. */ /* Define to any value to enable support for Just-In-Time compiling. */
@ -340,35 +351,91 @@ sure both macros are undefined; an emulation function will then be used. */
#ifndef _ALL_SOURCE #ifndef _ALL_SOURCE
# define _ALL_SOURCE 1 # define _ALL_SOURCE 1
#endif #endif
/* Enable GNU extensions on systems that have them. */ /* Enable general extensions on macOS. */
#ifndef _GNU_SOURCE #ifndef _DARWIN_C_SOURCE
# define _GNU_SOURCE 1 # define _DARWIN_C_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif #endif
/* Enable general extensions on Solaris. */ /* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__ #ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1 # define __EXTENSIONS__ 1
#endif #endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable X/Open compliant socket functions that do not require linking
with -lxnet on HP-UX 11.11. */
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
# define _HPUX_ALT_XOPEN_SOCKET_API 1
#endif
/* Identify the host operating system as Minix.
This macro does not affect the system headers' behavior.
A future release of Autoconf may stop defining this macro. */
#ifndef _MINIX
/* # undef _MINIX */
#endif
/* Enable general extensions on NetBSD.
Enable NetBSD compatibility extensions on Minix. */
#ifndef _NETBSD_SOURCE
# define _NETBSD_SOURCE 1
#endif
/* Enable OpenBSD compatibility extensions on NetBSD.
Oddly enough, this does nothing on OpenBSD. */
#ifndef _OPENBSD_SOURCE
# define _OPENBSD_SOURCE 1
#endif
/* Define to 1 if needed for POSIX-compatible behavior. */
#ifndef _POSIX_SOURCE
/* # undef _POSIX_SOURCE */
#endif
/* Define to 2 if needed for POSIX-compatible behavior. */
#ifndef _POSIX_1_SOURCE
/* # undef _POSIX_1_SOURCE */
#endif
/* Enable POSIX-compatible threading on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
#ifndef __STDC_WANT_LIB_EXT2__
# define __STDC_WANT_LIB_EXT2__ 1
#endif
/* Enable extensions specified by ISO/IEC 24747:2009. */
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable X/Open extensions. Define to 500 only if necessary
to make mbstate_t available. */
#ifndef _XOPEN_SOURCE
/* # undef _XOPEN_SOURCE */
#endif
/* Version number of package */ /* Version number of package */
#define VERSION "10.36" #define VERSION "10.39"
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* Define to empty if `const' does not conform to ANSI C. */ /* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */ /* #undef const */

View file

@ -5,7 +5,7 @@
/* This is the public header file for the PCRE library, second API, to be /* This is the public header file for the PCRE library, second API, to be
#included by applications that call PCRE2 functions. #included by applications that call PCRE2 functions.
Copyright (c) 2016-2020 University of Cambridge Copyright (c) 2016-2021 University of Cambridge
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* The current PCRE version information. */ /* The current PCRE version information. */
#define PCRE2_MAJOR 10 #define PCRE2_MAJOR 10
#define PCRE2_MINOR 36 #define PCRE2_MINOR 39
#define PCRE2_PRERELEASE #define PCRE2_PRERELEASE
#define PCRE2_DATE 2020-12-04 #define PCRE2_DATE 2021-10-29
/* When an application links to a PCRE DLL in Windows, the symbols that are /* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE2, the appropriate imported have to be identified as such. When building PCRE2, the appropriate
@ -84,8 +84,8 @@ set, we ensure here that it has no effect. */
/* Have to include limits.h, stdlib.h, and inttypes.h to ensure that size_t and /* Have to include limits.h, stdlib.h, and inttypes.h to ensure that size_t and
uint8_t, UCHAR_MAX, etc are defined. Some systems that do have inttypes.h do uint8_t, UCHAR_MAX, etc are defined. Some systems that do have inttypes.h do
not have stdint.h, which is why we use inttypes.h, which according to the C not have stdint.h, which is why we use inttypes.h, which according to the C
standard is a superset of stdint.h. If none of these headers are available, standard is a superset of stdint.h. If inttypes.h is not available the build
the relevant values must be provided by some other means. */ will break and the relevant values must be provided by some other means. */
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
@ -152,6 +152,7 @@ D is inspected during pcre2_dfa_match() execution
#define PCRE2_EXTRA_MATCH_LINE 0x00000008u /* C */ #define PCRE2_EXTRA_MATCH_LINE 0x00000008u /* C */
#define PCRE2_EXTRA_ESCAPED_CR_IS_LF 0x00000010u /* C */ #define PCRE2_EXTRA_ESCAPED_CR_IS_LF 0x00000010u /* C */
#define PCRE2_EXTRA_ALT_BSUX 0x00000020u /* C */ #define PCRE2_EXTRA_ALT_BSUX 0x00000020u /* C */
#define PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK 0x00000040u /* C */
/* These are for pcre2_jit_compile(). */ /* These are for pcre2_jit_compile(). */
@ -311,6 +312,7 @@ pcre2_pattern_convert(). */
#define PCRE2_ERROR_SCRIPT_RUN_NOT_AVAILABLE 196 #define PCRE2_ERROR_SCRIPT_RUN_NOT_AVAILABLE 196
#define PCRE2_ERROR_TOO_MANY_CAPTURES 197 #define PCRE2_ERROR_TOO_MANY_CAPTURES 197
#define PCRE2_ERROR_CONDITION_ATOMIC_ASSERTION_EXPECTED 198 #define PCRE2_ERROR_CONDITION_ATOMIC_ASSERTION_EXPECTED 198
#define PCRE2_ERROR_BACKSLASH_K_IN_LOOKAROUND 199
/* "Expected" matching error codes: no match and partial match. */ /* "Expected" matching error codes: no match and partial match. */

View file

@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2016-2020 University of Cambridge New API code Copyright (c) 2016-2021 University of Cambridge
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -490,6 +490,7 @@ switch(c)
list[2] = (uint32_t)(end - code); list[2] = (uint32_t)(end - code);
return end; return end;
} }
return NULL; /* Opcode not accepted */ return NULL; /* Opcode not accepted */
} }
@ -1186,12 +1187,16 @@ for (;;)
c = *repeat_opcode; c = *repeat_opcode;
if (c >= OP_CRSTAR && c <= OP_CRMINRANGE) if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
{ {
/* end must not be NULL. */ /* The return from get_chr_property_list() will never be NULL when
end = get_chr_property_list(code, utf, ucp, cb->fcc, list); *code (aka c) is one of the three class opcodes. However, gcc with
-fanalyzer notes that a NULL return is possible, and grumbles. Hence we
put in a check. */
end = get_chr_property_list(code, utf, ucp, cb->fcc, list);
list[1] = (c & 1) == 0; list[1] = (c & 1) == 0;
if (compare_opcodes(end, utf, ucp, cb, list, end, &rec_limit)) if (end != NULL &&
compare_opcodes(end, utf, ucp, cb, list, end, &rec_limit))
{ {
switch (c) switch (c)
{ {

View file

@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2016-2020 University of Cambridge New API code Copyright (c) 2016-2021 University of Cambridge
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -137,7 +137,7 @@ static BOOL
static int static int
check_lookbehinds(uint32_t *, uint32_t **, parsed_recurse_check *, check_lookbehinds(uint32_t *, uint32_t **, parsed_recurse_check *,
compile_block *); compile_block *, int *);
/************************************************* /*************************************************
@ -782,12 +782,15 @@ are allowed. */
#define PUBLIC_COMPILE_EXTRA_OPTIONS \ #define PUBLIC_COMPILE_EXTRA_OPTIONS \
(PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \ (PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \
PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL| \ PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL| \
PCRE2_EXTRA_ESCAPED_CR_IS_LF|PCRE2_EXTRA_ALT_BSUX) PCRE2_EXTRA_ESCAPED_CR_IS_LF|PCRE2_EXTRA_ALT_BSUX| \
PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)
/* Compile time error code numbers. They are given names so that they can more /* Compile time error code numbers. They are given names so that they can more
easily be tracked. When a new number is added, the tables called eint1 and easily be tracked. When a new number is added, the tables called eint1 and
eint2 in pcre2posix.c may need to be updated, and a new error text must be eint2 in pcre2posix.c may need to be updated, and a new error text must be
added to compile_error_texts in pcre2_error.c. */ added to compile_error_texts in pcre2_error.c. Also, the error codes in
pcre2.h.in must be updated - their values are exactly 100 greater than these
values. */
enum { ERR0 = COMPILE_ERROR_BASE, enum { ERR0 = COMPILE_ERROR_BASE,
ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10,
@ -799,7 +802,7 @@ enum { ERR0 = COMPILE_ERROR_BASE,
ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70,
ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80,
ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90,
ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98 }; ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99 };
/* This is a table of start-of-pattern options such as (*UTF) and settings such /* This is a table of start-of-pattern options such as (*UTF) and settings such
as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward
@ -1398,32 +1401,47 @@ static BOOL
read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp, read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp,
uint32_t *maxp, int *errorcodeptr) uint32_t *maxp, int *errorcodeptr)
{ {
PCRE2_SPTR p = *ptrptr; PCRE2_SPTR p;
BOOL yield = FALSE; BOOL yield = FALSE;
BOOL had_comma = FALSE;
int32_t min = 0; int32_t min = 0;
int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */ int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */
/* NB read_number() initializes the error code to zero. The only error is for a /* Check the syntax */
number that is too big. */
*errorcodeptr = 0;
for (p = *ptrptr;; p++)
{
uint32_t c;
if (p >= ptrend) return FALSE;
c = *p;
if (IS_DIGIT(c)) continue;
if (c == CHAR_RIGHT_CURLY_BRACKET) break;
if (c == CHAR_COMMA)
{
if (had_comma) return FALSE;
had_comma = TRUE;
}
else return FALSE;
}
/* The only error from read_number() is for a number that is too big. */
p = *ptrptr;
if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr)) if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
goto EXIT; goto EXIT;
if (p >= ptrend) goto EXIT;
if (*p == CHAR_RIGHT_CURLY_BRACKET) if (*p == CHAR_RIGHT_CURLY_BRACKET)
{ {
p++; p++;
max = min; max = min;
} }
else else
{ {
if (*p++ != CHAR_COMMA || p >= ptrend) goto EXIT; if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
if (*p != CHAR_RIGHT_CURLY_BRACKET)
{ {
if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max, if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max,
errorcodeptr) || p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET) errorcodeptr))
goto EXIT; goto EXIT;
if (max < min) if (max < min)
{ {
@ -1438,11 +1456,10 @@ yield = TRUE;
if (minp != NULL) *minp = (uint32_t)min; if (minp != NULL) *minp = (uint32_t)min;
if (maxp != NULL) *maxp = (uint32_t)max; if (maxp != NULL) *maxp = (uint32_t)max;
/* Update the pattern pointer on success, or after an error, but not when /* Update the pattern pointer */
the result is "not a repeat quantifier". */
EXIT: EXIT:
if (yield || *errorcodeptr != 0) *ptrptr = p; *ptrptr = p;
return yield; return yield;
} }
@ -1776,19 +1793,23 @@ else
{ {
oldptr = ptr; oldptr = ptr;
ptr--; /* Back to the digit */ ptr--; /* Back to the digit */
if (!read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, ERR61, &s,
errorcodeptr))
break;
/* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x /* As we know we are at a digit, the only possible error from
read_number() is a number that is too large to be a group number. In this
case we fall through handle this as not a group reference. If we have
read a small enough number, check for a back reference.
\1 to \9 are always back references. \8x and \9x are too; \1x to \7x
are octal escapes if there are not that many previous captures. */ are octal escapes if there are not that many previous captures. */
if (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount) if (read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, 0, &s, errorcodeptr) &&
(s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount))
{ {
if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61; if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61;
else escape = -s; /* Indicates a back reference */ else escape = -s; /* Indicates a back reference */
break; break;
} }
ptr = oldptr; /* Put the pointer back and fall through */ ptr = oldptr; /* Put the pointer back and fall through */
} }
@ -7781,6 +7802,16 @@ for (;; pptr++)
} }
#endif #endif
/* \K is forbidden in lookarounds since 10.38 because that's what Perl has
done. However, there's an option, in case anyone was relying on it. */
if (cb->assert_depth > 0 && meta_arg == ESC_K &&
(cb->cx->extra_options & PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) == 0)
{
*errorcodeptr = ERR99;
return 0;
}
/* For the rest (including \X when Unicode is supported - if not it's /* For the rest (including \X when Unicode is supported - if not it's
faulted at parse time), the OP value is the escape value when PCRE2_UCP is faulted at parse time), the OP value is the escape value when PCRE2_UCP is
not set; if it is set, these escapes do not show up here because they are not set; if it is set, these escapes do not show up here because they are
@ -9130,7 +9161,7 @@ for (;; pptr++)
case META_LOOKAHEAD: case META_LOOKAHEAD:
case META_LOOKAHEADNOT: case META_LOOKAHEADNOT:
case META_LOOKAHEAD_NA: case META_LOOKAHEAD_NA:
*errcodeptr = check_lookbehinds(pptr + 1, &pptr, recurses, cb); *errcodeptr = check_lookbehinds(pptr + 1, &pptr, recurses, cb, lcptr);
if (*errcodeptr != 0) return -1; if (*errcodeptr != 0) return -1;
/* Ignore any qualifiers that follow a lookahead assertion. */ /* Ignore any qualifiers that follow a lookahead assertion. */
@ -9470,16 +9501,16 @@ Arguments
retptr if not NULL, return the ket pointer here retptr if not NULL, return the ket pointer here
recurses chain of recurse_check to catch mutual recursion recurses chain of recurse_check to catch mutual recursion
cb points to the compile block cb points to the compile block
lcptr points to loop counter
Returns: 0 on success, or an errorcode (cb->erroroffset will be set) Returns: 0 on success, or an errorcode (cb->erroroffset will be set)
*/ */
static int static int
check_lookbehinds(uint32_t *pptr, uint32_t **retptr, check_lookbehinds(uint32_t *pptr, uint32_t **retptr,
parsed_recurse_check *recurses, compile_block *cb) parsed_recurse_check *recurses, compile_block *cb, int *lcptr)
{ {
int errorcode = 0; int errorcode = 0;
int loopcount = 0;
int nestlevel = 0; int nestlevel = 0;
cb->erroroffset = PCRE2_UNSET; cb->erroroffset = PCRE2_UNSET;
@ -9605,7 +9636,7 @@ for (; *pptr != META_END; pptr++)
case META_LOOKBEHIND: case META_LOOKBEHIND:
case META_LOOKBEHINDNOT: case META_LOOKBEHINDNOT:
case META_LOOKBEHIND_NA: case META_LOOKBEHIND_NA:
if (!set_lookbehind_lengths(&pptr, &errorcode, &loopcount, recurses, cb)) if (!set_lookbehind_lengths(&pptr, &errorcode, lcptr, recurses, cb))
return errorcode; return errorcode;
break; break;
} }
@ -10060,7 +10091,8 @@ lengths. */
if (has_lookbehind) if (has_lookbehind)
{ {
errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb); int loopcount = 0;
errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb, &loopcount);
if (errorcode != 0) goto HAD_CB_ERROR; if (errorcode != 0) goto HAD_CB_ERROR;
} }

View file

@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2016-2020 University of Cambridge New API code Copyright (c) 2016-2021 University of Cambridge
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -3256,8 +3256,8 @@ BOOL has_first_cu = FALSE;
BOOL has_req_cu = FALSE; BOOL has_req_cu = FALSE;
#if PCRE2_CODE_UNIT_WIDTH == 8 #if PCRE2_CODE_UNIT_WIDTH == 8
BOOL memchr_not_found_first_cu = FALSE; PCRE2_SPTR memchr_found_first_cu = NULL;
BOOL memchr_not_found_first_cu2 = FALSE; PCRE2_SPTR memchr_found_first_cu2 = NULL;
#endif #endif
PCRE2_UCHAR first_cu = 0; PCRE2_UCHAR first_cu = 0;
@ -3648,13 +3648,7 @@ for (;;)
} }
} }
/* Not anchored. Advance to a unique first code unit if there is one. In /* Not anchored. Advance to a unique first code unit if there is one. */
8-bit mode, the use of memchr() gives a big speed up, even though we have
to call it twice in caseless mode, in order to find the earliest occurrence
of the character in either of its cases. If a call to memchr() that
searches the rest of the subject fails to find one case, remember that in
order not to keep on repeating the search. This can make a huge difference
when the strings are very long and only one case is present. */
else else
{ {
@ -3662,43 +3656,68 @@ for (;;)
{ {
if (first_cu != first_cu2) /* Caseless */ if (first_cu != first_cu2) /* Caseless */
{ {
/* In 16-bit and 32_bit modes we have to do our own search, so can
look for both cases at once. */
#if PCRE2_CODE_UNIT_WIDTH != 8 #if PCRE2_CODE_UNIT_WIDTH != 8
PCRE2_UCHAR smc; PCRE2_UCHAR smc;
while (start_match < end_subject && while (start_match < end_subject &&
(smc = UCHAR21TEST(start_match)) != first_cu && (smc = UCHAR21TEST(start_match)) != first_cu &&
smc != first_cu2) smc != first_cu2)
start_match++; start_match++;
#else
/* In 8-bit mode, the use of memchr() gives a big speed up, even
though we have to call it twice in order to find the earliest
occurrence of the code unit in either of its cases. Caching is used
to remember the positions of previously found code units. This can
make a huge difference when the strings are very long and only one
case is actually present. */
#else /* 8-bit code units */
PCRE2_SPTR pp1 = NULL; PCRE2_SPTR pp1 = NULL;
PCRE2_SPTR pp2 = NULL; PCRE2_SPTR pp2 = NULL;
PCRE2_SIZE cu2size = end_subject - start_match; PCRE2_SIZE searchlength = end_subject - start_match;
if (!memchr_not_found_first_cu) /* If we haven't got a previously found position for first_cu, or if
the current starting position is later, we need to do a search. If
the code unit is not found, set it to the end. */
if (memchr_found_first_cu == NULL ||
start_match > memchr_found_first_cu)
{ {
pp1 = memchr(start_match, first_cu, end_subject - start_match); pp1 = memchr(start_match, first_cu, searchlength);
if (pp1 == NULL) memchr_not_found_first_cu = TRUE; memchr_found_first_cu = (pp1 == NULL)? end_subject : pp1;
else cu2size = pp1 - start_match;
} }
/* If pp1 is not NULL, we have arranged to search only as far as pp1, /* If the start is before a previously found position, use the
to see if the other case is earlier, so we can set "not found" only previous position, or NULL if a previous search failed. */
when both searches have returned NULL. */
if (!memchr_not_found_first_cu2) else pp1 = (memchr_found_first_cu == end_subject)? NULL :
memchr_found_first_cu;
/* Do the same thing for the other case. */
if (memchr_found_first_cu2 == NULL ||
start_match > memchr_found_first_cu2)
{ {
pp2 = memchr(start_match, first_cu2, cu2size); pp2 = memchr(start_match, first_cu2, searchlength);
memchr_not_found_first_cu2 = (pp2 == NULL && pp1 == NULL); memchr_found_first_cu2 = (pp2 == NULL)? end_subject : pp2;
} }
else pp2 = (memchr_found_first_cu2 == end_subject)? NULL :
memchr_found_first_cu2;
/* Set the start to the end of the subject if neither case was found.
Otherwise, use the earlier found point. */
if (pp1 == NULL) if (pp1 == NULL)
start_match = (pp2 == NULL)? end_subject : pp2; start_match = (pp2 == NULL)? end_subject : pp2;
else else
start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2; start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
#endif
#endif /* 8-bit handling */
} }
/* The caseful case */ /* The caseful case is much simpler. */
else else
{ {

View file

@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2016-2019 University of Cambridge New API code Copyright (c) 2016-2021 University of Cambridge
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -186,6 +186,7 @@ static const unsigned char compile_error_texts[] =
"script runs require Unicode support, which this version of PCRE2 does not have\0" "script runs require Unicode support, which this version of PCRE2 does not have\0"
"too many capturing groups (maximum 65535)\0" "too many capturing groups (maximum 65535)\0"
"atomic assertion expected after (?( or (?(?C)\0" "atomic assertion expected after (?( or (?(?C)\0"
"\\K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)\0"
; ;
/* Match-time and UTF error texts are in the same format. */ /* Match-time and UTF error texts are in the same format. */

View file

@ -1226,7 +1226,7 @@ while (cc < ccend)
return TRUE; return TRUE;
} }
#define EARLY_FAIL_ENHANCE_MAX (1 + 1) #define EARLY_FAIL_ENHANCE_MAX (1 + 3)
/* /*
start: start:
@ -1236,23 +1236,28 @@ start:
return: current number of iterators enhanced with fast fail return: current number of iterators enhanced with fast fail
*/ */
static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start, sljit_s32 depth, int start) static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start,
sljit_s32 depth, int start, BOOL fast_forward_allowed)
{ {
PCRE2_SPTR begin = cc;
PCRE2_SPTR next_alt; PCRE2_SPTR next_alt;
PCRE2_SPTR end; PCRE2_SPTR end;
PCRE2_SPTR accelerated_start; PCRE2_SPTR accelerated_start;
BOOL prev_fast_forward_allowed;
int result = 0; int result = 0;
int count; int count;
BOOL fast_forward_allowed = TRUE;
SLJIT_ASSERT(*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA); SLJIT_ASSERT(*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA);
SLJIT_ASSERT(*cc != OP_CBRA || common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] != 0); SLJIT_ASSERT(*cc != OP_CBRA || common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] != 0);
SLJIT_ASSERT(start < EARLY_FAIL_ENHANCE_MAX); SLJIT_ASSERT(start < EARLY_FAIL_ENHANCE_MAX);
next_alt = cc + GET(cc, 1);
if (*next_alt == OP_ALT)
fast_forward_allowed = FALSE;
do do
{ {
count = start; count = start;
next_alt = cc + GET(cc, 1);
cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0); cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0);
while (TRUE) while (TRUE)
@ -1475,31 +1480,20 @@ do
case OP_CBRA: case OP_CBRA:
end = cc + GET(cc, 1); end = cc + GET(cc, 1);
if (*end == OP_KET && PRIVATE_DATA(end) == 0) prev_fast_forward_allowed = fast_forward_allowed;
{
if (*cc == OP_CBRA)
{
if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
break;
cc += IMM2_SIZE;
}
cc += 1 + LINK_SIZE;
continue;
}
fast_forward_allowed = FALSE; fast_forward_allowed = FALSE;
if (depth >= 4) if (depth >= 4)
break; break;
end = bracketend(cc) - (1 + LINK_SIZE); end = bracketend(cc) - (1 + LINK_SIZE);
if (*end != OP_KET || PRIVATE_DATA(end) != 0) if (*end != OP_KET || (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0))
break; break;
if (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) count = detect_early_fail(common, cc, private_data_start, depth + 1, count, prev_fast_forward_allowed);
break;
if (PRIVATE_DATA(cc) != 0)
common->private_data_ptrs[begin - common->start] = 1;
count = detect_early_fail(common, cc, private_data_start, depth + 1, count);
if (count < EARLY_FAIL_ENHANCE_MAX) if (count < EARLY_FAIL_ENHANCE_MAX)
{ {
cc = end + (1 + LINK_SIZE); cc = end + (1 + LINK_SIZE);
@ -1521,7 +1515,7 @@ do
{ {
count++; count++;
if (fast_forward_allowed && *next_alt == OP_KET) if (fast_forward_allowed)
{ {
common->fast_forward_bc_ptr = accelerated_start; common->fast_forward_bc_ptr = accelerated_start;
common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_skip; common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_skip;
@ -1555,6 +1549,8 @@ do
return EARLY_FAIL_ENHANCE_MAX; return EARLY_FAIL_ENHANCE_MAX;
} }
/* Cannot be part of a repeat. */
common->private_data_ptrs[begin - common->start] = 1;
count++; count++;
if (count < EARLY_FAIL_ENHANCE_MAX) if (count < EARLY_FAIL_ENHANCE_MAX)
@ -1569,8 +1565,8 @@ do
else if (result < count) else if (result < count)
result = count; result = count;
fast_forward_allowed = FALSE;
cc = next_alt; cc = next_alt;
next_alt = cc + GET(cc, 1);
} }
while (*cc == OP_ALT); while (*cc == OP_ALT);
@ -1620,11 +1616,12 @@ sljit_sw length = end - begin;
sljit_s32 min, max, i; sljit_s32 min, max, i;
/* Detect fixed iterations first. */ /* Detect fixed iterations first. */
if (end[-(1 + LINK_SIZE)] != OP_KET) if (end[-(1 + LINK_SIZE)] != OP_KET || PRIVATE_DATA(begin) != 0)
return FALSE; return FALSE;
/* Already detected repeat. */ /* /(?:AB){4,6}/ is currently converted to /(?:AB){3}(?AB){1,3}/
if (common->private_data_ptrs[end - common->start - LINK_SIZE] != 0) * Skip the check of the second part. */
if (PRIVATE_DATA(end - LINK_SIZE) == 0)
return TRUE; return TRUE;
next = end; next = end;
@ -1763,6 +1760,7 @@ while (cc < ccend)
if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE)
break; break;
/* When the bracket is prefixed by a zero iteration, skip the repeat check (at this point). */
if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND))
{ {
if (detect_repeat(common, cc)) if (detect_repeat(common, cc))
@ -1813,6 +1811,7 @@ while (cc < ccend)
case OP_COND: case OP_COND:
/* Might be a hidden SCOND. */ /* Might be a hidden SCOND. */
common->private_data_ptrs[cc - common->start] = 0;
alternative = cc + GET(cc, 1); alternative = cc + GET(cc, 1);
if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
{ {
@ -4203,9 +4202,6 @@ TMP2 is not used. Otherwise TMP2 must contain the start of the subject buffer,
and it is destroyed. Does not modify STR_PTR for invalid character sequences. */ and it is destroyed. Does not modify STR_PTR for invalid character sequences. */
DEFINE_COMPILER; DEFINE_COMPILER;
SLJIT_UNUSED_ARG(backtracks);
SLJIT_UNUSED_ARG(must_be_valid);
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_jump *jump; struct sljit_jump *jump;
#endif #endif
@ -4279,6 +4275,10 @@ if (common->invalid_utf && !must_be_valid)
} }
#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ #endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
#endif /* SUPPORT_UNICODE */ #endif /* SUPPORT_UNICODE */
SLJIT_UNUSED_ARG(backtracks);
SLJIT_UNUSED_ARG(must_be_valid);
OP2(SLJIT_SUB, 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));
} }
@ -8141,7 +8141,7 @@ switch(type)
} }
else else
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
if (!common->endonly) if (!common->endonly)
compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks); compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks);
@ -8161,7 +8161,7 @@ switch(type)
} }
else else
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
check_partial(common, FALSE); check_partial(common, FALSE);
jump[0] = JUMP(SLJIT_JUMP); jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]); JUMPHERE(jump[1]);
@ -8201,14 +8201,14 @@ switch(type)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); 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)); add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
} }
else else
{ {
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0)); add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
} }
return cc; return cc;
@ -8227,7 +8227,7 @@ switch(type)
jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0); jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
} }
add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32)); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
jump[0] = JUMP(SLJIT_JUMP); jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]); JUMPHERE(jump[1]);
@ -9581,11 +9581,11 @@ free_stack(common, callout_arg_size);
/* Check return value. */ /* Check return value. */
OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); OP2(SLJIT_SUB32 | 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_GREATER32)); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER));
if (common->abort_label == NULL) if (common->abort_label == NULL)
add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */); add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */);
else else
JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->abort_label); JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->abort_label);
return cc + callout_length; return cc + callout_length;
} }
@ -11232,7 +11232,7 @@ early_fail_type = (early_fail_ptr & 0x7);
early_fail_ptr >>= 3; early_fail_ptr >>= 3;
/* During recursion, these optimizations are disabled. */ /* During recursion, these optimizations are disabled. */
if (common->early_fail_start_ptr == 0) if (common->early_fail_start_ptr == 0 && common->fast_forward_bc_ptr == NULL)
{ {
early_fail_ptr = 0; early_fail_ptr = 0;
early_fail_type = type_skip; early_fail_type = type_skip;
@ -13661,9 +13661,11 @@ if (!common->private_data_ptrs)
memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32)); memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw); private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
set_private_data_ptrs(common, &private_data_size, ccend);
if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && !common->has_skip_in_assert_back) if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && !common->has_skip_in_assert_back)
detect_early_fail(common, common->start, &private_data_size, 0, 0); detect_early_fail(common, common->start, &private_data_size, 0, 0, TRUE);
set_private_data_ptrs(common, &private_data_size, ccend);
SLJIT_ASSERT(common->early_fail_start_ptr <= common->early_fail_end_ptr); SLJIT_ASSERT(common->early_fail_start_ptr <= common->early_fail_end_ptr);
@ -14130,6 +14132,10 @@ PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_jit_compile(pcre2_code *code, uint32_t options) pcre2_jit_compile(pcre2_code *code, uint32_t options)
{ {
pcre2_real_code *re = (pcre2_real_code *)code; pcre2_real_code *re = (pcre2_real_code *)code;
#ifdef SUPPORT_JIT
executable_functions *functions;
static int executable_allocator_is_working = 0;
#endif
if (code == NULL) if (code == NULL)
return PCRE2_ERROR_NULL; return PCRE2_ERROR_NULL;
@ -14164,8 +14170,7 @@ actions are needed:
*/ */
#ifdef SUPPORT_JIT #ifdef SUPPORT_JIT
executable_functions *functions = (executable_functions *)re->executable_jit; functions = (executable_functions *)re->executable_jit;
static int executable_allocator_is_working = 0;
#endif #endif
if ((options & PCRE2_JIT_INVALID_UTF) != 0) if ((options & PCRE2_JIT_INVALID_UTF) != 0)

View file

@ -39,7 +39,29 @@ POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
*/ */
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) #if !(defined SUPPORT_VALGRIND)
#if ((defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X))
typedef enum {
vector_compare_match1,
vector_compare_match1i,
vector_compare_match2,
} vector_compare_type;
static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void)
{
#if PCRE2_CODE_UNIT_WIDTH == 8
return 15;
#elif PCRE2_CODE_UNIT_WIDTH == 16
return 7;
#elif PCRE2_CODE_UNIT_WIDTH == 32
return 3;
#else
#error "Unsupported unit width"
#endif
}
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg) static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg)
@ -56,6 +78,10 @@ return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00);
} }
#endif #endif
#endif /* SLJIT_CONFIG_X86 || SLJIT_CONFIG_S390X */
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
static sljit_s32 character_to_int32(PCRE2_UCHAR chr) static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
{ {
sljit_u32 value = chr; sljit_u32 value = chr;
@ -97,13 +123,7 @@ instruction[4] = (sljit_u8)offset;
sljit_emit_op_custom(compiler, instruction, 5); sljit_emit_op_custom(compiler, instruction, 5);
} }
typedef enum { static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
sse2_compare_match1,
sse2_compare_match1i,
sse2_compare_match2,
} sse2_compare_type;
static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, sse2_compare_type compare_type,
int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind) int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
{ {
sljit_u8 instruction[4]; sljit_u8 instruction[4];
@ -112,11 +132,11 @@ instruction[1] = 0x0f;
SLJIT_ASSERT(step >= 0 && step <= 3); SLJIT_ASSERT(step >= 0 && step <= 3);
if (compare_type != sse2_compare_match2) if (compare_type != vector_compare_match2)
{ {
if (step == 0) if (step == 0)
{ {
if (compare_type == sse2_compare_match1i) if (compare_type == vector_compare_match1i)
{ {
/* POR xmm1, xmm2/m128 */ /* POR xmm1, xmm2/m128 */
/* instruction[0] = 0x66; */ /* instruction[0] = 0x66; */
@ -185,14 +205,14 @@ switch (step)
static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset) static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
{ {
DEFINE_COMPILER; DEFINE_COMPILER;
sljit_u8 instruction[8];
struct sljit_label *start; struct sljit_label *start;
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_label *restart; struct sljit_label *restart;
#endif #endif
struct sljit_jump *quit; struct sljit_jump *quit;
struct sljit_jump *partial_quit[2]; struct sljit_jump *partial_quit[2];
sse2_compare_type compare_type = sse2_compare_match1; vector_compare_type compare_type = vector_compare_match1;
sljit_u8 instruction[8];
sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
sljit_s32 data_ind = 0; sljit_s32 data_ind = 0;
@ -207,12 +227,12 @@ SLJIT_UNUSED_ARG(offset);
if (char1 != char2) if (char1 != char2)
{ {
bit = char1 ^ char2; bit = char1 ^ char2;
compare_type = sse2_compare_match1i; compare_type = vector_compare_match1i;
if (!is_powerof2(bit)) if (!is_powerof2(bit))
{ {
bit = 0; bit = 0;
compare_type = sse2_compare_match2; compare_type = vector_compare_match2;
} }
} }
@ -349,11 +369,11 @@ if (common->utf && offset > 0)
static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2) static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
{ {
DEFINE_COMPILER; DEFINE_COMPILER;
sljit_u8 instruction[8];
struct sljit_label *start; struct sljit_label *start;
struct sljit_jump *quit; struct sljit_jump *quit;
jump_list *not_found = NULL; jump_list *not_found = NULL;
sse2_compare_type compare_type = sse2_compare_match1; vector_compare_type compare_type = vector_compare_match1;
sljit_u8 instruction[8];
sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
sljit_s32 data_ind = 0; sljit_s32 data_ind = 0;
@ -366,12 +386,12 @@ int i;
if (char1 != char2) if (char1 != char2)
{ {
bit = char1 ^ char2; bit = char1 ^ char2;
compare_type = sse2_compare_match1i; compare_type = vector_compare_match1i;
if (!is_powerof2(bit)) if (!is_powerof2(bit))
{ {
bit = 0; bit = 0;
compare_type = sse2_compare_match2; compare_type = vector_compare_match2;
} }
} }
@ -476,27 +496,15 @@ return not_found;
#ifndef _WIN64 #ifndef _WIN64
static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void)
{
#if PCRE2_CODE_UNIT_WIDTH == 8
return 15;
#elif PCRE2_CODE_UNIT_WIDTH == 16
return 7;
#elif PCRE2_CODE_UNIT_WIDTH == 32
return 3;
#else
#error "Unsupported unit width"
#endif
}
#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2)) #define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1, static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1,
PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b) PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
{ {
DEFINE_COMPILER; DEFINE_COMPILER;
sse2_compare_type compare1_type = sse2_compare_match1; sljit_u8 instruction[8];
sse2_compare_type compare2_type = sse2_compare_match1; vector_compare_type compare1_type = vector_compare_match1;
vector_compare_type compare2_type = vector_compare_match1;
sljit_u32 bit1 = 0; sljit_u32 bit1 = 0;
sljit_u32 bit2 = 0; sljit_u32 bit2 = 0;
sljit_u32 diff = IN_UCHARS(offs1 - offs2); sljit_u32 diff = IN_UCHARS(offs1 - offs2);
@ -516,7 +524,6 @@ struct sljit_label *start;
struct sljit_label *restart; struct sljit_label *restart;
#endif #endif
struct sljit_jump *jump[2]; struct sljit_jump *jump[2];
sljit_u8 instruction[8];
int i; int i;
SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2); SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
@ -549,13 +556,13 @@ else
bit1 = char1a ^ char1b; bit1 = char1a ^ char1b;
if (is_powerof2(bit1)) if (is_powerof2(bit1))
{ {
compare1_type = sse2_compare_match1i; compare1_type = vector_compare_match1i;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1));
} }
else else
{ {
compare1_type = sse2_compare_match2; compare1_type = vector_compare_match2;
bit1 = 0; bit1 = 0;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b));
@ -578,13 +585,13 @@ else
bit2 = char2a ^ char2b; bit2 = char2a ^ char2b;
if (is_powerof2(bit2)) if (is_powerof2(bit2))
{ {
compare2_type = sse2_compare_match1i; compare2_type = vector_compare_match1i;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2));
} }
else else
{ {
compare2_type = sse2_compare_match2; compare2_type = vector_compare_match2;
bit2 = 0; bit2 = 0;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b));
@ -731,9 +738,6 @@ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf) if (common->utf)
{ {
@ -760,7 +764,7 @@ if (common->match_end_ptr != 0)
#undef SSE2_COMPARE_TYPE_INDEX #undef SSE2_COMPARE_TYPE_INDEX
#endif /* SLJIT_CONFIG_X86 && !SUPPORT_VALGRIND */ #endif /* SLJIT_CONFIG_X86 */
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 && (defined __ARM_NEON || defined __ARM_NEON__)) #if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 && (defined __ARM_NEON || defined __ARM_NEON__))
@ -1121,3 +1125,734 @@ JUMPHERE(partial_quit);
} }
#endif /* SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 */ #endif /* SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 */
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
#if PCRE2_CODE_UNIT_WIDTH == 8
#define VECTOR_ELEMENT_SIZE 0
#elif PCRE2_CODE_UNIT_WIDTH == 16
#define VECTOR_ELEMENT_SIZE 1
#elif PCRE2_CODE_UNIT_WIDTH == 32
#define VECTOR_ELEMENT_SIZE 2
#else
#error "Unsupported unit width"
#endif
static void load_from_mem_vector(struct sljit_compiler *compiler, BOOL vlbb, sljit_s32 dst_vreg,
sljit_s32 base_reg, sljit_s32 index_reg)
{
sljit_u16 instruction[3];
instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | index_reg);
instruction[1] = (sljit_u16)(base_reg << 12);
instruction[2] = (sljit_u16)((0x8 << 8) | (vlbb ? 0x07 : 0x06));
sljit_emit_op_custom(compiler, instruction, 6);
}
#if PCRE2_CODE_UNIT_WIDTH == 32
static void replicate_imm_vector(struct sljit_compiler *compiler, int step, sljit_s32 dst_vreg,
PCRE2_UCHAR chr, sljit_s32 tmp_general_reg)
{
sljit_u16 instruction[3];
SLJIT_ASSERT(step >= 0 && step <= 1);
if (chr < 0x7fff)
{
if (step == 1)
return;
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4));
instruction[1] = (sljit_u16)chr;
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
return;
}
if (step == 0)
{
OP1(SLJIT_MOV, tmp_general_reg, 0, SLJIT_IMM, chr);
/* VLVG */
instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | sljit_get_register_index(tmp_general_reg));
instruction[1] = 0;
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x22);
sljit_emit_op_custom(compiler, instruction, 6);
return;
}
/* VREP */
instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | dst_vreg);
instruction[1] = 0;
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xc << 8) | 0x4d);
sljit_emit_op_custom(compiler, instruction, 6);
}
#endif
static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
{
sljit_u16 instruction[3];
SLJIT_ASSERT(step >= 0 && step <= 2);
if (step == 1)
{
/* VCEQ */
instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind);
instruction[1] = (sljit_u16)(cmp1_ind << 12);
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0xf8);
sljit_emit_op_custom(compiler, instruction, 6);
return;
}
if (compare_type != vector_compare_match2)
{
if (step == 0 && compare_type == vector_compare_match1i)
{
/* VO */
instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind);
instruction[1] = (sljit_u16)(cmp2_ind << 12);
instruction[2] = (sljit_u16)((0xe << 8) | 0x6a);
sljit_emit_op_custom(compiler, instruction, 6);
}
return;
}
switch (step)
{
case 0:
/* VCEQ */
instruction[0] = (sljit_u16)(0xe700 | (tmp_ind << 4) | dst_ind);
instruction[1] = (sljit_u16)(cmp2_ind << 12);
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0xf8);
sljit_emit_op_custom(compiler, instruction, 6);
return;
case 2:
/* VO */
instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind);
instruction[1] = (sljit_u16)(tmp_ind << 12);
instruction[2] = (sljit_u16)((0xe << 8) | 0x6a);
sljit_emit_op_custom(compiler, instruction, 6);
return;
}
}
#define JIT_HAS_FAST_FORWARD_CHAR_SIMD 1
static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
{
DEFINE_COMPILER;
sljit_u16 instruction[3];
struct sljit_label *start;
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_label *restart;
#endif
struct sljit_jump *quit;
struct sljit_jump *partial_quit[2];
vector_compare_type compare_type = vector_compare_match1;
sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
sljit_s32 data_ind = 0;
sljit_s32 tmp_ind = 1;
sljit_s32 cmp1_ind = 2;
sljit_s32 cmp2_ind = 3;
sljit_s32 zero_ind = 4;
sljit_u32 bit = 0;
int i;
SLJIT_UNUSED_ARG(offset);
if (char1 != char2)
{
bit = char1 ^ char2;
compare_type = vector_compare_match1i;
if (!is_powerof2(bit))
{
bit = 0;
compare_type = vector_compare_match2;
}
}
partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, &common->failed_match, partial_quit[0]);
/* First part (unaligned start) */
OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 16);
#if PCRE2_CODE_UNIT_WIDTH != 32
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp1_ind << 4));
instruction[1] = (sljit_u16)(char1 | bit);
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
if (char1 != char2)
{
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp2_ind << 4));
instruction[1] = (sljit_u16)(bit != 0 ? bit : char2);
/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
sljit_emit_op_custom(compiler, instruction, 6);
}
#else /* PCRE2_CODE_UNIT_WIDTH == 32 */
for (int i = 0; i < 2; i++)
{
replicate_imm_vector(compiler, i, cmp1_ind, char1 | bit, TMP1);
if (char1 != char2)
replicate_imm_vector(compiler, i, cmp2_ind, bit != 0 ? bit : char2, TMP1);
}
#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
if (compare_type == vector_compare_match2)
{
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4));
instruction[1] = 0;
instruction[2] = (sljit_u16)((0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
}
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
restart = LABEL();
#endif
load_from_mem_vector(compiler, TRUE, data_ind, str_ptr_reg_ind, 0);
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, ~15);
if (compare_type != vector_compare_match2)
{
if (compare_type == vector_compare_match1i)
fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFEE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
sljit_emit_op_custom(compiler, instruction, 6);
}
else
{
for (i = 0; i < 3; i++)
fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFENE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
sljit_emit_op_custom(compiler, instruction, 6);
}
/* VLGVB */
instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data_ind);
instruction[1] = 7;
instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
sljit_emit_op_custom(compiler, instruction, 6);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
quit = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_SUB, STR_PTR, 0, TMP2, 0, SLJIT_IMM, 16);
/* Second part (aligned) */
start = LABEL();
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, &common->failed_match, partial_quit[1]);
load_from_mem_vector(compiler, TRUE, data_ind, str_ptr_reg_ind, 0);
if (compare_type != vector_compare_match2)
{
if (compare_type == vector_compare_match1i)
fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFEE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
sljit_emit_op_custom(compiler, instruction, 6);
}
else
{
for (i = 0; i < 3; i++)
fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFENE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
sljit_emit_op_custom(compiler, instruction, 6);
}
sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW);
JUMPTO(SLJIT_OVERFLOW, start);
/* VLGVB */
instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data_ind);
instruction[1] = 7;
instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
sljit_emit_op_custom(compiler, instruction, 6);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
JUMPHERE(quit);
if (common->mode != PCRE2_JIT_COMPLETE)
{
JUMPHERE(partial_quit[0]);
JUMPHERE(partial_quit[1]);
OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
}
else
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf && offset > 0)
{
SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
quit = jump_if_utf_char_start(compiler, TMP1);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 16);
JUMPTO(SLJIT_JUMP, restart);
JUMPHERE(quit);
}
#endif
}
#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD 1
static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
{
DEFINE_COMPILER;
sljit_u16 instruction[3];
struct sljit_label *start;
struct sljit_jump *quit;
jump_list *not_found = NULL;
vector_compare_type compare_type = vector_compare_match1;
sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
sljit_s32 tmp3_reg_ind = sljit_get_register_index(TMP3);
sljit_s32 data_ind = 0;
sljit_s32 tmp_ind = 1;
sljit_s32 cmp1_ind = 2;
sljit_s32 cmp2_ind = 3;
sljit_s32 zero_ind = 4;
sljit_u32 bit = 0;
int i;
if (char1 != char2)
{
bit = char1 ^ char2;
compare_type = vector_compare_match1i;
if (!is_powerof2(bit))
{
bit = 0;
compare_type = vector_compare_match2;
}
}
add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
/* First part (unaligned start) */
OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, 16);
#if PCRE2_CODE_UNIT_WIDTH != 32
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp1_ind << 4));
instruction[1] = (sljit_u16)(char1 | bit);
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
if (char1 != char2)
{
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp2_ind << 4));
instruction[1] = (sljit_u16)(bit != 0 ? bit : char2);
/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
sljit_emit_op_custom(compiler, instruction, 6);
}
#else /* PCRE2_CODE_UNIT_WIDTH == 32 */
for (int i = 0; i < 2; i++)
{
replicate_imm_vector(compiler, i, cmp1_ind, char1 | bit, TMP3);
if (char1 != char2)
replicate_imm_vector(compiler, i, cmp2_ind, bit != 0 ? bit : char2, TMP3);
}
#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
if (compare_type == vector_compare_match2)
{
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4));
instruction[1] = 0;
instruction[2] = (sljit_u16)((0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
}
load_from_mem_vector(compiler, TRUE, data_ind, tmp1_reg_ind, 0);
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, ~15);
if (compare_type != vector_compare_match2)
{
if (compare_type == vector_compare_match1i)
fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFEE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
sljit_emit_op_custom(compiler, instruction, 6);
}
else
{
for (i = 0; i < 3; i++)
fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFENE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
sljit_emit_op_custom(compiler, instruction, 6);
}
/* VLGVB */
instruction[0] = (sljit_u16)(0xe700 | (tmp3_reg_ind << 4) | data_ind);
instruction[1] = 7;
instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
sljit_emit_op_custom(compiler, instruction, 6);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0);
quit = CMP(SLJIT_LESS, TMP1, 0, TMP2, 0);
OP2(SLJIT_SUB, TMP1, 0, TMP2, 0, SLJIT_IMM, 16);
/* Second part (aligned) */
start = LABEL();
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 16);
add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
load_from_mem_vector(compiler, TRUE, data_ind, tmp1_reg_ind, 0);
if (compare_type != vector_compare_match2)
{
if (compare_type == vector_compare_match1i)
fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFEE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
sljit_emit_op_custom(compiler, instruction, 6);
}
else
{
for (i = 0; i < 3; i++)
fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
/* VFENE */
instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
sljit_emit_op_custom(compiler, instruction, 6);
}
sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW);
JUMPTO(SLJIT_OVERFLOW, start);
/* VLGVB */
instruction[0] = (sljit_u16)(0xe700 | (tmp3_reg_ind << 4) | data_ind);
instruction[1] = 7;
instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
sljit_emit_op_custom(compiler, instruction, 6);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0);
JUMPHERE(quit);
add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
return not_found;
}
#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD 1
static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1,
PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
{
DEFINE_COMPILER;
sljit_u16 instruction[3];
struct sljit_label *start;
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_label *restart;
#endif
struct sljit_jump *quit;
struct sljit_jump *jump[2];
vector_compare_type compare1_type = vector_compare_match1;
vector_compare_type compare2_type = vector_compare_match1;
sljit_u32 bit1 = 0;
sljit_u32 bit2 = 0;
sljit_s32 diff = IN_UCHARS(offs2 - offs1);
sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
sljit_s32 tmp2_reg_ind = sljit_get_register_index(TMP2);
sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
sljit_s32 data1_ind = 0;
sljit_s32 data2_ind = 1;
sljit_s32 tmp1_ind = 2;
sljit_s32 tmp2_ind = 3;
sljit_s32 cmp1a_ind = 4;
sljit_s32 cmp1b_ind = 5;
sljit_s32 cmp2a_ind = 6;
sljit_s32 cmp2b_ind = 7;
sljit_s32 zero_ind = 8;
int i;
SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
SLJIT_ASSERT(-diff <= (sljit_s32)IN_UCHARS(max_fast_forward_char_pair_offset()));
SLJIT_ASSERT(tmp1_reg_ind != 0 && tmp2_reg_ind != 0);
if (char1a != char1b)
{
bit1 = char1a ^ char1b;
compare1_type = vector_compare_match1i;
if (!is_powerof2(bit1))
{
bit1 = 0;
compare1_type = vector_compare_match2;
}
}
if (char2a != char2b)
{
bit2 = char2a ^ char2b;
compare2_type = vector_compare_match1i;
if (!is_powerof2(bit2))
{
bit2 = 0;
compare2_type = vector_compare_match2;
}
}
/* Initialize. */
if (common->match_end_ptr != 0)
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0);
CMOV(SLJIT_LESS, STR_END, TMP1, 0);
}
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, ~15);
#if PCRE2_CODE_UNIT_WIDTH != 32
OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff);
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp1a_ind << 4));
instruction[1] = (sljit_u16)(char1a | bit1);
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
if (char1a != char1b)
{
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp1b_ind << 4));
instruction[1] = (sljit_u16)(bit1 != 0 ? bit1 : char1b);
/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
sljit_emit_op_custom(compiler, instruction, 6);
}
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp2a_ind << 4));
instruction[1] = (sljit_u16)(char2a | bit2);
/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
sljit_emit_op_custom(compiler, instruction, 6);
if (char2a != char2b)
{
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (cmp2b_ind << 4));
instruction[1] = (sljit_u16)(bit2 != 0 ? bit2 : char2b);
/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
sljit_emit_op_custom(compiler, instruction, 6);
}
#else /* PCRE2_CODE_UNIT_WIDTH == 32 */
for (int i = 0; i < 2; i++)
{
replicate_imm_vector(compiler, i, cmp1a_ind, char1a | bit1, TMP1);
if (char1a != char1b)
replicate_imm_vector(compiler, i, cmp1b_ind, bit1 != 0 ? bit1 : char1b, TMP1);
replicate_imm_vector(compiler, i, cmp2a_ind, char2a | bit2, TMP1);
if (char2a != char2b)
replicate_imm_vector(compiler, i, cmp2b_ind, bit2 != 0 ? bit2 : char2b, TMP1);
}
OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff);
#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
/* VREPI */
instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4));
instruction[1] = 0;
instruction[2] = (sljit_u16)((0x8 << 8) | 0x45);
sljit_emit_op_custom(compiler, instruction, 6);
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
restart = LABEL();
#endif
jump[0] = CMP(SLJIT_LESS, TMP1, 0, TMP2, 0);
load_from_mem_vector(compiler, TRUE, data2_ind, tmp1_reg_ind, 0);
jump[1] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[0]);
load_from_mem_vector(compiler, FALSE, data2_ind, tmp1_reg_ind, 0);
JUMPHERE(jump[1]);
load_from_mem_vector(compiler, TRUE, data1_ind, str_ptr_reg_ind, 0);
OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 16);
for (i = 0; i < 3; i++)
{
fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
}
/* VN */
instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
instruction[1] = (sljit_u16)(data2_ind << 12);
instruction[2] = (sljit_u16)((0xe << 8) | 0x68);
sljit_emit_op_custom(compiler, instruction, 6);
/* VFENE */
instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
sljit_emit_op_custom(compiler, instruction, 6);
/* VLGVB */
instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data1_ind);
instruction[1] = 7;
instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
sljit_emit_op_custom(compiler, instruction, 6);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
quit = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_SUB, STR_PTR, 0, TMP2, 0, SLJIT_IMM, 16);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, diff);
/* Main loop. */
start = LABEL();
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
load_from_mem_vector(compiler, FALSE, data1_ind, str_ptr_reg_ind, 0);
load_from_mem_vector(compiler, FALSE, data2_ind, str_ptr_reg_ind, tmp1_reg_ind);
for (i = 0; i < 3; i++)
{
fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
}
/* VN */
instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
instruction[1] = (sljit_u16)(data2_ind << 12);
instruction[2] = (sljit_u16)((0xe << 8) | 0x68);
sljit_emit_op_custom(compiler, instruction, 6);
/* VFENE */
instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
sljit_emit_op_custom(compiler, instruction, 6);
sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW);
JUMPTO(SLJIT_OVERFLOW, start);
/* VLGVB */
instruction[0] = (sljit_u16)(0xe700 | (tmp2_reg_ind << 4) | data1_ind);
instruction[1] = 7;
instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
sljit_emit_op_custom(compiler, instruction, 6);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
JUMPHERE(quit);
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf)
{
SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1));
quit = jump_if_utf_char_start(compiler, TMP1);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
/* TMP1 contains diff. */
OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, ~15);
OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff);
JUMPTO(SLJIT_JUMP, restart);
JUMPHERE(quit);
}
#endif
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
}
#endif /* SLJIT_CONFIG_S390X */
#endif /* !SUPPORT_VALGRIND */

View file

@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2015-2020 University of Cambridge New API code Copyright (c) 2015-2021 University of Cambridge
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -818,10 +818,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* N is now the frame of the recursion; the previous frame is at the /* N is now the frame of the recursion; the previous frame is at the
OP_RECURSE position. Go back there, copying the current subject position OP_RECURSE position. Go back there, copying the current subject position
and mark, and move on past the OP_RECURSE. */ and mark, and the start_match position (\K might have changed it), and
then move on past the OP_RECURSE. */
P->eptr = Feptr; P->eptr = Feptr;
P->mark = Fmark; P->mark = Fmark;
P->start_match = Fstart_match;
F = P; F = P;
Fecode += 1 + LINK_SIZE; Fecode += 1 + LINK_SIZE;
continue; continue;
@ -6115,8 +6117,8 @@ BOOL has_req_cu = FALSE;
BOOL startline; BOOL startline;
#if PCRE2_CODE_UNIT_WIDTH == 8 #if PCRE2_CODE_UNIT_WIDTH == 8
BOOL memchr_not_found_first_cu; PCRE2_SPTR memchr_found_first_cu;
BOOL memchr_not_found_first_cu2; PCRE2_SPTR memchr_found_first_cu2;
#endif #endif
PCRE2_UCHAR first_cu = 0; PCRE2_UCHAR first_cu = 0;
@ -6710,8 +6712,8 @@ start_partial = match_partial = NULL;
mb->hitend = FALSE; mb->hitend = FALSE;
#if PCRE2_CODE_UNIT_WIDTH == 8 #if PCRE2_CODE_UNIT_WIDTH == 8
memchr_not_found_first_cu = FALSE; memchr_found_first_cu = NULL;
memchr_not_found_first_cu2 = FALSE; memchr_found_first_cu2 = NULL;
#endif #endif
for(;;) for(;;)
@ -6780,13 +6782,7 @@ for(;;)
} }
} }
/* Not anchored. Advance to a unique first code unit if there is one. In /* Not anchored. Advance to a unique first code unit if there is one. */
8-bit mode, the use of memchr() gives a big speed up, even though we have
to call it twice in caseless mode, in order to find the earliest occurrence
of the character in either of its cases. If a call to memchr() that
searches the rest of the subject fails to find one case, remember that in
order not to keep on repeating the search. This can make a huge difference
when the strings are very long and only one case is present. */
else else
{ {
@ -6794,43 +6790,68 @@ for(;;)
{ {
if (first_cu != first_cu2) /* Caseless */ if (first_cu != first_cu2) /* Caseless */
{ {
/* In 16-bit and 32_bit modes we have to do our own search, so can
look for both cases at once. */
#if PCRE2_CODE_UNIT_WIDTH != 8 #if PCRE2_CODE_UNIT_WIDTH != 8
PCRE2_UCHAR smc; PCRE2_UCHAR smc;
while (start_match < end_subject && while (start_match < end_subject &&
(smc = UCHAR21TEST(start_match)) != first_cu && (smc = UCHAR21TEST(start_match)) != first_cu &&
smc != first_cu2) smc != first_cu2)
start_match++; start_match++;
#else
/* In 8-bit mode, the use of memchr() gives a big speed up, even
though we have to call it twice in order to find the earliest
occurrence of the code unit in either of its cases. Caching is used
to remember the positions of previously found code units. This can
make a huge difference when the strings are very long and only one
case is actually present. */
#else /* 8-bit code units */
PCRE2_SPTR pp1 = NULL; PCRE2_SPTR pp1 = NULL;
PCRE2_SPTR pp2 = NULL; PCRE2_SPTR pp2 = NULL;
PCRE2_SIZE cu2size = end_subject - start_match; PCRE2_SIZE searchlength = end_subject - start_match;
if (!memchr_not_found_first_cu) /* If we haven't got a previously found position for first_cu, or if
the current starting position is later, we need to do a search. If
the code unit is not found, set it to the end. */
if (memchr_found_first_cu == NULL ||
start_match > memchr_found_first_cu)
{ {
pp1 = memchr(start_match, first_cu, end_subject - start_match); pp1 = memchr(start_match, first_cu, searchlength);
if (pp1 == NULL) memchr_not_found_first_cu = TRUE; memchr_found_first_cu = (pp1 == NULL)? end_subject : pp1;
else cu2size = pp1 - start_match;
} }
/* If pp1 is not NULL, we have arranged to search only as far as pp1, /* If the start is before a previously found position, use the
to see if the other case is earlier, so we can set "not found" only previous position, or NULL if a previous search failed. */
when both searches have returned NULL. */
if (!memchr_not_found_first_cu2) else pp1 = (memchr_found_first_cu == end_subject)? NULL :
memchr_found_first_cu;
/* Do the same thing for the other case. */
if (memchr_found_first_cu2 == NULL ||
start_match > memchr_found_first_cu2)
{ {
pp2 = memchr(start_match, first_cu2, cu2size); pp2 = memchr(start_match, first_cu2, searchlength);
memchr_not_found_first_cu2 = (pp2 == NULL && pp1 == NULL); memchr_found_first_cu2 = (pp2 == NULL)? end_subject : pp2;
} }
else pp2 = (memchr_found_first_cu2 == end_subject)? NULL :
memchr_found_first_cu2;
/* Set the start to the end of the subject if neither case was found.
Otherwise, use the earlier found point. */
if (pp1 == NULL) if (pp1 == NULL)
start_match = (pp2 == NULL)? end_subject : pp2; start_match = (pp2 == NULL)? end_subject : pp2;
else else
start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2; start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
#endif
#endif /* 8-bit handling */
} }
/* The caseful case */ /* The caseful case is much simpler. */
else else
{ {

View file

@ -273,6 +273,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Cs0 STR_C STR_s "\0" #define STRING_Cs0 STR_C STR_s "\0"
#define STRING_Cuneiform0 STR_C STR_u STR_n STR_e STR_i STR_f STR_o STR_r STR_m "\0" #define STRING_Cuneiform0 STR_C STR_u STR_n STR_e STR_i STR_f STR_o STR_r STR_m "\0"
#define STRING_Cypriot0 STR_C STR_y STR_p STR_r STR_i STR_o STR_t "\0" #define STRING_Cypriot0 STR_C STR_y STR_p STR_r STR_i STR_o STR_t "\0"
#define STRING_Cypro_Minoan0 STR_C STR_y STR_p STR_r STR_o STR_UNDERSCORE STR_M STR_i STR_n STR_o STR_a STR_n "\0"
#define STRING_Cyrillic0 STR_C STR_y STR_r STR_i STR_l STR_l STR_i STR_c "\0" #define STRING_Cyrillic0 STR_C STR_y STR_r STR_i STR_l STR_l STR_i STR_c "\0"
#define STRING_Deseret0 STR_D STR_e STR_s STR_e STR_r STR_e STR_t "\0" #define STRING_Deseret0 STR_D STR_e STR_s STR_e STR_r STR_e STR_t "\0"
#define STRING_Devanagari0 STR_D STR_e STR_v STR_a STR_n STR_a STR_g STR_a STR_r STR_i "\0" #define STRING_Devanagari0 STR_D STR_e STR_v STR_a STR_n STR_a STR_g STR_a STR_r STR_i "\0"
@ -371,6 +372,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Old_Sogdian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0" #define STRING_Old_Sogdian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0"
#define STRING_Old_South_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_u STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0" #define STRING_Old_South_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_u STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
#define STRING_Old_Turkic0 STR_O STR_l STR_d STR_UNDERSCORE STR_T STR_u STR_r STR_k STR_i STR_c "\0" #define STRING_Old_Turkic0 STR_O STR_l STR_d STR_UNDERSCORE STR_T STR_u STR_r STR_k STR_i STR_c "\0"
#define STRING_Old_Uyghur0 STR_O STR_l STR_d STR_UNDERSCORE STR_U STR_y STR_g STR_h STR_u STR_r "\0"
#define STRING_Oriya0 STR_O STR_r STR_i STR_y STR_a "\0" #define STRING_Oriya0 STR_O STR_r STR_i STR_y STR_a "\0"
#define STRING_Osage0 STR_O STR_s STR_a STR_g STR_e "\0" #define STRING_Osage0 STR_O STR_s STR_a STR_g STR_e "\0"
#define STRING_Osmanya0 STR_O STR_s STR_m STR_a STR_n STR_y STR_a "\0" #define STRING_Osmanya0 STR_O STR_s STR_m STR_a STR_n STR_y STR_a "\0"
@ -415,6 +417,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Tai_Viet0 STR_T STR_a STR_i STR_UNDERSCORE STR_V STR_i STR_e STR_t "\0" #define STRING_Tai_Viet0 STR_T STR_a STR_i STR_UNDERSCORE STR_V STR_i STR_e STR_t "\0"
#define STRING_Takri0 STR_T STR_a STR_k STR_r STR_i "\0" #define STRING_Takri0 STR_T STR_a STR_k STR_r STR_i "\0"
#define STRING_Tamil0 STR_T STR_a STR_m STR_i STR_l "\0" #define STRING_Tamil0 STR_T STR_a STR_m STR_i STR_l "\0"
#define STRING_Tangsa0 STR_T STR_a STR_n STR_g STR_s STR_a "\0"
#define STRING_Tangut0 STR_T STR_a STR_n STR_g STR_u STR_t "\0" #define STRING_Tangut0 STR_T STR_a STR_n STR_g STR_u STR_t "\0"
#define STRING_Telugu0 STR_T STR_e STR_l STR_u STR_g STR_u "\0" #define STRING_Telugu0 STR_T STR_e STR_l STR_u STR_g STR_u "\0"
#define STRING_Thaana0 STR_T STR_h STR_a STR_a STR_n STR_a "\0" #define STRING_Thaana0 STR_T STR_h STR_a STR_a STR_n STR_a "\0"
@ -422,9 +425,11 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Tibetan0 STR_T STR_i STR_b STR_e STR_t STR_a STR_n "\0" #define STRING_Tibetan0 STR_T STR_i STR_b STR_e STR_t STR_a STR_n "\0"
#define STRING_Tifinagh0 STR_T STR_i STR_f STR_i STR_n STR_a STR_g STR_h "\0" #define STRING_Tifinagh0 STR_T STR_i STR_f STR_i STR_n STR_a STR_g STR_h "\0"
#define STRING_Tirhuta0 STR_T STR_i STR_r STR_h STR_u STR_t STR_a "\0" #define STRING_Tirhuta0 STR_T STR_i STR_r STR_h STR_u STR_t STR_a "\0"
#define STRING_Toto0 STR_T STR_o STR_t STR_o "\0"
#define STRING_Ugaritic0 STR_U STR_g STR_a STR_r STR_i STR_t STR_i STR_c "\0" #define STRING_Ugaritic0 STR_U STR_g STR_a STR_r STR_i STR_t STR_i STR_c "\0"
#define STRING_Unknown0 STR_U STR_n STR_k STR_n STR_o STR_w STR_n "\0" #define STRING_Unknown0 STR_U STR_n STR_k STR_n STR_o STR_w STR_n "\0"
#define STRING_Vai0 STR_V STR_a STR_i "\0" #define STRING_Vai0 STR_V STR_a STR_i "\0"
#define STRING_Vithkuqi0 STR_V STR_i STR_t STR_h STR_k STR_u STR_q STR_i "\0"
#define STRING_Wancho0 STR_W STR_a STR_n STR_c STR_h STR_o "\0" #define STRING_Wancho0 STR_W STR_a STR_n STR_c STR_h STR_o "\0"
#define STRING_Warang_Citi0 STR_W STR_a STR_r STR_a STR_n STR_g STR_UNDERSCORE STR_C STR_i STR_t STR_i "\0" #define STRING_Warang_Citi0 STR_W STR_a STR_r STR_a STR_n STR_g STR_UNDERSCORE STR_C STR_i STR_t STR_i "\0"
#define STRING_Xan0 STR_X STR_a STR_n "\0" #define STRING_Xan0 STR_X STR_a STR_n "\0"
@ -476,6 +481,7 @@ const char PRIV(utt_names)[] =
STRING_Cs0 STRING_Cs0
STRING_Cuneiform0 STRING_Cuneiform0
STRING_Cypriot0 STRING_Cypriot0
STRING_Cypro_Minoan0
STRING_Cyrillic0 STRING_Cyrillic0
STRING_Deseret0 STRING_Deseret0
STRING_Devanagari0 STRING_Devanagari0
@ -574,6 +580,7 @@ const char PRIV(utt_names)[] =
STRING_Old_Sogdian0 STRING_Old_Sogdian0
STRING_Old_South_Arabian0 STRING_Old_South_Arabian0
STRING_Old_Turkic0 STRING_Old_Turkic0
STRING_Old_Uyghur0
STRING_Oriya0 STRING_Oriya0
STRING_Osage0 STRING_Osage0
STRING_Osmanya0 STRING_Osmanya0
@ -618,6 +625,7 @@ const char PRIV(utt_names)[] =
STRING_Tai_Viet0 STRING_Tai_Viet0
STRING_Takri0 STRING_Takri0
STRING_Tamil0 STRING_Tamil0
STRING_Tangsa0
STRING_Tangut0 STRING_Tangut0
STRING_Telugu0 STRING_Telugu0
STRING_Thaana0 STRING_Thaana0
@ -625,9 +633,11 @@ const char PRIV(utt_names)[] =
STRING_Tibetan0 STRING_Tibetan0
STRING_Tifinagh0 STRING_Tifinagh0
STRING_Tirhuta0 STRING_Tirhuta0
STRING_Toto0
STRING_Ugaritic0 STRING_Ugaritic0
STRING_Unknown0 STRING_Unknown0
STRING_Vai0 STRING_Vai0
STRING_Vithkuqi0
STRING_Wancho0 STRING_Wancho0
STRING_Warang_Citi0 STRING_Warang_Citi0
STRING_Xan0 STRING_Xan0
@ -679,172 +689,177 @@ const ucp_type_table PRIV(utt)[] = {
{ 255, PT_PC, ucp_Cs }, { 255, PT_PC, ucp_Cs },
{ 258, PT_SC, ucp_Cuneiform }, { 258, PT_SC, ucp_Cuneiform },
{ 268, PT_SC, ucp_Cypriot }, { 268, PT_SC, ucp_Cypriot },
{ 276, PT_SC, ucp_Cyrillic }, { 276, PT_SC, ucp_Cypro_Minoan },
{ 285, PT_SC, ucp_Deseret }, { 289, PT_SC, ucp_Cyrillic },
{ 293, PT_SC, ucp_Devanagari }, { 298, PT_SC, ucp_Deseret },
{ 304, PT_SC, ucp_Dives_Akuru }, { 306, PT_SC, ucp_Devanagari },
{ 316, PT_SC, ucp_Dogra }, { 317, PT_SC, ucp_Dives_Akuru },
{ 322, PT_SC, ucp_Duployan }, { 329, PT_SC, ucp_Dogra },
{ 331, PT_SC, ucp_Egyptian_Hieroglyphs }, { 335, PT_SC, ucp_Duployan },
{ 352, PT_SC, ucp_Elbasan }, { 344, PT_SC, ucp_Egyptian_Hieroglyphs },
{ 360, PT_SC, ucp_Elymaic }, { 365, PT_SC, ucp_Elbasan },
{ 368, PT_SC, ucp_Ethiopic }, { 373, PT_SC, ucp_Elymaic },
{ 377, PT_SC, ucp_Georgian }, { 381, PT_SC, ucp_Ethiopic },
{ 386, PT_SC, ucp_Glagolitic }, { 390, PT_SC, ucp_Georgian },
{ 397, PT_SC, ucp_Gothic }, { 399, PT_SC, ucp_Glagolitic },
{ 404, PT_SC, ucp_Grantha }, { 410, PT_SC, ucp_Gothic },
{ 412, PT_SC, ucp_Greek }, { 417, PT_SC, ucp_Grantha },
{ 418, PT_SC, ucp_Gujarati }, { 425, PT_SC, ucp_Greek },
{ 427, PT_SC, ucp_Gunjala_Gondi }, { 431, PT_SC, ucp_Gujarati },
{ 441, PT_SC, ucp_Gurmukhi }, { 440, PT_SC, ucp_Gunjala_Gondi },
{ 450, PT_SC, ucp_Han }, { 454, PT_SC, ucp_Gurmukhi },
{ 454, PT_SC, ucp_Hangul }, { 463, PT_SC, ucp_Han },
{ 461, PT_SC, ucp_Hanifi_Rohingya }, { 467, PT_SC, ucp_Hangul },
{ 477, PT_SC, ucp_Hanunoo }, { 474, PT_SC, ucp_Hanifi_Rohingya },
{ 485, PT_SC, ucp_Hatran }, { 490, PT_SC, ucp_Hanunoo },
{ 492, PT_SC, ucp_Hebrew }, { 498, PT_SC, ucp_Hatran },
{ 499, PT_SC, ucp_Hiragana }, { 505, PT_SC, ucp_Hebrew },
{ 508, PT_SC, ucp_Imperial_Aramaic }, { 512, PT_SC, ucp_Hiragana },
{ 525, PT_SC, ucp_Inherited }, { 521, PT_SC, ucp_Imperial_Aramaic },
{ 535, PT_SC, ucp_Inscriptional_Pahlavi }, { 538, PT_SC, ucp_Inherited },
{ 557, PT_SC, ucp_Inscriptional_Parthian }, { 548, PT_SC, ucp_Inscriptional_Pahlavi },
{ 580, PT_SC, ucp_Javanese }, { 570, PT_SC, ucp_Inscriptional_Parthian },
{ 589, PT_SC, ucp_Kaithi }, { 593, PT_SC, ucp_Javanese },
{ 596, PT_SC, ucp_Kannada }, { 602, PT_SC, ucp_Kaithi },
{ 604, PT_SC, ucp_Katakana }, { 609, PT_SC, ucp_Kannada },
{ 613, PT_SC, ucp_Kayah_Li }, { 617, PT_SC, ucp_Katakana },
{ 622, PT_SC, ucp_Kharoshthi }, { 626, PT_SC, ucp_Kayah_Li },
{ 633, PT_SC, ucp_Khitan_Small_Script }, { 635, PT_SC, ucp_Kharoshthi },
{ 653, PT_SC, ucp_Khmer }, { 646, PT_SC, ucp_Khitan_Small_Script },
{ 659, PT_SC, ucp_Khojki }, { 666, PT_SC, ucp_Khmer },
{ 666, PT_SC, ucp_Khudawadi }, { 672, PT_SC, ucp_Khojki },
{ 676, PT_GC, ucp_L }, { 679, PT_SC, ucp_Khudawadi },
{ 678, PT_LAMP, 0 }, { 689, PT_GC, ucp_L },
{ 681, PT_SC, ucp_Lao }, { 691, PT_LAMP, 0 },
{ 685, PT_SC, ucp_Latin }, { 694, PT_SC, ucp_Lao },
{ 691, PT_SC, ucp_Lepcha }, { 698, PT_SC, ucp_Latin },
{ 698, PT_SC, ucp_Limbu }, { 704, PT_SC, ucp_Lepcha },
{ 704, PT_SC, ucp_Linear_A }, { 711, PT_SC, ucp_Limbu },
{ 713, PT_SC, ucp_Linear_B }, { 717, PT_SC, ucp_Linear_A },
{ 722, PT_SC, ucp_Lisu }, { 726, PT_SC, ucp_Linear_B },
{ 727, PT_PC, ucp_Ll }, { 735, PT_SC, ucp_Lisu },
{ 730, PT_PC, ucp_Lm }, { 740, PT_PC, ucp_Ll },
{ 733, PT_PC, ucp_Lo }, { 743, PT_PC, ucp_Lm },
{ 736, PT_PC, ucp_Lt }, { 746, PT_PC, ucp_Lo },
{ 739, PT_PC, ucp_Lu }, { 749, PT_PC, ucp_Lt },
{ 742, PT_SC, ucp_Lycian }, { 752, PT_PC, ucp_Lu },
{ 749, PT_SC, ucp_Lydian }, { 755, PT_SC, ucp_Lycian },
{ 756, PT_GC, ucp_M }, { 762, PT_SC, ucp_Lydian },
{ 758, PT_SC, ucp_Mahajani }, { 769, PT_GC, ucp_M },
{ 767, PT_SC, ucp_Makasar }, { 771, PT_SC, ucp_Mahajani },
{ 775, PT_SC, ucp_Malayalam }, { 780, PT_SC, ucp_Makasar },
{ 785, PT_SC, ucp_Mandaic }, { 788, PT_SC, ucp_Malayalam },
{ 793, PT_SC, ucp_Manichaean }, { 798, PT_SC, ucp_Mandaic },
{ 804, PT_SC, ucp_Marchen }, { 806, PT_SC, ucp_Manichaean },
{ 812, PT_SC, ucp_Masaram_Gondi }, { 817, PT_SC, ucp_Marchen },
{ 826, PT_PC, ucp_Mc }, { 825, PT_SC, ucp_Masaram_Gondi },
{ 829, PT_PC, ucp_Me }, { 839, PT_PC, ucp_Mc },
{ 832, PT_SC, ucp_Medefaidrin }, { 842, PT_PC, ucp_Me },
{ 844, PT_SC, ucp_Meetei_Mayek }, { 845, PT_SC, ucp_Medefaidrin },
{ 857, PT_SC, ucp_Mende_Kikakui }, { 857, PT_SC, ucp_Meetei_Mayek },
{ 871, PT_SC, ucp_Meroitic_Cursive }, { 870, PT_SC, ucp_Mende_Kikakui },
{ 888, PT_SC, ucp_Meroitic_Hieroglyphs }, { 884, PT_SC, ucp_Meroitic_Cursive },
{ 909, PT_SC, ucp_Miao }, { 901, PT_SC, ucp_Meroitic_Hieroglyphs },
{ 914, PT_PC, ucp_Mn }, { 922, PT_SC, ucp_Miao },
{ 917, PT_SC, ucp_Modi }, { 927, PT_PC, ucp_Mn },
{ 922, PT_SC, ucp_Mongolian }, { 930, PT_SC, ucp_Modi },
{ 932, PT_SC, ucp_Mro }, { 935, PT_SC, ucp_Mongolian },
{ 936, PT_SC, ucp_Multani }, { 945, PT_SC, ucp_Mro },
{ 944, PT_SC, ucp_Myanmar }, { 949, PT_SC, ucp_Multani },
{ 952, PT_GC, ucp_N }, { 957, PT_SC, ucp_Myanmar },
{ 954, PT_SC, ucp_Nabataean }, { 965, PT_GC, ucp_N },
{ 964, PT_SC, ucp_Nandinagari }, { 967, PT_SC, ucp_Nabataean },
{ 976, PT_PC, ucp_Nd }, { 977, PT_SC, ucp_Nandinagari },
{ 979, PT_SC, ucp_New_Tai_Lue }, { 989, PT_PC, ucp_Nd },
{ 991, PT_SC, ucp_Newa }, { 992, PT_SC, ucp_New_Tai_Lue },
{ 996, PT_SC, ucp_Nko }, { 1004, PT_SC, ucp_Newa },
{ 1000, PT_PC, ucp_Nl }, { 1009, PT_SC, ucp_Nko },
{ 1003, PT_PC, ucp_No }, { 1013, PT_PC, ucp_Nl },
{ 1006, PT_SC, ucp_Nushu }, { 1016, PT_PC, ucp_No },
{ 1012, PT_SC, ucp_Nyiakeng_Puachue_Hmong }, { 1019, PT_SC, ucp_Nushu },
{ 1035, PT_SC, ucp_Ogham }, { 1025, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
{ 1041, PT_SC, ucp_Ol_Chiki }, { 1048, PT_SC, ucp_Ogham },
{ 1050, PT_SC, ucp_Old_Hungarian }, { 1054, PT_SC, ucp_Ol_Chiki },
{ 1064, PT_SC, ucp_Old_Italic }, { 1063, PT_SC, ucp_Old_Hungarian },
{ 1075, PT_SC, ucp_Old_North_Arabian }, { 1077, PT_SC, ucp_Old_Italic },
{ 1093, PT_SC, ucp_Old_Permic }, { 1088, PT_SC, ucp_Old_North_Arabian },
{ 1104, PT_SC, ucp_Old_Persian }, { 1106, PT_SC, ucp_Old_Permic },
{ 1116, PT_SC, ucp_Old_Sogdian }, { 1117, PT_SC, ucp_Old_Persian },
{ 1128, PT_SC, ucp_Old_South_Arabian }, { 1129, PT_SC, ucp_Old_Sogdian },
{ 1146, PT_SC, ucp_Old_Turkic }, { 1141, PT_SC, ucp_Old_South_Arabian },
{ 1157, PT_SC, ucp_Oriya }, { 1159, PT_SC, ucp_Old_Turkic },
{ 1163, PT_SC, ucp_Osage }, { 1170, PT_SC, ucp_Old_Uyghur },
{ 1169, PT_SC, ucp_Osmanya }, { 1181, PT_SC, ucp_Oriya },
{ 1177, PT_GC, ucp_P }, { 1187, PT_SC, ucp_Osage },
{ 1179, PT_SC, ucp_Pahawh_Hmong }, { 1193, PT_SC, ucp_Osmanya },
{ 1192, PT_SC, ucp_Palmyrene }, { 1201, PT_GC, ucp_P },
{ 1202, PT_SC, ucp_Pau_Cin_Hau }, { 1203, PT_SC, ucp_Pahawh_Hmong },
{ 1214, PT_PC, ucp_Pc }, { 1216, PT_SC, ucp_Palmyrene },
{ 1217, PT_PC, ucp_Pd }, { 1226, PT_SC, ucp_Pau_Cin_Hau },
{ 1220, PT_PC, ucp_Pe }, { 1238, PT_PC, ucp_Pc },
{ 1223, PT_PC, ucp_Pf }, { 1241, PT_PC, ucp_Pd },
{ 1226, PT_SC, ucp_Phags_Pa }, { 1244, PT_PC, ucp_Pe },
{ 1235, PT_SC, ucp_Phoenician }, { 1247, PT_PC, ucp_Pf },
{ 1246, PT_PC, ucp_Pi }, { 1250, PT_SC, ucp_Phags_Pa },
{ 1249, PT_PC, ucp_Po }, { 1259, PT_SC, ucp_Phoenician },
{ 1252, PT_PC, ucp_Ps }, { 1270, PT_PC, ucp_Pi },
{ 1255, PT_SC, ucp_Psalter_Pahlavi }, { 1273, PT_PC, ucp_Po },
{ 1271, PT_SC, ucp_Rejang }, { 1276, PT_PC, ucp_Ps },
{ 1278, PT_SC, ucp_Runic }, { 1279, PT_SC, ucp_Psalter_Pahlavi },
{ 1284, PT_GC, ucp_S }, { 1295, PT_SC, ucp_Rejang },
{ 1286, PT_SC, ucp_Samaritan }, { 1302, PT_SC, ucp_Runic },
{ 1296, PT_SC, ucp_Saurashtra }, { 1308, PT_GC, ucp_S },
{ 1307, PT_PC, ucp_Sc }, { 1310, PT_SC, ucp_Samaritan },
{ 1310, PT_SC, ucp_Sharada }, { 1320, PT_SC, ucp_Saurashtra },
{ 1318, PT_SC, ucp_Shavian }, { 1331, PT_PC, ucp_Sc },
{ 1326, PT_SC, ucp_Siddham }, { 1334, PT_SC, ucp_Sharada },
{ 1334, PT_SC, ucp_SignWriting }, { 1342, PT_SC, ucp_Shavian },
{ 1346, PT_SC, ucp_Sinhala }, { 1350, PT_SC, ucp_Siddham },
{ 1354, PT_PC, ucp_Sk }, { 1358, PT_SC, ucp_SignWriting },
{ 1357, PT_PC, ucp_Sm }, { 1370, PT_SC, ucp_Sinhala },
{ 1360, PT_PC, ucp_So }, { 1378, PT_PC, ucp_Sk },
{ 1363, PT_SC, ucp_Sogdian }, { 1381, PT_PC, ucp_Sm },
{ 1371, PT_SC, ucp_Sora_Sompeng }, { 1384, PT_PC, ucp_So },
{ 1384, PT_SC, ucp_Soyombo }, { 1387, PT_SC, ucp_Sogdian },
{ 1392, PT_SC, ucp_Sundanese }, { 1395, PT_SC, ucp_Sora_Sompeng },
{ 1402, PT_SC, ucp_Syloti_Nagri }, { 1408, PT_SC, ucp_Soyombo },
{ 1415, PT_SC, ucp_Syriac }, { 1416, PT_SC, ucp_Sundanese },
{ 1422, PT_SC, ucp_Tagalog }, { 1426, PT_SC, ucp_Syloti_Nagri },
{ 1430, PT_SC, ucp_Tagbanwa }, { 1439, PT_SC, ucp_Syriac },
{ 1439, PT_SC, ucp_Tai_Le }, { 1446, PT_SC, ucp_Tagalog },
{ 1446, PT_SC, ucp_Tai_Tham }, { 1454, PT_SC, ucp_Tagbanwa },
{ 1455, PT_SC, ucp_Tai_Viet }, { 1463, PT_SC, ucp_Tai_Le },
{ 1464, PT_SC, ucp_Takri }, { 1470, PT_SC, ucp_Tai_Tham },
{ 1470, PT_SC, ucp_Tamil }, { 1479, PT_SC, ucp_Tai_Viet },
{ 1476, PT_SC, ucp_Tangut }, { 1488, PT_SC, ucp_Takri },
{ 1483, PT_SC, ucp_Telugu }, { 1494, PT_SC, ucp_Tamil },
{ 1490, PT_SC, ucp_Thaana }, { 1500, PT_SC, ucp_Tangsa },
{ 1497, PT_SC, ucp_Thai }, { 1507, PT_SC, ucp_Tangut },
{ 1502, PT_SC, ucp_Tibetan }, { 1514, PT_SC, ucp_Telugu },
{ 1510, PT_SC, ucp_Tifinagh }, { 1521, PT_SC, ucp_Thaana },
{ 1519, PT_SC, ucp_Tirhuta }, { 1528, PT_SC, ucp_Thai },
{ 1527, PT_SC, ucp_Ugaritic }, { 1533, PT_SC, ucp_Tibetan },
{ 1536, PT_SC, ucp_Unknown }, { 1541, PT_SC, ucp_Tifinagh },
{ 1544, PT_SC, ucp_Vai }, { 1550, PT_SC, ucp_Tirhuta },
{ 1548, PT_SC, ucp_Wancho }, { 1558, PT_SC, ucp_Toto },
{ 1555, PT_SC, ucp_Warang_Citi }, { 1563, PT_SC, ucp_Ugaritic },
{ 1567, PT_ALNUM, 0 }, { 1572, PT_SC, ucp_Unknown },
{ 1571, PT_PXSPACE, 0 }, { 1580, PT_SC, ucp_Vai },
{ 1575, PT_SPACE, 0 }, { 1584, PT_SC, ucp_Vithkuqi },
{ 1579, PT_UCNC, 0 }, { 1593, PT_SC, ucp_Wancho },
{ 1583, PT_WORD, 0 }, { 1600, PT_SC, ucp_Warang_Citi },
{ 1587, PT_SC, ucp_Yezidi }, { 1612, PT_ALNUM, 0 },
{ 1594, PT_SC, ucp_Yi }, { 1616, PT_PXSPACE, 0 },
{ 1597, PT_GC, ucp_Z }, { 1620, PT_SPACE, 0 },
{ 1599, PT_SC, ucp_Zanabazar_Square }, { 1624, PT_UCNC, 0 },
{ 1616, PT_PC, ucp_Zl }, { 1628, PT_WORD, 0 },
{ 1619, PT_PC, ucp_Zp }, { 1632, PT_SC, ucp_Yezidi },
{ 1622, PT_PC, ucp_Zs } { 1639, PT_SC, ucp_Yi },
{ 1642, PT_GC, ucp_Z },
{ 1644, PT_SC, ucp_Zanabazar_Square },
{ 1661, PT_PC, ucp_Zl },
{ 1664, PT_PC, ucp_Zp },
{ 1667, PT_PC, ucp_Zs }
}; };
const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table); const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);

File diff suppressed because it is too large Load diff

View file

@ -291,7 +291,13 @@ enum {
ucp_Chorasmian, ucp_Chorasmian,
ucp_Dives_Akuru, ucp_Dives_Akuru,
ucp_Khitan_Small_Script, ucp_Khitan_Small_Script,
ucp_Yezidi ucp_Yezidi,
/* New for Unicode 14.0.0 */
ucp_Cypro_Minoan,
ucp_Old_Uyghur,
ucp_Tangsa,
ucp_Toto,
ucp_Vithkuqi
}; };
#endif /* PCRE2_UCP_H_IDEMPOTENT_GUARD */ #endif /* PCRE2_UCP_H_IDEMPOTENT_GUARD */

View file

@ -158,6 +158,8 @@ extern "C" {
#define SLJIT_CONFIG_MIPS_64 1 #define SLJIT_CONFIG_MIPS_64 1
#elif defined(__sparc__) || defined(__sparc) #elif defined(__sparc__) || defined(__sparc)
#define SLJIT_CONFIG_SPARC_32 1 #define SLJIT_CONFIG_SPARC_32 1
#elif defined(__s390x__)
#define SLJIT_CONFIG_S390X 1
#else #else
/* Unsupported architecture */ /* Unsupported architecture */
#define SLJIT_CONFIG_UNSUPPORTED 1 #define SLJIT_CONFIG_UNSUPPORTED 1
@ -759,6 +761,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \ #define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS) (SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
/********************************/
/* CPU status flags management. */
/********************************/
#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|| (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \
|| (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC) \
|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
#define SLJIT_HAS_STATUS_FLAGS_STATE 1
#endif
/*************************************/ /*************************************/
/* Debug and verbose related macros. */ /* Debug and verbose related macros. */
/*************************************/ /*************************************/

View file

@ -79,6 +79,7 @@
*/ */
#ifdef _WIN32 #ifdef _WIN32
#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
static SLJIT_INLINE void* alloc_chunk(sljit_uw size) static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{ {
@ -91,96 +92,108 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
VirtualFree(chunk, 0, MEM_RELEASE); VirtualFree(chunk, 0, MEM_RELEASE);
} }
#else #else /* POSIX */
#ifdef __APPLE__
#ifdef MAP_ANON
/* Configures TARGET_OS_OSX when appropriate */
#include <TargetConditionals.h>
#if TARGET_OS_OSX && defined(MAP_JIT)
#include <sys/utsname.h>
#endif /* TARGET_OS_OSX && MAP_JIT */
#ifdef MAP_JIT
#if defined(__APPLE__) && defined(MAP_JIT)
/* /*
On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a
version where it's OK to have more than one JIT block. version where it's OK to have more than one JIT block or where MAP_JIT is
required.
On non-macOS systems, returns MAP_JIT if it is defined. On non-macOS systems, returns MAP_JIT if it is defined.
*/ */
#include <TargetConditionals.h>
#if TARGET_OS_OSX
#if defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86
#ifdef MAP_ANON
#include <sys/utsname.h>
#include <stdlib.h>
#define SLJIT_MAP_JIT (get_map_jit_flag())
static SLJIT_INLINE int get_map_jit_flag() static SLJIT_INLINE int get_map_jit_flag()
{ {
#if TARGET_OS_OSX sljit_sw page_size;
sljit_sw page_size = get_page_alignment() + 1;
void *ptr; void *ptr;
struct utsname name;
static int map_jit_flag = -1; static int map_jit_flag = -1;
/* if (map_jit_flag < 0) {
The following code is thread safe because multiple initialization
sets map_jit_flag to the same value and the code has no side-effects.
Changing the kernel version witout system restart is (very) unlikely.
*/
if (map_jit_flag == -1) {
struct utsname name;
map_jit_flag = 0; map_jit_flag = 0;
uname(&name); uname(&name);
/* Kernel version for 10.14.0 (Mojave) */ /* Kernel version for 10.14.0 (Mojave) or later */
if (atoi(name.release) >= 18) { if (atoi(name.release) >= 18) {
page_size = get_page_alignment() + 1;
/* Only use MAP_JIT if a hardened runtime is used */ /* Only use MAP_JIT if a hardened runtime is used */
ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON, -1, 0);
ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); if (ptr != MAP_FAILED)
if (ptr == MAP_FAILED) {
map_jit_flag = MAP_JIT;
} else {
munmap(ptr, page_size); munmap(ptr, page_size);
else
map_jit_flag = MAP_JIT;
} }
} }
}
return map_jit_flag; return map_jit_flag;
#else /* !TARGET_OS_OSX */
return MAP_JIT;
#endif /* TARGET_OS_OSX */
} }
#endif /* MAP_JIT */
#endif /* MAP_ANON */ #endif /* MAP_ANON */
#endif /* __APPLE__ */ #else /* !SLJIT_CONFIG_X86 */
#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
#error Unsupported architecture
#endif /* SLJIT_CONFIG_ARM */
#include <pthread.h>
#define SLJIT_MAP_JIT (MAP_JIT)
#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
apple_update_wx_flags(enable_exec)
static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
{
pthread_jit_write_protect_np(enable_exec);
}
#endif /* SLJIT_CONFIG_X86 */
#else /* !TARGET_OS_OSX */
#define SLJIT_MAP_JIT (MAP_JIT)
#endif /* TARGET_OS_OSX */
#endif /* __APPLE__ && MAP_JIT */
#ifndef SLJIT_UPDATE_WX_FLAGS
#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
#endif /* !SLJIT_UPDATE_WX_FLAGS */
#ifndef SLJIT_MAP_JIT
#define SLJIT_MAP_JIT (0)
#endif /* !SLJIT_MAP_JIT */
static SLJIT_INLINE void* alloc_chunk(sljit_uw size) static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{ {
void *retval; void *retval;
const int prot = PROT_READ | PROT_WRITE | PROT_EXEC; int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int flags = MAP_PRIVATE;
int fd = -1;
#ifdef MAP_ANON #ifdef PROT_MAX
prot |= PROT_MAX(prot);
int flags = MAP_PRIVATE | MAP_ANON;
#ifdef MAP_JIT
flags |= get_map_jit_flag();
#endif #endif
retval = mmap(NULL, size, prot, flags, -1, 0); #ifdef MAP_ANON
flags |= MAP_ANON | SLJIT_MAP_JIT;
#else /* !MAP_ANON */ #else /* !MAP_ANON */
if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero())) if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
return NULL; return NULL;
retval = mmap(NULL, size, prot, MAP_PRIVATE, dev_zero, 0); fd = dev_zero;
#endif /* MAP_ANON */ #endif /* MAP_ANON */
retval = mmap(NULL, size, prot, flags, fd, 0);
if (retval == MAP_FAILED) if (retval == MAP_FAILED)
retval = NULL; return NULL;
else {
if (mprotect(retval, size, prot) < 0) { if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
munmap(retval, size); munmap(retval, size);
retval = NULL; return NULL;
}
} }
SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0);
return retval; return retval;
} }
@ -189,7 +202,7 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
munmap(chunk, size); munmap(chunk, size);
} }
#endif #endif /* windows */
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* Common functions */ /* Common functions */
@ -261,6 +274,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
while (free_block) { while (free_block) {
if (free_block->size >= size) { if (free_block->size >= size) {
chunk_size = free_block->size; chunk_size = free_block->size;
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
if (chunk_size > size + 64) { if (chunk_size > size + 64) {
/* We just cut a block from the end of the free block. */ /* We just cut a block from the end of the free block. */
chunk_size -= size; chunk_size -= size;
@ -326,6 +340,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
allocated_size -= header->size; allocated_size -= header->size;
/* Connecting free blocks together if possible. */ /* Connecting free blocks together if possible. */
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
/* If header->prev_size == 0, free_block will equal to header. /* If header->prev_size == 0, free_block will equal to header.
In this case, free_block->header.size will be > 0. */ In this case, free_block->header.size will be > 0. */
@ -358,6 +373,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
} }
} }
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
SLJIT_ALLOCATOR_UNLOCK(); SLJIT_ALLOCATOR_UNLOCK();
} }
@ -367,6 +383,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
struct free_block* next_free_block; struct free_block* next_free_block;
SLJIT_ALLOCATOR_LOCK(); SLJIT_ALLOCATOR_LOCK();
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
free_block = free_blocks; free_block = free_blocks;
while (free_block) { while (free_block) {
@ -381,5 +398,6 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
} }
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks)); SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
SLJIT_ALLOCATOR_UNLOCK(); SLJIT_ALLOCATOR_UNLOCK();
} }

View file

@ -532,13 +532,21 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_la
put_label->label = label; put_label->label = label;
} }
#define SLJIT_CURRENT_FLAGS_ALL \
(SLJIT_CURRENT_FLAGS_I32_OP | SLJIT_CURRENT_FLAGS_ADD_SUB | SLJIT_CURRENT_FLAGS_COMPARE)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags) SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
{ {
SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(current_flags); SLJIT_UNUSED_ARG(current_flags);
#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
compiler->status_flags_state = current_flags;
#endif
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_I32_OP | SLJIT_SET_Z)) == 0) { compiler->last_flags = 0;
if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_SET_Z | SLJIT_CURRENT_FLAGS_ALL)) == 0) {
compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_I32_OP | SLJIT_SET_Z)); compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_I32_OP | SLJIT_SET_Z));
} }
#endif #endif
@ -968,7 +976,7 @@ static const char* fop2_names[] = {
}; };
#define JUMP_POSTFIX(type) \ #define JUMP_POSTFIX(type) \
((type & 0xff) <= SLJIT_MUL_NOT_OVERFLOW ? ((type & SLJIT_I32_OP) ? "32" : "") \ ((type & 0xff) <= SLJIT_NOT_OVERFLOW ? ((type & SLJIT_I32_OP) ? "32" : "") \
: ((type & 0xff) <= SLJIT_ORDERED_F64 ? ((type & SLJIT_F32_OP) ? ".f32" : ".f64") : "")) : ((type & 0xff) <= SLJIT_ORDERED_F64 ? ((type & SLJIT_F32_OP) ? ".f32" : ".f64") : ""))
static char* jump_names[] = { static char* jump_names[] = {
@ -978,7 +986,6 @@ static char* jump_names[] = {
(char*)"sig_less", (char*)"sig_greater_equal", (char*)"sig_less", (char*)"sig_greater_equal",
(char*)"sig_greater", (char*)"sig_less_equal", (char*)"sig_greater", (char*)"sig_less_equal",
(char*)"overflow", (char*)"not_overflow", (char*)"overflow", (char*)"not_overflow",
(char*)"mul_overflow", (char*)"mul_not_overflow",
(char*)"carry", (char*)"", (char*)"carry", (char*)"",
(char*)"equal", (char*)"not_equal", (char*)"equal", (char*)"not_equal",
(char*)"less", (char*)"greater_equal", (char*)"less", (char*)"greater_equal",
@ -1278,7 +1285,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler
case SLJIT_MUL: case SLJIT_MUL:
CHECK_ARGUMENT(!(op & SLJIT_SET_Z)); CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
|| GET_FLAG_TYPE(op) == SLJIT_MUL_OVERFLOW); || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
break; break;
case SLJIT_ADD: case SLJIT_ADD:
CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
@ -1601,9 +1608,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compile
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z); CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else else
CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff) CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
|| ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW) || ((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 #endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@ -1818,8 +1823,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z); CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else else
CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff) CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
|| ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW) || ((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); FUNCTION_CHECK_DST(dst, dstw, 0);
@ -1858,8 +1862,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compile
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z); CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else else
CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff) CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
|| ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW) || ((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 #endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) { if (SLJIT_UNLIKELY(!!compiler->verbose)) {

View file

@ -412,6 +412,10 @@ struct sljit_compiler {
/* Executable size for statistical purposes. */ /* Executable size for statistical purposes. */
sljit_uw executable_size; sljit_uw executable_size;
#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
sljit_s32 status_flags_state;
#endif
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
sljit_s32 args; sljit_s32 args;
sljit_s32 locals_offset; sljit_s32 locals_offset;
@ -460,7 +464,7 @@ struct sljit_compiler {
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) #if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
/* Need to allocate register save area to make calls. */ /* Need to allocate register save area to make calls. */
sljit_s32 have_save_area; sljit_s32 mode;
#endif #endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@ -996,7 +1000,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
#define SLJIT_SUBC (SLJIT_OP2_BASE + 3) #define SLJIT_SUBC (SLJIT_OP2_BASE + 3)
#define SLJIT_SUBC32 (SLJIT_SUBC | SLJIT_I32_OP) #define SLJIT_SUBC32 (SLJIT_SUBC | SLJIT_I32_OP)
/* Note: integer mul /* Note: integer mul
Flags: MUL_OVERFLOW */ Flags: OVERFLOW */
#define SLJIT_MUL (SLJIT_OP2_BASE + 4) #define SLJIT_MUL (SLJIT_OP2_BASE + 4)
#define SLJIT_MUL32 (SLJIT_MUL | SLJIT_I32_OP) #define SLJIT_MUL32 (SLJIT_MUL | SLJIT_I32_OP)
/* Flags: Z */ /* Flags: Z */
@ -1141,89 +1145,69 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
/* Integer comparison types. */ /* Integer comparison types. */
#define SLJIT_EQUAL 0 #define SLJIT_EQUAL 0
#define SLJIT_EQUAL32 (SLJIT_EQUAL | SLJIT_I32_OP) #define SLJIT_ZERO SLJIT_EQUAL
#define SLJIT_ZERO 0
#define SLJIT_ZERO32 (SLJIT_ZERO | SLJIT_I32_OP)
#define SLJIT_NOT_EQUAL 1 #define SLJIT_NOT_EQUAL 1
#define SLJIT_NOT_EQUAL32 (SLJIT_NOT_EQUAL | SLJIT_I32_OP) #define SLJIT_NOT_ZERO SLJIT_NOT_EQUAL
#define SLJIT_NOT_ZERO 1
#define SLJIT_NOT_ZERO32 (SLJIT_NOT_ZERO | SLJIT_I32_OP)
#define SLJIT_LESS 2 #define SLJIT_LESS 2
#define SLJIT_LESS32 (SLJIT_LESS | SLJIT_I32_OP)
#define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS) #define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS)
#define SLJIT_GREATER_EQUAL 3 #define SLJIT_GREATER_EQUAL 3
#define SLJIT_GREATER_EQUAL32 (SLJIT_GREATER_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_GREATER_EQUAL) #define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_GREATER_EQUAL)
#define SLJIT_GREATER 4 #define SLJIT_GREATER 4
#define SLJIT_GREATER32 (SLJIT_GREATER | SLJIT_I32_OP)
#define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER) #define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER)
#define SLJIT_LESS_EQUAL 5 #define SLJIT_LESS_EQUAL 5
#define SLJIT_LESS_EQUAL32 (SLJIT_LESS_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_LESS_EQUAL) #define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_LESS_EQUAL)
#define SLJIT_SIG_LESS 6 #define SLJIT_SIG_LESS 6
#define SLJIT_SIG_LESS32 (SLJIT_SIG_LESS | SLJIT_I32_OP)
#define SLJIT_SET_SIG_LESS SLJIT_SET(SLJIT_SIG_LESS) #define SLJIT_SET_SIG_LESS SLJIT_SET(SLJIT_SIG_LESS)
#define SLJIT_SIG_GREATER_EQUAL 7 #define SLJIT_SIG_GREATER_EQUAL 7
#define SLJIT_SIG_GREATER_EQUAL32 (SLJIT_SIG_GREATER_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_GREATER_EQUAL) #define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_GREATER_EQUAL)
#define SLJIT_SIG_GREATER 8 #define SLJIT_SIG_GREATER 8
#define SLJIT_SIG_GREATER32 (SLJIT_SIG_GREATER | SLJIT_I32_OP)
#define SLJIT_SET_SIG_GREATER SLJIT_SET(SLJIT_SIG_GREATER) #define SLJIT_SET_SIG_GREATER SLJIT_SET(SLJIT_SIG_GREATER)
#define SLJIT_SIG_LESS_EQUAL 9 #define SLJIT_SIG_LESS_EQUAL 9
#define SLJIT_SIG_LESS_EQUAL32 (SLJIT_SIG_LESS_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_LESS_EQUAL) #define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_LESS_EQUAL)
#define SLJIT_OVERFLOW 10 #define SLJIT_OVERFLOW 10
#define SLJIT_OVERFLOW32 (SLJIT_OVERFLOW | SLJIT_I32_OP)
#define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW) #define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW)
#define SLJIT_NOT_OVERFLOW 11 #define SLJIT_NOT_OVERFLOW 11
#define SLJIT_NOT_OVERFLOW32 (SLJIT_NOT_OVERFLOW | SLJIT_I32_OP)
#define SLJIT_MUL_OVERFLOW 12
#define SLJIT_MUL_OVERFLOW32 (SLJIT_MUL_OVERFLOW | SLJIT_I32_OP)
#define SLJIT_SET_MUL_OVERFLOW SLJIT_SET(SLJIT_MUL_OVERFLOW)
#define SLJIT_MUL_NOT_OVERFLOW 13
#define SLJIT_MUL_NOT_OVERFLOW32 (SLJIT_MUL_NOT_OVERFLOW | SLJIT_I32_OP)
/* There is no SLJIT_CARRY or SLJIT_NOT_CARRY. */ /* There is no SLJIT_CARRY or SLJIT_NOT_CARRY. */
#define SLJIT_SET_CARRY SLJIT_SET(14) #define SLJIT_SET_CARRY SLJIT_SET(12)
/* Floating point comparison types. */ /* Floating point comparison types. */
#define SLJIT_EQUAL_F64 16 #define SLJIT_EQUAL_F64 14
#define SLJIT_EQUAL_F32 (SLJIT_EQUAL_F64 | SLJIT_F32_OP) #define SLJIT_EQUAL_F32 (SLJIT_EQUAL_F64 | SLJIT_F32_OP)
#define SLJIT_SET_EQUAL_F SLJIT_SET(SLJIT_EQUAL_F64) #define SLJIT_SET_EQUAL_F SLJIT_SET(SLJIT_EQUAL_F64)
#define SLJIT_NOT_EQUAL_F64 17 #define SLJIT_NOT_EQUAL_F64 15
#define SLJIT_NOT_EQUAL_F32 (SLJIT_NOT_EQUAL_F64 | SLJIT_F32_OP) #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_SET_NOT_EQUAL_F SLJIT_SET(SLJIT_NOT_EQUAL_F64)
#define SLJIT_LESS_F64 18 #define SLJIT_LESS_F64 16
#define SLJIT_LESS_F32 (SLJIT_LESS_F64 | SLJIT_F32_OP) #define SLJIT_LESS_F32 (SLJIT_LESS_F64 | SLJIT_F32_OP)
#define SLJIT_SET_LESS_F SLJIT_SET(SLJIT_LESS_F64) #define SLJIT_SET_LESS_F SLJIT_SET(SLJIT_LESS_F64)
#define SLJIT_GREATER_EQUAL_F64 19 #define SLJIT_GREATER_EQUAL_F64 17
#define SLJIT_GREATER_EQUAL_F32 (SLJIT_GREATER_EQUAL_F64 | SLJIT_F32_OP) #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_SET_GREATER_EQUAL_F SLJIT_SET(SLJIT_GREATER_EQUAL_F64)
#define SLJIT_GREATER_F64 20 #define SLJIT_GREATER_F64 18
#define SLJIT_GREATER_F32 (SLJIT_GREATER_F64 | SLJIT_F32_OP) #define SLJIT_GREATER_F32 (SLJIT_GREATER_F64 | SLJIT_F32_OP)
#define SLJIT_SET_GREATER_F SLJIT_SET(SLJIT_GREATER_F64) #define SLJIT_SET_GREATER_F SLJIT_SET(SLJIT_GREATER_F64)
#define SLJIT_LESS_EQUAL_F64 21 #define SLJIT_LESS_EQUAL_F64 19
#define SLJIT_LESS_EQUAL_F32 (SLJIT_LESS_EQUAL_F64 | SLJIT_F32_OP) #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_SET_LESS_EQUAL_F SLJIT_SET(SLJIT_LESS_EQUAL_F64)
#define SLJIT_UNORDERED_F64 22 #define SLJIT_UNORDERED_F64 20
#define SLJIT_UNORDERED_F32 (SLJIT_UNORDERED_F64 | SLJIT_F32_OP) #define SLJIT_UNORDERED_F32 (SLJIT_UNORDERED_F64 | SLJIT_F32_OP)
#define SLJIT_SET_UNORDERED_F SLJIT_SET(SLJIT_UNORDERED_F64) #define SLJIT_SET_UNORDERED_F SLJIT_SET(SLJIT_UNORDERED_F64)
#define SLJIT_ORDERED_F64 23 #define SLJIT_ORDERED_F64 21
#define SLJIT_ORDERED_F32 (SLJIT_ORDERED_F64 | SLJIT_F32_OP) #define SLJIT_ORDERED_F32 (SLJIT_ORDERED_F64 | SLJIT_F32_OP)
#define SLJIT_SET_ORDERED_F SLJIT_SET(SLJIT_ORDERED_F64) #define SLJIT_SET_ORDERED_F SLJIT_SET(SLJIT_ORDERED_F64)
/* Unconditional jump types. */ /* Unconditional jump types. */
#define SLJIT_JUMP 24 #define SLJIT_JUMP 22
/* Fast calling method. See sljit_emit_fast_enter / SLJIT_FAST_RETURN. */ /* Fast calling method. See sljit_emit_fast_enter / SLJIT_FAST_RETURN. */
#define SLJIT_FAST_CALL 25 #define SLJIT_FAST_CALL 23
/* Called function must be declared with the SLJIT_FUNC attribute. */ /* Called function must be declared with the SLJIT_FUNC attribute. */
#define SLJIT_CALL 26 #define SLJIT_CALL 24
/* Called function must be declared with cdecl attribute. /* Called function must be declared with cdecl attribute.
This is the default attribute for C functions. */ This is the default attribute for C functions. */
#define SLJIT_CALL_CDECL 27 #define SLJIT_CALL_CDECL 25
/* The target can be changed during runtime (see: sljit_set_jump_addr). */ /* The target can be changed during runtime (see: sljit_set_jump_addr). */
#define SLJIT_REWRITABLE_JUMP 0x1000 #define SLJIT_REWRITABLE_JUMP 0x1000
@ -1534,8 +1518,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_s32 size); void *instruction, sljit_s32 size);
/* Define the currently available CPU status flags. It is usually used after an /* Flags were set by a 32 bit operation. */
sljit_emit_op_custom call to define which flags are set. */ #define SLJIT_CURRENT_FLAGS_I32_OP SLJIT_I32_OP
/* Flags were set by an ADD, ADDC, SUB, SUBC, or NEG operation. */
#define SLJIT_CURRENT_FLAGS_ADD_SUB 0x01
/* Flags were set by a SUB with unused destination.
Must be combined with SLJIT_CURRENT_FLAGS_ADD_SUB. */
#define SLJIT_CURRENT_FLAGS_COMPARE 0x02
/* Define the currently available CPU status flags. It is usually used after
an sljit_emit_label or sljit_emit_op_custom operations to define which CPU
status flags are available.
The current_flags must be a valid combination of SLJIT_SET_* and
SLJIT_CURRENT_FLAGS_* constants. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler,
sljit_s32 current_flags); sljit_s32 current_flags);

View file

@ -1197,6 +1197,8 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_ADD: case SLJIT_ADD:
SLJIT_ASSERT(!(flags & INV_IMM)); SLJIT_ASSERT(!(flags & INV_IMM));
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED)) if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
return push_inst(compiler, CMN | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); return push_inst(compiler, CMN | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
return push_inst(compiler, ADD | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); return push_inst(compiler, ADD | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
@ -1207,6 +1209,8 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_SUB: case SLJIT_SUB:
SLJIT_ASSERT(!(flags & INV_IMM)); SLJIT_ASSERT(!(flags & INV_IMM));
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED)) if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
return push_inst(compiler, CMP | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); return push_inst(compiler, CMP | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SUB : RSB) | (flags & SET_FLAGS) return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SUB : RSB) | (flags & SET_FLAGS)
@ -1220,6 +1224,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MUL: case SLJIT_MUL:
SLJIT_ASSERT(!(flags & INV_IMM)); SLJIT_ASSERT(!(flags & INV_IMM));
SLJIT_ASSERT(!(src2 & SRC2_IMM)); SLJIT_ASSERT(!(src2 & SRC2_IMM));
compiler->status_flags_state = 0;
if (!HAS_FLAGS(op)) if (!HAS_FLAGS(op))
return push_inst(compiler, MUL | (reg_map[dst] << 16) | (reg_map[src2] << 8) | reg_map[src1]); return push_inst(compiler, MUL | (reg_map[dst] << 16) | (reg_map[src2] << 8) | reg_map[src1]);
@ -2153,16 +2158,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
/* Conditional instructions */ /* Conditional instructions */
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static sljit_uw get_cc(sljit_s32 type) static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{ {
switch (type) { switch (type) {
case SLJIT_EQUAL: case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_EQUAL_F64: case SLJIT_EQUAL_F64:
return 0x00000000; return 0x00000000;
case SLJIT_NOT_EQUAL: case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
case SLJIT_NOT_EQUAL_F64: case SLJIT_NOT_EQUAL_F64:
return 0x10000000; return 0x10000000;
@ -2195,10 +2198,16 @@ static sljit_uw get_cc(sljit_s32 type)
return 0xd0000000; return 0xd0000000;
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return 0x10000000;
case SLJIT_UNORDERED_F64: case SLJIT_UNORDERED_F64:
return 0x60000000; return 0x60000000;
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return 0x00000000;
case SLJIT_ORDERED_F64: case SLJIT_ORDERED_F64:
return 0x70000000; return 0x70000000;
@ -2242,7 +2251,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (type >= SLJIT_FAST_CALL) if (type >= SLJIT_FAST_CALL)
PTR_FAIL_IF(prepare_blx(compiler)); PTR_FAIL_IF(prepare_blx(compiler));
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,
type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(type), 0)); type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(compiler, type), 0));
if (jump->flags & SLJIT_REWRITABLE_JUMP) { if (jump->flags & SLJIT_REWRITABLE_JUMP) {
jump->addr = compiler->size; jump->addr = compiler->size;
@ -2260,7 +2269,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (type >= SLJIT_FAST_CALL) if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL; jump->flags |= IS_BL;
PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0)); 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(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(compiler, type)));
jump->addr = compiler->size; jump->addr = compiler->size;
#endif #endif
return jump; return jump;
@ -2589,7 +2598,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
ADJUST_LOCAL_OFFSET(dst, dstw); ADJUST_LOCAL_OFFSET(dst, dstw);
op = GET_OPCODE(op); op = GET_OPCODE(op);
cc = get_cc(type & 0xff); cc = get_cc(compiler, type & 0xff);
dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1; dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (op < SLJIT_ADD) { if (op < SLJIT_ADD) {
@ -2629,7 +2638,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
dst_reg &= ~SLJIT_I32_OP; dst_reg &= ~SLJIT_I32_OP;
cc = get_cc(type & 0xff); cc = get_cc(compiler, type & 0xff);
if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
tmp = get_imm(srcw); tmp = get_imm(srcw);

View file

@ -644,6 +644,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
imm = -imm; imm = -imm;
/* Fall through. */ /* Fall through. */
case SLJIT_ADD: case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (imm == 0) { if (imm == 0) {
CHECK_FLAGS(1 << 29); CHECK_FLAGS(1 << 29);
return push_inst(compiler, ((op == SLJIT_ADD ? ADDI : SUBI) ^ inv_bits) | RD(dst) | RN(reg)); return push_inst(compiler, ((op == SLJIT_ADD ? ADDI : SUBI) ^ inv_bits) | RD(dst) | RN(reg));
@ -781,6 +782,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
break; /* Set flags. */ break; /* Set flags. */
case SLJIT_NEG: case SLJIT_NEG:
SLJIT_ASSERT(arg1 == TMP_REG1); SLJIT_ASSERT(arg1 == TMP_REG1);
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (flags & SET_FLAGS) if (flags & SET_FLAGS)
inv_bits |= 1 << 29; inv_bits |= 1 << 29;
return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2)); return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
@ -789,17 +791,20 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2)); return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2));
case SLJIT_ADD: case SLJIT_ADD:
CHECK_FLAGS(1 << 29); CHECK_FLAGS(1 << 29);
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, (ADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); return push_inst(compiler, (ADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_ADDC: case SLJIT_ADDC:
CHECK_FLAGS(1 << 29); CHECK_FLAGS(1 << 29);
return push_inst(compiler, (ADC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); return push_inst(compiler, (ADC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_SUB: case SLJIT_SUB:
CHECK_FLAGS(1 << 29); CHECK_FLAGS(1 << 29);
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_SUBC: case SLJIT_SUBC:
CHECK_FLAGS(1 << 29); CHECK_FLAGS(1 << 29);
return push_inst(compiler, (SBC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); return push_inst(compiler, (SBC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_MUL: case SLJIT_MUL:
compiler->status_flags_state = 0;
if (!(flags & SET_FLAGS)) if (!(flags & SET_FLAGS))
return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO)); return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO));
if (flags & INT_OP) { if (flags & INT_OP) {
@ -1600,16 +1605,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
/* Conditional instructions */ /* Conditional instructions */
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static sljit_uw get_cc(sljit_s32 type) static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{ {
switch (type) { switch (type) {
case SLJIT_EQUAL: case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_EQUAL_F64: case SLJIT_EQUAL_F64:
return 0x1; return 0x1;
case SLJIT_NOT_EQUAL: case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
case SLJIT_NOT_EQUAL_F64: case SLJIT_NOT_EQUAL_F64:
return 0x0; return 0x0;
@ -1642,10 +1645,16 @@ static sljit_uw get_cc(sljit_s32 type)
return 0xc; return 0xc;
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return 0x0;
case SLJIT_UNORDERED_F64: case SLJIT_UNORDERED_F64:
return 0x7; return 0x7;
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return 0x1;
case SLJIT_ORDERED_F64: case SLJIT_ORDERED_F64:
return 0x6; return 0x6;
@ -1685,7 +1694,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (type < SLJIT_JUMP) { if (type < SLJIT_JUMP) {
jump->flags |= IS_COND; jump->flags |= IS_COND;
PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(type))); PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(compiler, type)));
} }
else if (type >= SLJIT_FAST_CALL) else if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL; jump->flags |= IS_BL;
@ -1799,7 +1808,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
ADJUST_LOCAL_OFFSET(dst, dstw); ADJUST_LOCAL_OFFSET(dst, dstw);
cc = get_cc(type & 0xff); cc = get_cc(compiler, type & 0xff);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (GET_OPCODE(op) < SLJIT_ADD) { if (GET_OPCODE(op) < SLJIT_ADD) {
@ -1854,7 +1863,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
srcw = 0; srcw = 0;
} }
cc = get_cc(type & 0xff); cc = get_cc(compiler, type & 0xff);
dst_reg &= ~SLJIT_I32_OP; dst_reg &= ~SLJIT_I32_OP;
return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src)); return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src));

View file

@ -610,6 +610,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
Although some clever things could be done here, "NOT IMM" does not worth the efforts. */ Although some clever things could be done here, "NOT IMM" does not worth the efforts. */
break; break;
case SLJIT_ADD: case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
nimm = -(sljit_sw)imm; nimm = -(sljit_sw)imm;
if (IS_2_LO_REGS(reg, dst)) { if (IS_2_LO_REGS(reg, dst)) {
if (imm <= 0x7) if (imm <= 0x7)
@ -643,6 +644,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
break; break;
case SLJIT_SUB: case SLJIT_SUB:
/* SUB operation can be replaced by ADD because of the negative carry flag. */ /* SUB operation can be replaced by ADD because of the negative carry flag. */
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (flags & ARG1_IMM) { if (flags & ARG1_IMM) {
if (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)); return push_inst16(compiler, RSBSI | RD3(dst) | RN3(reg));
@ -801,6 +803,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
FAIL_IF(push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2))); FAIL_IF(push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2)));
return SLJIT_SUCCESS; return SLJIT_SUCCESS;
case SLJIT_ADD: case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (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)); return push_inst16(compiler, ADDS | RD3(dst) | RN3(arg1) | RM3(arg2));
if (dst == arg1 && !(flags & SET_FLAGS)) if (dst == arg1 && !(flags & SET_FLAGS))
@ -811,6 +814,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst16(compiler, ADCS | RD3(dst) | RN3(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)); return push_inst32(compiler, ADC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_SUB: case SLJIT_SUB:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (flags & UNUSED_RETURN) { if (flags & UNUSED_RETURN) {
if (IS_2_LO_REGS(arg1, arg2)) if (IS_2_LO_REGS(arg1, arg2))
return push_inst16(compiler, CMP | RD3(arg1) | RN3(arg2)); return push_inst16(compiler, CMP | RD3(arg1) | RN3(arg2));
@ -824,6 +828,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst16(compiler, SBCS | RD3(dst) | RN3(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)); return push_inst32(compiler, SBC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_MUL: case SLJIT_MUL:
compiler->status_flags_state = 0;
if (!(flags & SET_FLAGS)) if (!(flags & SET_FLAGS))
return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2)); return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2));
SLJIT_ASSERT(dst != TMP_REG2); SLJIT_ASSERT(dst != TMP_REG2);
@ -1760,16 +1765,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
/* Conditional instructions */ /* Conditional instructions */
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static sljit_uw get_cc(sljit_s32 type) static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{ {
switch (type) { switch (type) {
case SLJIT_EQUAL: case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_EQUAL_F64: case SLJIT_EQUAL_F64:
return 0x0; return 0x0;
case SLJIT_NOT_EQUAL: case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
case SLJIT_NOT_EQUAL_F64: case SLJIT_NOT_EQUAL_F64:
return 0x1; return 0x1;
@ -1802,10 +1805,16 @@ static sljit_uw get_cc(sljit_s32 type)
return 0xd; return 0xd;
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return 0x1;
case SLJIT_UNORDERED_F64: case SLJIT_UNORDERED_F64:
return 0x6; return 0x6;
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return 0x0;
case SLJIT_ORDERED_F64: case SLJIT_ORDERED_F64:
return 0x7; return 0x7;
@ -1847,7 +1856,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0)); PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0));
if (type < SLJIT_JUMP) { if (type < SLJIT_JUMP) {
jump->flags |= IS_COND; jump->flags |= IS_COND;
cc = get_cc(type); cc = get_cc(compiler, type);
jump->flags |= cc << 8; jump->flags |= cc << 8;
PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
} }
@ -2177,7 +2186,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
ADJUST_LOCAL_OFFSET(dst, dstw); ADJUST_LOCAL_OFFSET(dst, dstw);
op = GET_OPCODE(op); op = GET_OPCODE(op);
cc = get_cc(type & 0xff); cc = get_cc(compiler, type & 0xff);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (op < SLJIT_ADD) { if (op < SLJIT_ADD) {
@ -2229,7 +2238,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
dst_reg &= ~SLJIT_I32_OP; dst_reg &= ~SLJIT_I32_OP;
cc = get_cc(type & 0xff); cc = get_cc(compiler, type & 0xff);
if (!(src & SLJIT_IMM)) { if (!(src & SLJIT_IMM)) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));

View file

@ -367,7 +367,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MUL: case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM)); SLJIT_ASSERT(!(flags & SRC2_IMM));
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) { if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW) {
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst)); return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
#else /* SLJIT_MIPS_REV < 1 */ #else /* SLJIT_MIPS_REV < 1 */

View file

@ -458,7 +458,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MUL: case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM)); SLJIT_ASSERT(!(flags & SRC2_IMM));
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) { if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW) {
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
return push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst)); return push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst));
#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) #elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)

View file

@ -1377,6 +1377,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_NEG: case SLJIT_NEG:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw); return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
case SLJIT_CLZ: case SLJIT_CLZ:
@ -1424,13 +1425,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
switch (GET_OPCODE(op)) { switch (GET_OPCODE(op)) {
case SLJIT_ADD: case SLJIT_ADD:
case SLJIT_ADDC: case SLJIT_ADDC:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SUB: case SLJIT_SUB:
case SLJIT_SUBC: case SLJIT_SUBC:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_MUL: case SLJIT_MUL:
compiler->status_flags_state = 0;
return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_AND: case SLJIT_AND:
@ -1860,7 +1864,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_SIG_LESS: case SLJIT_SIG_LESS:
case SLJIT_SIG_GREATER: case SLJIT_SIG_GREATER:
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
case SLJIT_MUL_OVERFLOW:
BR_Z(OTHER_FLAG); BR_Z(OTHER_FLAG);
break; break;
case SLJIT_GREATER_EQUAL: case SLJIT_GREATER_EQUAL:
@ -1868,7 +1871,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_SIG_GREATER_EQUAL: case SLJIT_SIG_GREATER_EQUAL:
case SLJIT_SIG_LESS_EQUAL: case SLJIT_SIG_LESS_EQUAL:
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW:
BR_NZ(OTHER_FLAG); BR_NZ(OTHER_FLAG);
break; break;
case SLJIT_NOT_EQUAL_F64: case SLJIT_NOT_EQUAL_F64:
@ -2127,8 +2129,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(dst_ar) | IMM(1), dst_ar)); FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
src_ar = dst_ar; src_ar = dst_ar;
break; break;
case SLJIT_MUL_OVERFLOW: case SLJIT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB) {
src_ar = OTHER_FLAG;
break;
}
FAIL_IF(push_inst(compiler, SLTIU | SA(OTHER_FLAG) | TA(dst_ar) | IMM(1), dst_ar)); FAIL_IF(push_inst(compiler, SLTIU | SA(OTHER_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
src_ar = dst_ar; src_ar = dst_ar;
type ^= 0x1; /* Flip type bit for the XORI below. */ type ^= 0x1; /* Flip type bit for the XORI below. */
@ -2219,7 +2225,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
case SLJIT_SIG_LESS: case SLJIT_SIG_LESS:
case SLJIT_SIG_GREATER: case SLJIT_SIG_GREATER:
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
case SLJIT_MUL_OVERFLOW:
ins = MOVN | TA(OTHER_FLAG); ins = MOVN | TA(OTHER_FLAG);
break; break;
case SLJIT_GREATER_EQUAL: case SLJIT_GREATER_EQUAL:
@ -2227,7 +2232,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
case SLJIT_SIG_GREATER_EQUAL: case SLJIT_SIG_GREATER_EQUAL:
case SLJIT_SIG_LESS_EQUAL: case SLJIT_SIG_LESS_EQUAL:
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW:
ins = MOVZ | TA(OTHER_FLAG); ins = MOVZ | TA(OTHER_FLAG);
break; break;
case SLJIT_EQUAL_F64: case SLJIT_EQUAL_F64:

View file

@ -119,9 +119,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
SLJIT_ASSERT(src2 == TMP_REG2); SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm); return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
} }
SLJIT_ASSERT(!(flags & ALT_FORM4));
if (!(flags & ALT_SET_FLAGS)) if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2)); return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
if (flags & ALT_FORM4) if (flags & ALT_FORM5)
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)); 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)); return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
@ -143,24 +144,29 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
} }
if (flags & ALT_FORM2) { if (flags & ALT_FORM2) {
if (flags & ALT_FORM3) {
FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm));
if (!(flags & ALT_FORM4))
return SLJIT_SUCCESS;
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
}
FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2)));
if (!(flags & ALT_FORM4))
return SLJIT_SUCCESS;
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
}
if (flags & ALT_FORM3) {
/* Setting XER SO is not enough, CR SO is also needed. */ /* 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)); return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
} }
if (flags & ALT_FORM3) { if (flags & ALT_FORM4) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */ /* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2); SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm); return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
} }
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)) if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
if (flags & ALT_FORM5) if (flags & ALT_FORM5)

View file

@ -252,10 +252,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
BIN_IMM_EXTS(); BIN_IMM_EXTS();
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm); return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
} }
if (flags & ALT_FORM4) {
if (flags & ALT_FORM5)
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm));
else
FAIL_IF(push_inst(compiler, ADD | D(dst) | A(src1) | B(src2)));
return push_inst(compiler, CMPI | A(dst) | 0);
}
if (!(flags & ALT_SET_FLAGS)) if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2)); return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
BIN_EXTS(); BIN_EXTS();
if (flags & ALT_FORM4) if (flags & ALT_FORM5)
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)); 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)); return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
@ -278,6 +285,19 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
} }
if (flags & ALT_FORM2) { if (flags & ALT_FORM2) {
if (flags & ALT_FORM3) {
FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
if (!(flags & ALT_FORM4))
return SLJIT_SUCCESS;
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
}
FAIL_IF(push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
if (!(flags & ALT_FORM4))
return SLJIT_SUCCESS;
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
}
if (flags & ALT_FORM3) {
if (flags & ALT_SIGN_EXT) { if (flags & ALT_SIGN_EXT) {
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1))); FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
src1 = TMP_REG1; src1 = TMP_REG1;
@ -291,20 +311,12 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return SLJIT_SUCCESS; return SLJIT_SUCCESS;
} }
if (flags & ALT_FORM3) { if (flags & ALT_FORM4) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */ /* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2); SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm); return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
} }
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)) if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
BIN_EXTS(); BIN_EXTS();

View file

@ -1324,6 +1324,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
((src) & SLJIT_IMM) ((src) & SLJIT_IMM)
#endif #endif
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#define TEST_ADD_FORM1(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
|| (op & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_I32_OP | SLJIT_SET_Z | SLJIT_SET_CARRY))
#define TEST_SUB_FORM2(op) \
((GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) \
|| (op & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_I32_OP | SLJIT_SET_Z))
#define TEST_SUB_FORM3(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
|| (op & (SLJIT_I32_OP | SLJIT_SET_Z)) == (SLJIT_I32_OP | SLJIT_SET_Z))
#else
#define TEST_ADD_FORM1(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
#define TEST_SUB_FORM2(op) \
(GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL)
#define TEST_SUB_FORM3(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
#endif
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw, sljit_s32 dst, sljit_sw dstw,
sljit_s32 src1, sljit_sw src1w, sljit_s32 src1, sljit_sw src1w,
@ -1362,7 +1381,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
switch (GET_OPCODE(op)) { switch (GET_OPCODE(op)) {
case SLJIT_ADD: case SLJIT_ADD:
if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW) if (TEST_ADD_FORM1(op))
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) { if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
@ -1392,6 +1411,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | 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 (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
if ((op & (SLJIT_I32_OP | SLJIT_SET_Z)) == (SLJIT_I32_OP | SLJIT_SET_Z)) {
if (TEST_SL_IMM(src2, src2w)) {
compiler->imm = src2w & 0xffff;
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, 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_FORM4 | ALT_FORM5, dst, dstw, src2, src2w, TMP_REG2, 0);
}
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
}
#endif
if (HAS_FLAGS(op)) { if (HAS_FLAGS(op)) {
if (TEST_SL_IMM(src2, src2w)) { if (TEST_SL_IMM(src2, src2w)) {
compiler->imm = src2w & 0xffff; compiler->imm = src2w & 0xffff;
@ -1402,7 +1435,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
} }
} }
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); return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
case SLJIT_ADDC: case SLJIT_ADDC:
return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);
@ -1424,18 +1457,36 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
} }
if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW) if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
if (TEST_SL_IMM(src2, src2w)) {
compiler->imm = src2w & 0xffff;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
}
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w); return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w);
}
if (TEST_SUB_FORM2(op)) {
if ((src2 & SLJIT_IMM) && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) {
compiler->imm = src2w & 0xffff;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
}
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
}
if (TEST_SUB_FORM3(op))
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
if (TEST_SL_IMM(src2, -src2w)) { if (TEST_SL_IMM(src2, -src2w)) {
compiler->imm = (-src2w) & 0xffff; compiler->imm = (-src2w) & 0xffff;
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); return emit_op(compiler, SLJIT_ADD, flags | (!HAS_FLAGS(op) ? ALT_FORM2 : ALT_FORM3), dst, dstw, src1, src1w, TMP_REG2, 0);
} }
if (TEST_SL_IMM(src1, src1w)) {
if (TEST_SL_IMM(src1, src1w) && !(op & SLJIT_SET_Z)) {
compiler->imm = src1w & 0xffff; compiler->imm = src1w & 0xffff;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
} }
if (!HAS_FLAGS(op)) {
if (TEST_SH_IMM(src2, -src2w)) { if (TEST_SH_IMM(src2, -src2w)) {
compiler->imm = ((-src2w) >> 16) & 0xffff; compiler->imm = ((-src2w) >> 16) & 0xffff;
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, 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);
@ -1447,18 +1498,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
} }
} }
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 | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
}
if (TEST_SL_IMM(src2, -src2w)) {
compiler->imm = (-src2w) & 0xffff;
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
}
/* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP on 64 bit systems. */ /* 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); 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);
@ -1536,6 +1575,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return SLJIT_SUCCESS; return SLJIT_SUCCESS;
} }
#undef TEST_ADD_FORM1
#undef TEST_SUB_FORM2
#undef TEST_SUB_FORM3
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src, sljit_sw srcw) sljit_s32 src, sljit_sw srcw)
{ {
@ -1941,11 +1984,9 @@ static sljit_ins get_bo_bi_flags(sljit_s32 type)
return (4 << 21) | ((4 + 1) << 16); return (4 << 21) | ((4 + 1) << 16);
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
case SLJIT_MUL_OVERFLOW:
return (12 << 21) | (3 << 16); return (12 << 21) | (3 << 16);
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW:
return (4 << 21) | (3 << 16); return (4 << 21) | (3 << 16);
case SLJIT_EQUAL_F64: case SLJIT_EQUAL_F64:
@ -2143,12 +2184,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
break; break;
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
case SLJIT_MUL_OVERFLOW:
cr_bit = 3; cr_bit = 3;
break; break;
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW:
cr_bit = 3; cr_bit = 3;
invert = 1; invert = 1;
break; break;

File diff suppressed because it is too large Load diff

View file

@ -93,18 +93,21 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS); return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS);
case SLJIT_ADD: case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS)); return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_ADDC: case SLJIT_ADDC:
return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS)); return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SUB: case SLJIT_SUB:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS)); return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SUBC: case SLJIT_SUBC:
return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS)); return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_MUL: case SLJIT_MUL:
compiler->status_flags_state = 0;
FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst))); FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
if (!(flags & SET_FLAGS)) if (!(flags & SET_FLAGS))
return SLJIT_SUCCESS; return SLJIT_SUCCESS;

View file

@ -1275,16 +1275,14 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
return label; return label;
} }
static sljit_ins get_cc(sljit_s32 type) static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{ {
switch (type) { switch (type) {
case SLJIT_EQUAL: case SLJIT_EQUAL:
case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_NOT_EQUAL_F64: /* Unordered. */ case SLJIT_NOT_EQUAL_F64: /* Unordered. */
return DA(0x1); return DA(0x1);
case SLJIT_NOT_EQUAL: case SLJIT_NOT_EQUAL:
case SLJIT_MUL_OVERFLOW:
case SLJIT_EQUAL_F64: case SLJIT_EQUAL_F64:
return DA(0x9); return DA(0x9);
@ -1317,10 +1315,16 @@ static sljit_ins get_cc(sljit_s32 type)
return DA(0x2); return DA(0x2);
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return DA(0x9);
case SLJIT_UNORDERED_F64: case SLJIT_UNORDERED_F64:
return DA(0x7); return DA(0x7);
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
return DA(0x1);
case SLJIT_ORDERED_F64: case SLJIT_ORDERED_F64:
return DA(0xf); return DA(0xf);
@ -1347,7 +1351,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & ICC_IS_SET)) if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & ICC_IS_SET))
jump->flags |= IS_MOVABLE; jump->flags |= IS_MOVABLE;
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) #if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
PTR_FAIL_IF(push_inst(compiler, BICC | get_cc(type ^ 1) | 5, UNMOVABLE_INS)); PTR_FAIL_IF(push_inst(compiler, BICC | get_cc(compiler, type ^ 1) | 5, UNMOVABLE_INS));
#else #else
#error "Implementation required" #error "Implementation required"
#endif #endif
@ -1357,7 +1361,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & FCC_IS_SET)) if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & FCC_IS_SET))
jump->flags |= IS_MOVABLE; jump->flags |= IS_MOVABLE;
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) #if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
PTR_FAIL_IF(push_inst(compiler, FBFCC | get_cc(type ^ 1) | 5, UNMOVABLE_INS)); PTR_FAIL_IF(push_inst(compiler, FBFCC | get_cc(compiler, type ^ 1) | 5, UNMOVABLE_INS));
#else #else
#error "Implementation required" #error "Implementation required"
#endif #endif
@ -1474,9 +1478,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
type &= 0xff; type &= 0xff;
if (type < SLJIT_EQUAL_F64) if (type < SLJIT_EQUAL_F64)
FAIL_IF(push_inst(compiler, BICC | get_cc(type) | 3, UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, BICC | get_cc(compiler, type) | 3, UNMOVABLE_INS));
else else
FAIL_IF(push_inst(compiler, FBFCC | get_cc(type) | 3, UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, FBFCC | get_cc(compiler, 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(1), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS));

View file

@ -411,11 +411,9 @@ static sljit_u8 get_jump_code(sljit_s32 type)
return 0x8e /* jle */; return 0x8e /* jle */;
case SLJIT_OVERFLOW: case SLJIT_OVERFLOW:
case SLJIT_MUL_OVERFLOW:
return 0x80 /* jo */; return 0x80 /* jo */;
case SLJIT_NOT_OVERFLOW: case SLJIT_NOT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW:
return 0x81 /* jno */; return 0x81 /* jno */;
case SLJIT_UNORDERED_F64: case SLJIT_UNORDERED_F64:

View file

@ -48,7 +48,7 @@ static HANDLE allocator_lock;
static SLJIT_INLINE void allocator_grab_lock(void) static SLJIT_INLINE void allocator_grab_lock(void)
{ {
HANDLE lock; HANDLE lock;
if (SLJIT_UNLIKELY(!allocator_lock)) { if (SLJIT_UNLIKELY(!InterlockedCompareExchangePointer(&allocator_lock, NULL, NULL))) {
lock = CreateMutex(NULL, FALSE, NULL); lock = CreateMutex(NULL, FALSE, NULL);
if (InterlockedCompareExchangePointer(&allocator_lock, lock, NULL)) if (InterlockedCompareExchangePointer(&allocator_lock, lock, NULL))
CloseHandle(lock); CloseHandle(lock);
@ -146,9 +146,13 @@ static SLJIT_INLINE sljit_sw get_page_alignment(void) {
#include <unistd.h> #include <unistd.h>
static SLJIT_INLINE sljit_sw get_page_alignment(void) { static SLJIT_INLINE sljit_sw get_page_alignment(void) {
static sljit_sw sljit_page_align; static sljit_sw sljit_page_align = -1;
if (!sljit_page_align) { if (sljit_page_align < 0) {
#ifdef _SC_PAGESIZE
sljit_page_align = sysconf(_SC_PAGESIZE); sljit_page_align = sysconf(_SC_PAGESIZE);
#else
sljit_page_align = getpagesize();
#endif
/* Should never happen. */ /* Should never happen. */
if (sljit_page_align < 0) if (sljit_page_align < 0)
sljit_page_align = 4096; sljit_page_align = 4096;

View file

@ -121,14 +121,18 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
#endif #endif
static int se_protected = !SLJIT_PROT_WX; static int se_protected = !SLJIT_PROT_WX;
int prot = PROT_READ | PROT_WRITE | SLJIT_PROT_WX;
sljit_uw* ptr; sljit_uw* ptr;
if (SLJIT_UNLIKELY(se_protected < 0)) if (SLJIT_UNLIKELY(se_protected < 0))
return NULL; return NULL;
#ifdef PROT_MAX
prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
size += sizeof(sljit_uw); size += sizeof(sljit_uw);
ptr = (sljit_uw*)mmap(NULL, size, PROT_READ | PROT_WRITE | SLJIT_PROT_WX, ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED) if (ptr == MAP_FAILED)
return NULL; return NULL;