Selaa lähdekoodia

Merge pull request #89371 from Chubercik/pcre2-10.43

pcre2: Update to 10.43
Rémi Verschelde 1 vuosi sitten
vanhempi
commit
a2edcf83ab
65 muutettua tiedostoa jossa 13370 lisäystä ja 4100 poistoa
  1. 2 2
      COPYRIGHT.txt
  2. 1 0
      modules/regex/SCsub
  3. 2 1
      thirdparty/README.md
  4. 3 3
      thirdparty/pcre2/AUTHORS
  5. 3 3
      thirdparty/pcre2/LICENCE
  6. 5 5
      thirdparty/pcre2/patches/sljit-macos11-conditional.patch
  7. 44 18
      thirdparty/pcre2/src/config.h
  8. 22 8
      thirdparty/pcre2/src/pcre2.h
  9. 11 5
      thirdparty/pcre2/src/pcre2_auto_possess.c
  10. 3 9
      thirdparty/pcre2/src/pcre2_chartables.c
  11. 96 0
      thirdparty/pcre2/src/pcre2_chkdint.c
  12. 361 177
      thirdparty/pcre2/src/pcre2_compile.c
  13. 27 19
      thirdparty/pcre2/src/pcre2_context.c
  14. 8 0
      thirdparty/pcre2/src/pcre2_convert.c
  15. 110 57
      thirdparty/pcre2/src/pcre2_dfa_match.c
  16. 6 3
      thirdparty/pcre2/src/pcre2_error.c
  17. 5 5
      thirdparty/pcre2/src/pcre2_find_bracket.c
  18. 96 59
      thirdparty/pcre2/src/pcre2_internal.h
  19. 31 26
      thirdparty/pcre2/src/pcre2_intmodedep.h
  20. 294 139
      thirdparty/pcre2/src/pcre2_jit_compile.c
  21. 15 1
      thirdparty/pcre2/src/pcre2_jit_match.c
  22. 29 24
      thirdparty/pcre2/src/pcre2_jit_neon_inc.h
  23. 779 282
      thirdparty/pcre2/src/pcre2_jit_simd_inc.h
  24. 5 3
      thirdparty/pcre2/src/pcre2_maketables.c
  25. 351 118
      thirdparty/pcre2/src/pcre2_match.c
  26. 12 0
      thirdparty/pcre2/src/pcre2_match_data.c
  27. 97 7
      thirdparty/pcre2/src/pcre2_study.c
  28. 5 2
      thirdparty/pcre2/src/pcre2_substring.c
  29. 484 484
      thirdparty/pcre2/src/pcre2_ucd.c
  30. 25 23
      thirdparty/pcre2/src/pcre2_ucp.h
  31. 269 260
      thirdparty/pcre2/src/pcre2_ucptables.c
  32. 24 24
      thirdparty/pcre2/src/pcre2_valid_utf.c
  33. 36 17
      thirdparty/pcre2/src/pcre2_xclass.c
  34. 133 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c
  35. 330 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c
  36. 89 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c
  37. 62 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c
  38. 40 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c
  39. 72 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c
  40. 172 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c
  41. 141 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c
  42. 102 0
      thirdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c
  43. 3 23
      thirdparty/pcre2/src/sljit/sljitConfig.h
  44. 188 0
      thirdparty/pcre2/src/sljit/sljitConfigCPU.h
  45. 184 154
      thirdparty/pcre2/src/sljit/sljitConfigInternal.h
  46. 3 0
      thirdparty/pcre2/src/sljit/sljitExecAllocator.c
  47. 500 169
      thirdparty/pcre2/src/sljit/sljitLir.c
  48. 414 198
      thirdparty/pcre2/src/sljit/sljitLir.h
  49. 226 175
      thirdparty/pcre2/src/sljit/sljitNativeARM_32.c
  50. 434 194
      thirdparty/pcre2/src/sljit/sljitNativeARM_64.c
  51. 405 144
      thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
  52. 3158 0
      thirdparty/pcre2/src/sljit/sljitNativeLOONGARCH_64.c
  53. 165 7
      thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
  54. 73 5
      thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
  55. 399 137
      thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
  56. 149 4
      thirdparty/pcre2/src/sljit/sljitNativePPC_32.c
  57. 146 6
      thirdparty/pcre2/src/sljit/sljitNativePPC_64.c
  58. 381 236
      thirdparty/pcre2/src/sljit/sljitNativePPC_common.c
  59. 70 1
      thirdparty/pcre2/src/sljit/sljitNativeRISCV_32.c
  60. 41 2
      thirdparty/pcre2/src/sljit/sljitNativeRISCV_64.c
  61. 427 176
      thirdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
  62. 414 204
      thirdparty/pcre2/src/sljit/sljitNativeS390X.c
  63. 395 70
      thirdparty/pcre2/src/sljit/sljitNativeX86_32.c
  64. 354 92
      thirdparty/pcre2/src/sljit/sljitNativeX86_64.c
  65. 439 319
      thirdparty/pcre2/src/sljit/sljitNativeX86_common.c

+ 2 - 2
COPYRIGHT.txt

@@ -457,8 +457,8 @@ License: Apache-2.0
 
 Files: ./thirdparty/pcre2/
 Comment: PCRE2
-Copyright: 1997-2022, University of Cambridge
- 2009-2022, Zoltan Herczeg
+Copyright: 1997-2024, University of Cambridge
+ 2009-2024, Zoltan Herczeg
 License: BSD-3-clause
 
 Files: ./thirdparty/recastnavigation/

+ 1 - 0
modules/regex/SCsub

@@ -19,6 +19,7 @@ if env["builtin_pcre2"]:
     thirdparty_sources = [
         "pcre2_auto_possess.c",
         "pcre2_chartables.c",
+        "pcre2_chkdint.c",
         "pcre2_compile.c",
         "pcre2_config.c",
         "pcre2_context.c",

+ 2 - 1
thirdparty/README.md

@@ -756,7 +756,7 @@ Exclude:
 ## pcre2
 
 - Upstream: http://www.pcre.org
-- Version: 10.42 (52c08847921a324c804cabf2814549f50bce1265, 2022)
+- Version: 10.43 (3864abdb713f78831dd12d898ab31bbb0fa630b6, 2024)
 - License: BSD-3-Clause
 
 Files extracted from upstream source:
@@ -765,6 +765,7 @@ Files extracted from upstream source:
 - All `.h` files in `src/` apart from `pcre2posix.h`
 - `src/pcre2_jit_match.c`
 - `src/pcre2_jit_misc.c`
+- `src/pcre2_ucptables.c`
 - `src/sljit/`
 - `AUTHORS` and `LICENCE`
 

+ 3 - 3
thirdparty/pcre2/AUTHORS

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

+ 3 - 3
thirdparty/pcre2/LICENCE

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

+ 5 - 5
thirdparty/pcre2/patches/sljit-macos11-conditional.patch

@@ -12,13 +12,13 @@ if the toolchain allows it.
 
 Fixes: PCRE2Project/pcre2#109
 ---
- sljit_src/sljitExecAllocator.c | 3 +++
+ thirdparty/pcre2/src/sljit/sljitExecAllocator.c | 3 +++
  1 file changed, 3 insertions(+)
 
-diff --git a/sljit_src/sljitExecAllocator.c b/sljit_src/sljitExecAllocator.c
-index 92d940dd..6359848c 100644
---- a/sljit_src/sljitExecAllocator.c
-+++ b/sljit_src/sljitExecAllocator.c
+diff --git a/thirdparty/pcre2/src/sljit/sljitExecAllocator.c b/thirdparty/pcre2/src/sljit/sljitExecAllocator.c
+index 92d940ddc2..6359848cd5 100644
+--- a/thirdparty/pcre2/src/sljit/sljitExecAllocator.c
++++ b/thirdparty/pcre2/src/sljit/sljitExecAllocator.c
 @@ -152,6 +152,9 @@ static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
  {
  #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000

+ 44 - 18
thirdparty/pcre2/src/config.h

@@ -55,9 +55,12 @@ sure both macros are undefined; an emulation function will then be used. */
 /* Define this if your compiler supports __attribute__((uninitialized)) */
 /* #undef HAVE_ATTRIBUTE_UNINITIALIZED */
 
-/* Define to 1 if you have the `bcopy' function. */
+/* Define to 1 if you have the 'bcopy' function. */
 /* #undef HAVE_BCOPY */
 
+/* Define this if your compiler provides __builtin_mul_overflow() */
+/* #undef HAVE_BUILTIN_MUL_OVERFLOW */
+
 /* Define to 1 if you have the <bzlib.h> header file. */
 /* #undef HAVE_BZLIB_H */
 
@@ -79,16 +82,16 @@ sure both macros are undefined; an emulation function will then be used. */
 /* Define to 1 if you have the <limits.h> header file. */
 /* #undef HAVE_LIMITS_H */
 
-/* Define to 1 if you have the `memfd_create' function. */
+/* Define to 1 if you have the 'memfd_create' function. */
 /* #undef HAVE_MEMFD_CREATE */
 
-/* Define to 1 if you have the `memmove' function. */
+/* Define to 1 if you have the 'memmove' function. */
 /* #undef HAVE_MEMMOVE */
 
 /* Define to 1 if you have the <minix/config.h> header file. */
 /* #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 */
 
 /* Define if you have POSIX threads libraries and header files. */
@@ -109,7 +112,7 @@ sure both macros are undefined; an emulation function will then be used. */
 /* 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 */
 
 /* Define to 1 if you have the <stdint.h> header file. */
@@ -121,7 +124,7 @@ sure both macros are undefined; an emulation function will then be used. */
 /* Define to 1 if you have the <stdlib.h> header file. */
 /* #undef HAVE_STDLIB_H */
 
-/* Define to 1 if you have the `strerror' function. */
+/* Define to 1 if you have the 'strerror' function. */
 /* #undef HAVE_STRERROR */
 
 /* Define to 1 if you have the <strings.h> header file. */
@@ -181,7 +184,7 @@ sure both macros are undefined; an emulation function will then be used. */
    matching attempt. The value is also used to limit a loop counter in
    pcre2_dfa_match(). There is a runtime interface for setting a different
    limit. The limit exists in order to catch runaway regular expressions that
-   take for ever to determine that they do not match. The default is set very
+   take forever to determine that they do not match. The default is set very
    large so that it does not accidentally catch legitimate cases. */
 #ifndef MATCH_LIMIT
 #define MATCH_LIMIT 10000000
@@ -215,6 +218,12 @@ sure both macros are undefined; an emulation function will then be used. */
 #define MAX_NAME_SIZE 32
 #endif
 
+/* The value of MAX_VARLOOKBEHIND specifies the default maximum length, in
+   characters, for a variable-length lookbehind assertion. */
+#ifndef MAX_VARLOOKBEHIND
+#define MAX_VARLOOKBEHIND 255
+#endif
+
 /* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */
 /* #undef NEVER_BACKSLASH_C */
 
@@ -236,7 +245,7 @@ sure both macros are undefined; an emulation function will then be used. */
 #define PACKAGE_NAME "PCRE2"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "PCRE2 10.42"
+#define PACKAGE_STRING "PCRE2 10.43"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "pcre2"
@@ -245,7 +254,7 @@ sure both macros are undefined; an emulation function will then be used. */
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "10.42"
+#define PACKAGE_VERSION "10.43"
 
 /* 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
@@ -275,12 +284,16 @@ sure both macros are undefined; an emulation function will then be used. */
 /* Define to any value to include debugging code. */
 /* #undef PCRE2_DEBUG */
 
+/* to make a symbol visible */
+#define PCRE2_EXPORT
+
 /* If you are compiling for a system other than a Unix-like system or
    Win32, and it needs some magic to be inserted before the definition
    of a function that is exported by the library, define this macro to
    contain the relevant magic. If you do not define this macro, a suitable
-    __declspec value is used for Windows systems; in other environments
-   "extern" is used for a C compiler and "extern C" for a C++ compiler.
+   __declspec value is used for Windows systems; in other environments
+   a compiler relevant "extern" is used with any "visibility" related
+   attributes from PCRE2_EXPORT included.
    This macro apears at the start of every exported function that is part
    of the external API. It does not appear on functions that are "external"
    in the C sense, but which are internal to the library. */
@@ -298,11 +311,14 @@ sure both macros are undefined; an emulation function will then be used. */
    unless SUPPORT_JIT is also defined. */
 /* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */
 
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
+/* Define to 1 if all of the C89 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 */
 
+/* Define to any value to enable differential fuzzing support. */
+/* #undef SUPPORT_DIFF_FUZZ */
+
 /* Define to any value to enable support for Just-In-Time compiling. */
 /* #undef SUPPORT_JIT */
 
@@ -350,7 +366,7 @@ sure both macros are undefined; an emulation function will then be used. */
 /* Define to any value for valgrind support to find invalid memory reads. */
 /* #undef SUPPORT_VALGRIND */
 
-/* Enable extensions on AIX 3, Interix.  */
+/* Enable extensions on AIX, Interix, z/OS.  */
 #ifndef _ALL_SOURCE
 # define _ALL_SOURCE 1
 #endif
@@ -411,11 +427,15 @@ sure both macros are undefined; an emulation function will then be used. */
 #ifndef __STDC_WANT_IEC_60559_DFP_EXT__
 # define __STDC_WANT_IEC_60559_DFP_EXT__ 1
 #endif
+/* Enable extensions specified by C23 Annex F.  */
+#ifndef __STDC_WANT_IEC_60559_EXT__
+# define __STDC_WANT_IEC_60559_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.  */
+/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015.  */
 #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
 # define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
 #endif
@@ -438,20 +458,26 @@ sure both macros are undefined; an emulation function will then be used. */
 #endif
 
 /* Version number of package */
-#define VERSION "10.42"
+#define VERSION "10.43"
 
 /* Number of bits in a file offset, on hosts where this is settable. */
 /* #undef _FILE_OFFSET_BITS */
 
-/* Define for large files, on AIX-style hosts. */
+/* Define to 1 on platforms where this makes off_t a 64-bit type. */
 /* #undef _LARGE_FILES */
 
-/* Define to empty if `const' does not conform to ANSI C. */
+/* Number of bits in time_t, on hosts where this is settable. */
+/* #undef _TIME_BITS */
+
+/* Define to 1 on platforms where this makes time_t a 64-bit type. */
+/* #undef __MINGW_USE_VC2005_COMPAT */
+
+/* Define to empty if 'const' does not conform to ANSI C. */
 /* #undef const */
 
 /* Define to the type of a signed integer type of width exactly 64 bits if
    such a type exists and the standard includes do not define it. */
 /* #undef int64_t */
 
-/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* Define as 'unsigned int' if <stddef.h> doesn't define. */
 /* #undef size_t */

+ 22 - 8
thirdparty/pcre2/src/pcre2.h

@@ -5,7 +5,7 @@
 /* This is the public header file for the PCRE library, second API, to be
 #included by applications that call PCRE2 functions.
 
-           Copyright (c) 2016-2021 University of Cambridge
+           Copyright (c) 2016-2024 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
 /* The current PCRE version information. */
 
 #define PCRE2_MAJOR           10
-#define PCRE2_MINOR           42
+#define PCRE2_MINOR           43
 #define PCRE2_PRERELEASE      
-#define PCRE2_DATE            2022-12-11
+#define PCRE2_DATE            2024-02-16
 
 /* 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
@@ -153,6 +153,12 @@ D   is inspected during pcre2_dfa_match() execution
 #define PCRE2_EXTRA_ESCAPED_CR_IS_LF         0x00000010u  /* C */
 #define PCRE2_EXTRA_ALT_BSUX                 0x00000020u  /* C */
 #define PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK     0x00000040u  /* C */
+#define PCRE2_EXTRA_CASELESS_RESTRICT        0x00000080u  /* C */
+#define PCRE2_EXTRA_ASCII_BSD                0x00000100u  /* C */
+#define PCRE2_EXTRA_ASCII_BSS                0x00000200u  /* C */
+#define PCRE2_EXTRA_ASCII_BSW                0x00000400u  /* C */
+#define PCRE2_EXTRA_ASCII_POSIX              0x00000800u  /* C */
+#define PCRE2_EXTRA_ASCII_DIGIT              0x00001000u  /* C */
 
 /* These are for pcre2_jit_compile(). */
 
@@ -180,11 +186,12 @@ pcre2_jit_match() ignores the latter since it bypasses all sanity checks). */
 #define PCRE2_SUBSTITUTE_UNSET_EMPTY      0x00000400u  /* pcre2_substitute() only */
 #define PCRE2_SUBSTITUTE_UNKNOWN_UNSET    0x00000800u  /* pcre2_substitute() only */
 #define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH  0x00001000u  /* pcre2_substitute() only */
-#define PCRE2_NO_JIT                      0x00002000u  /* Not for pcre2_dfa_match() */
+#define PCRE2_NO_JIT                      0x00002000u  /* not for pcre2_dfa_match() */
 #define PCRE2_COPY_MATCHED_SUBJECT        0x00004000u
 #define PCRE2_SUBSTITUTE_LITERAL          0x00008000u  /* pcre2_substitute() only */
 #define PCRE2_SUBSTITUTE_MATCHED          0x00010000u  /* pcre2_substitute() only */
 #define PCRE2_SUBSTITUTE_REPLACEMENT_ONLY 0x00020000u  /* pcre2_substitute() only */
+#define PCRE2_DISABLE_RECURSELOOP_CHECK   0x00040000u  /* not for pcre2_dfa_match() or pcre2_jit_match() */
 
 /* Options for pcre2_pattern_convert(). */
 
@@ -399,6 +406,7 @@ released, the numbers must not be changed. */
 #define PCRE2_ERROR_CONVERT_SYNTAX    (-64)
 #define PCRE2_ERROR_INTERNAL_DUPMATCH (-65)
 #define PCRE2_ERROR_DFA_UINVALID_UTF  (-66)
+#define PCRE2_ERROR_INVALIDOFFSET     (-67)
 
 
 /* Request types for pcre2_pattern_info() */
@@ -575,7 +583,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *);
 PCRE2_EXP_DECL pcre2_general_context *PCRE2_CALL_CONVENTION \
   pcre2_general_context_copy(pcre2_general_context *); \
 PCRE2_EXP_DECL pcre2_general_context *PCRE2_CALL_CONVENTION \
-  pcre2_general_context_create(void *(*)(PCRE2_SIZE, void *), \
+  pcre2_general_context_create(void *(*)(size_t, void *), \
     void (*)(void *, void *), void *); \
 PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
   pcre2_general_context_free(pcre2_general_context *);
@@ -595,6 +603,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \
 PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_max_varlookbehind(pcre2_compile_context *, uint32_t); \
 PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_set_newline(pcre2_compile_context *, uint32_t); \
 PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
@@ -628,7 +638,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_set_recursion_limit(pcre2_match_context *, uint32_t); \
 PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_set_recursion_memory_management(pcre2_match_context *, \
-    void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *);
+    void *(*)(size_t, void *), void (*)(void *, void *), void *);
 
 #define PCRE2_CONVERT_CONTEXT_FUNCTIONS \
 PCRE2_EXP_DECL pcre2_convert_context *PCRE2_CALL_CONVENTION \
@@ -687,6 +697,8 @@ PCRE2_EXP_DECL PCRE2_SPTR PCRE2_CALL_CONVENTION \
   pcre2_get_mark(pcre2_match_data *); \
 PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
   pcre2_get_match_data_size(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+  pcre2_get_match_data_heapframes_size(pcre2_match_data *); \
 PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \
   pcre2_get_ovector_count(pcre2_match_data *); \
 PCRE2_EXP_DECL PCRE2_SIZE *PCRE2_CALL_CONVENTION \
@@ -722,7 +734,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
 PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_substring_number_from_name(const pcre2_code *, PCRE2_SPTR); \
 PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
-  pcre2_substring_list_free(PCRE2_SPTR *); \
+  pcre2_substring_list_free(PCRE2_UCHAR **); \
 PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
   pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **);
 
@@ -771,7 +783,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
 PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
   pcre2_jit_free_unused_memory(pcre2_general_context *); \
 PCRE2_EXP_DECL pcre2_jit_stack *PCRE2_CALL_CONVENTION \
-  pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, pcre2_general_context *); \
+  pcre2_jit_stack_create(size_t, size_t, pcre2_general_context *); \
 PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
   pcre2_jit_stack_assign(pcre2_match_context *, pcre2_jit_callback, void *); \
 PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
@@ -851,6 +863,7 @@ pcre2_compile are called by application code. */
 #define pcre2_general_context_free            PCRE2_SUFFIX(pcre2_general_context_free_)
 #define pcre2_get_error_message               PCRE2_SUFFIX(pcre2_get_error_message_)
 #define pcre2_get_mark                        PCRE2_SUFFIX(pcre2_get_mark_)
+#define pcre2_get_match_data_heapframes_size  PCRE2_SUFFIX(pcre2_get_match_data_heapframes_size_)
 #define pcre2_get_match_data_size             PCRE2_SUFFIX(pcre2_get_match_data_size_)
 #define pcre2_get_ovector_pointer             PCRE2_SUFFIX(pcre2_get_ovector_pointer_)
 #define pcre2_get_ovector_count               PCRE2_SUFFIX(pcre2_get_ovector_count_)
@@ -886,6 +899,7 @@ pcre2_compile are called by application code. */
 #define pcre2_set_glob_separator              PCRE2_SUFFIX(pcre2_set_glob_separator_)
 #define pcre2_set_heap_limit                  PCRE2_SUFFIX(pcre2_set_heap_limit_)
 #define pcre2_set_match_limit                 PCRE2_SUFFIX(pcre2_set_match_limit_)
+#define pcre2_set_max_varlookbehind           PCRE2_SUFFIX(pcre2_set_max_varlookbehind_)
 #define pcre2_set_max_pattern_length          PCRE2_SUFFIX(pcre2_set_max_pattern_length_)
 #define pcre2_set_newline                     PCRE2_SUFFIX(pcre2_set_newline_)
 #define pcre2_set_parens_nest_limit           PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)

+ 11 - 5
thirdparty/pcre2/src/pcre2_auto_possess.c

@@ -560,6 +560,8 @@ matches to an empty string (also represented by a non-zero value). */
 
 for(;;)
   {
+  PCRE2_SPTR bracode;
+
   /* All operations move the code pointer forward.
   Therefore infinite recursions are not possible. */
 
@@ -617,7 +619,8 @@ for(;;)
     recursions. (This could be improved by keeping a list of group numbers that
     are called by recursion.) */
 
-    switch(*(code - GET(code, 1)))
+    bracode = code - GET(code, 1);
+    switch(*bracode)
       {
       case OP_CBRA:
       case OP_SCBRA:
@@ -636,16 +639,19 @@ for(;;)
       break;
 
       /* Atomic sub-patterns and assertions can always auto-possessify their
-      last iterator. However, if the group was entered as a result of checking
-      a previous iterator, this is not possible. */
+      last iterator except for variable length lookbehinds. However, if the
+      group was entered as a result of checking a previous iterator, this is
+      not possible. */
 
       case OP_ASSERT:
       case OP_ASSERT_NOT:
-      case OP_ASSERTBACK:
-      case OP_ASSERTBACK_NOT:
       case OP_ONCE:
       return !entered_a_group;
 
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+      return (bracode[1+LINK_SIZE] == OP_VREVERSE)? FALSE : !entered_a_group;
+
       /* Non-atomic assertions - don't possessify last iterator. This needs
       more thought. */
 

+ 3 - 9
thirdparty/pcre2/src/pcre2_chartables.c

@@ -5,7 +5,8 @@
 /* This file was automatically written by the pcre2_dftables auxiliary
 program. It contains character tables that are used when no external
 tables are passed to PCRE2 by the application that calls it. The tables
-are used only for characters whose code values are less than 256. */
+are used only for characters whose code values are less than 256, and
+only relevant if not in UCP mode. */
 
 /* This set of tables was written in the C locale. */
 
@@ -18,13 +19,6 @@ PCRE2 is configured with --enable-rebuild-chartables. However, you can run
 pcre2_dftables manually with the -L option to build tables using the LC_ALL
 locale. */
 
-/* The following #include is present because without it gcc 4.x may remove
-the array definition from the final binary if PCRE2 is built into a static
-library and dead code stripping is activated. This leads to link errors.
-Pulling in the header ensures that the array gets flagged as "someone
-outside this compilation unit might reference this" and so it will always
-be supplied to the linker. */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -163,7 +157,7 @@ graph, print, punct, and cntrl. Other classes are built from combinations. */
   0x02   letter
   0x04   lower case letter
   0x08   decimal digit
-  0x10   alphanumeric or '_'
+  0x10   word (alphanumeric or '_')
 */
 
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */

+ 96 - 0
thirdparty/pcre2/src/pcre2_chkdint.c

@@ -0,0 +1,96 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                     Written by Philip Hazel
+            Copyright (c) 2023 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This file contains functions to implement checked integer operation */
+
+#ifndef PCRE2_PCRE2TEST
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+#endif
+
+/*************************************************
+*        Checked Integer Multiplication          *
+*************************************************/
+
+/*
+Arguments:
+  r         A pointer to PCRE2_SIZE to store the answer
+  a, b      Two integers
+
+Returns:    Bool indicating if the operation overflows
+
+It is modeled after C23's <stdckdint.h> interface
+The INT64_OR_DOUBLE type is a 64-bit integer type when available,
+otherwise double. */
+
+BOOL
+PRIV(ckd_smul)(PCRE2_SIZE *r, int a, int b)
+{
+#ifdef HAVE_BUILTIN_MUL_OVERFLOW
+PCRE2_SIZE m;
+
+if (__builtin_mul_overflow(a, b, &m)) return TRUE;
+
+*r = m;
+#else
+INT64_OR_DOUBLE m;
+
+#ifdef PCRE2_DEBUG
+if (a < 0 || b < 0) abort();
+#endif
+
+m = (INT64_OR_DOUBLE)a * (INT64_OR_DOUBLE)b;
+
+#if defined INT64_MAX || defined int64_t
+if (sizeof(m) > sizeof(*r) && m > (INT64_OR_DOUBLE)PCRE2_SIZE_MAX) return TRUE;
+*r = (PCRE2_SIZE)m;
+#else
+if (m > PCRE2_SIZE_MAX) return TRUE;
+*r = m;
+#endif
+
+#endif
+
+return FALSE;
+}
+
+/* End of pcre_chkdint.c */

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 361 - 177
thirdparty/pcre2/src/pcre2_compile.c


+ 27 - 19
thirdparty/pcre2/src/pcre2_context.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2022 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -139,7 +139,9 @@ const pcre2_compile_context PRIV(default_compile_context) = {
   BSR_DEFAULT,                               /* Backslash R default */
   NEWLINE_DEFAULT,                           /* Newline convention */
   PARENS_NEST_LIMIT,                         /* As it says */
-  0 };                                       /* Extra options */
+  0,                                         /* Extra options */
+  MAX_VARLOOKBEHIND                          /* As it says */
+  };
 
 /* The create function copies the default into the new memory, but must
 override the default memory handling functions if a gcontext was provided. */
@@ -228,49 +230,48 @@ return ccontext;
 PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
 pcre2_general_context_copy(pcre2_general_context *gcontext)
 {
-pcre2_general_context *new =
+pcre2_general_context *newcontext =
   gcontext->memctl.malloc(sizeof(pcre2_real_general_context),
   gcontext->memctl.memory_data);
-if (new == NULL) return NULL;
-memcpy(new, gcontext, sizeof(pcre2_real_general_context));
-return new;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, gcontext, sizeof(pcre2_real_general_context));
+return newcontext;
 }
 
 
 PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
 pcre2_compile_context_copy(pcre2_compile_context *ccontext)
 {
-pcre2_compile_context *new =
+pcre2_compile_context *newcontext =
   ccontext->memctl.malloc(sizeof(pcre2_real_compile_context),
   ccontext->memctl.memory_data);
-if (new == NULL) return NULL;
-memcpy(new, ccontext, sizeof(pcre2_real_compile_context));
-return new;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, ccontext, sizeof(pcre2_real_compile_context));
+return newcontext;
 }
 
 
 PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
 pcre2_match_context_copy(pcre2_match_context *mcontext)
 {
-pcre2_match_context *new =
+pcre2_match_context *newcontext =
   mcontext->memctl.malloc(sizeof(pcre2_real_match_context),
   mcontext->memctl.memory_data);
-if (new == NULL) return NULL;
-memcpy(new, mcontext, sizeof(pcre2_real_match_context));
-return new;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, mcontext, sizeof(pcre2_real_match_context));
+return newcontext;
 }
 
 
-
 PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION
 pcre2_convert_context_copy(pcre2_convert_context *ccontext)
 {
-pcre2_convert_context *new =
+pcre2_convert_context *newcontext =
   ccontext->memctl.malloc(sizeof(pcre2_real_convert_context),
   ccontext->memctl.memory_data);
-if (new == NULL) return NULL;
-memcpy(new, ccontext, sizeof(pcre2_real_convert_context));
-return new;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, ccontext, sizeof(pcre2_real_convert_context));
+return newcontext;
 }
 
 
@@ -370,6 +371,13 @@ switch(newline)
   }
 }
 
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_max_varlookbehind(pcre2_compile_context *ccontext, uint32_t limit)
+{
+ccontext->max_varlookbehind = limit;
+return 0;
+}
+
 PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
 pcre2_set_parens_nest_limit(pcre2_compile_context *ccontext, uint32_t limit)
 {

+ 8 - 0
thirdparty/pcre2/src/pcre2_convert.c

@@ -540,6 +540,14 @@ Returns:   !0 => character is found in the class
 static BOOL
 convert_glob_char_in_class(int class_index, PCRE2_UCHAR c)
 {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+if (c > 0xff)
+  {
+  /* ctype functions are not sane for c > 0xff */
+  return 0;
+  }
+#endif
+
 switch (class_index)
   {
   case 1: return isalnum(c);

+ 110 - 57
thirdparty/pcre2/src/pcre2_dfa_match.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2022 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -168,7 +168,7 @@ static const uint8_t coptable[] = {
   0,                             /* KetRmax                                */
   0,                             /* KetRmin                                */
   0,                             /* KetRpos                                */
-  0,                             /* Reverse                                */
+  0, 0,                          /* Reverse, Vreverse                      */
   0,                             /* Assert                                 */
   0,                             /* Assert not                             */
   0,                             /* Assert behind                          */
@@ -187,7 +187,8 @@ static const uint8_t coptable[] = {
   0, 0, 0, 0,                    /* SKIP, SKIP_ARG, THEN, THEN_ARG         */
   0, 0,                          /* COMMIT, COMMIT_ARG                     */
   0, 0, 0,                       /* FAIL, ACCEPT, ASSERT_ACCEPT            */
-  0, 0, 0                        /* CLOSE, SKIPZERO, DEFINE                */
+  0, 0, 0,                       /* CLOSE, SKIPZERO, DEFINE                */
+  0, 0                           /* \B and \b in UCP mode                  */
 };
 
 /* This table identifies those opcodes that inspect a character. It is used to
@@ -245,7 +246,7 @@ static const uint8_t poptable[] = {
   0,                             /* KetRmax                                */
   0,                             /* KetRmin                                */
   0,                             /* KetRpos                                */
-  0,                             /* Reverse                                */
+  0, 0,                          /* Reverse, Vreverse                      */
   0,                             /* Assert                                 */
   0,                             /* Assert not                             */
   0,                             /* Assert behind                          */
@@ -264,7 +265,8 @@ static const uint8_t poptable[] = {
   0, 0, 0, 0,                    /* SKIP, SKIP_ARG, THEN, THEN_ARG         */
   0, 0,                          /* COMMIT, COMMIT_ARG                     */
   0, 0, 0,                       /* FAIL, ACCEPT, ASSERT_ACCEPT            */
-  0, 0, 0                        /* CLOSE, SKIPZERO, DEFINE                */
+  0, 0, 0,                       /* CLOSE, SKIPZERO, DEFINE                */
+  1, 1                           /* \B and \b in UCP mode                  */
 };
 
 /* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W,
@@ -426,7 +428,7 @@ overflow. */
 
 else
   {
-  uint32_t newsize = (rws->size >= UINT32_MAX/2)? UINT32_MAX/2 : rws->size * 2;
+  uint32_t newsize = (rws->size >= UINT32_MAX/(sizeof(int)*2))? UINT32_MAX/sizeof(int) : rws->size * 2;
   uint32_t newsizeK = newsize/(1024/sizeof(int));
 
   if (newsizeK + mb->heap_used > mb->heap_limit)
@@ -589,7 +591,7 @@ if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT)
   end_code = this_start_code;
   do
     {
-    size_t back = (size_t)GET(end_code, 2+LINK_SIZE);
+    size_t back = (size_t)GET2(end_code, 2+LINK_SIZE);
     if (back > max_back) max_back = back;
     end_code += GET(end_code, 1);
     }
@@ -633,8 +635,8 @@ if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT)
   end_code = this_start_code;
   do
     {
-    uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + LINK_SIZE : 0;
-    size_t back = (revlen == 0)? 0 : (size_t)GET(end_code, 2+LINK_SIZE);
+    uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + IMM2_SIZE : 0;
+    size_t back = (revlen == 0)? 0 : (size_t)GET2(end_code, 2+LINK_SIZE);
     if (back <= gone_back)
       {
       int bstate = (int)(end_code - start_code + 1 + LINK_SIZE + revlen);
@@ -1100,6 +1102,8 @@ for (;;)
       /*-----------------------------------------------------------------*/
       case OP_WORD_BOUNDARY:
       case OP_NOT_WORD_BOUNDARY:
+      case OP_NOT_UCP_WORD_BOUNDARY:
+      case OP_UCP_WORD_BOUNDARY:
         {
         int left_word, right_word;
 
@@ -1112,13 +1116,13 @@ for (;;)
 #endif
           GETCHARTEST(d, temp);
 #ifdef SUPPORT_UNICODE
-          if ((mb->poptions & PCRE2_UCP) != 0)
+          if (codevalue == OP_UCP_WORD_BOUNDARY ||
+              codevalue == OP_NOT_UCP_WORD_BOUNDARY)
             {
-            if (d == '_') left_word = TRUE; else
-              {
-              uint32_t cat = UCD_CATEGORY(d);
-              left_word = (cat == ucp_L || cat == ucp_N);
-              }
+            int chartype = UCD_CHARTYPE(d);
+            int category = PRIV(ucp_gentype)[chartype];
+            left_word = (category == ucp_L || category == ucp_N ||
+              chartype == ucp_Mn || chartype == ucp_Pc);
             }
           else
 #endif
@@ -1137,13 +1141,13 @@ for (;;)
             mb->last_used_ptr = temp;
             }
 #ifdef SUPPORT_UNICODE
-          if ((mb->poptions & PCRE2_UCP) != 0)
+          if (codevalue == OP_UCP_WORD_BOUNDARY ||
+              codevalue == OP_NOT_UCP_WORD_BOUNDARY)
             {
-            if (c == '_') right_word = TRUE; else
-              {
-              uint32_t cat = UCD_CATEGORY(c);
-              right_word = (cat == ucp_L || cat == ucp_N);
-              }
+            int chartype = UCD_CHARTYPE(c);
+            int category = PRIV(ucp_gentype)[chartype];
+            right_word = (category == ucp_L || category == ucp_N ||
+              chartype == ucp_Mn || chartype == ucp_Pc);
             }
           else
 #endif
@@ -1151,7 +1155,9 @@ for (;;)
           }
         else right_word = FALSE;
 
-        if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY))
+        if ((left_word == right_word) ==
+            (codevalue == OP_NOT_WORD_BOUNDARY ||
+             codevalue == OP_NOT_UCP_WORD_BOUNDARY))
           { ADD_ACTIVE(state_offset + 1, 0); }
         }
       break;
@@ -1168,6 +1174,7 @@ for (;;)
       if (clen > 0)
         {
         BOOL OK;
+        int chartype;
         const uint32_t *cp;
         const ucd_record * prop = GET_UCD(c);
         switch(code[1])
@@ -1177,8 +1184,9 @@ for (;;)
           break;
 
           case PT_LAMP:
-          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
-               prop->chartype == ucp_Lt;
+          chartype = prop->chartype;
+          OK = chartype == ucp_Lu || chartype == ucp_Ll ||
+               chartype == ucp_Lt;
           break;
 
           case PT_GC:
@@ -1201,8 +1209,9 @@ for (;;)
           /* These are specials for combination cases. */
 
           case PT_ALNUM:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N;
           break;
 
           /* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -1225,12 +1234,20 @@ for (;;)
           break;
 
           case PT_WORD:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
-               c == CHAR_UNDERSCORE;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N ||
+               chartype == ucp_Mn || chartype == ucp_Pc;
           break;
 
           case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+          if (c > MAX_UTF_CODE_POINT)
+            {
+            OK = FALSE;
+            break;
+            }
+#endif
           cp = PRIV(ucd_caseless_sets) + code[2];
           for (;;)
             {
@@ -1440,6 +1457,7 @@ for (;;)
       if (clen > 0)
         {
         BOOL OK;
+        int chartype;
         const uint32_t *cp;
         const ucd_record * prop = GET_UCD(c);
         switch(code[2])
@@ -1449,8 +1467,8 @@ for (;;)
           break;
 
           case PT_LAMP:
-          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
-            prop->chartype == ucp_Lt;
+          chartype = prop->chartype;
+          OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt;
           break;
 
           case PT_GC:
@@ -1473,8 +1491,9 @@ for (;;)
           /* These are specials for combination cases. */
 
           case PT_ALNUM:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N;
           break;
 
           /* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -1497,12 +1516,20 @@ for (;;)
           break;
 
           case PT_WORD:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
-               c == CHAR_UNDERSCORE;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N ||
+               chartype == ucp_Mn || chartype == ucp_Pc;
           break;
 
           case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+          if (c > MAX_UTF_CODE_POINT)
+            {
+            OK = FALSE;
+            break;
+            }
+#endif
           cp = PRIV(ucd_caseless_sets) + code[3];
           for (;;)
             {
@@ -1695,6 +1722,7 @@ for (;;)
       if (clen > 0)
         {
         BOOL OK;
+        int chartype;
         const uint32_t *cp;
         const ucd_record * prop = GET_UCD(c);
         switch(code[2])
@@ -1704,8 +1732,8 @@ for (;;)
           break;
 
           case PT_LAMP:
-          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
-            prop->chartype == ucp_Lt;
+          chartype = prop->chartype;
+          OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt;
           break;
 
           case PT_GC:
@@ -1728,8 +1756,9 @@ for (;;)
           /* These are specials for combination cases. */
 
           case PT_ALNUM:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N;
           break;
 
           /* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -1752,12 +1781,20 @@ for (;;)
           break;
 
           case PT_WORD:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
-               c == CHAR_UNDERSCORE;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N ||
+               chartype == ucp_Mn || chartype == ucp_Pc;
           break;
 
           case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+          if (c > MAX_UTF_CODE_POINT)
+            {
+            OK = FALSE;
+            break;
+            }
+#endif
           cp = PRIV(ucd_caseless_sets) + code[3];
           for (;;)
             {
@@ -1975,6 +2012,7 @@ for (;;)
       if (clen > 0)
         {
         BOOL OK;
+        int chartype;
         const uint32_t *cp;
         const ucd_record * prop = GET_UCD(c);
         switch(code[1 + IMM2_SIZE + 1])
@@ -1984,8 +2022,8 @@ for (;;)
           break;
 
           case PT_LAMP:
-          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
-            prop->chartype == ucp_Lt;
+          chartype = prop->chartype;
+          OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt;
           break;
 
           case PT_GC:
@@ -2009,8 +2047,9 @@ for (;;)
           /* These are specials for combination cases. */
 
           case PT_ALNUM:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N;
           break;
 
           /* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -2033,12 +2072,20 @@ for (;;)
           break;
 
           case PT_WORD:
-          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
-               c == CHAR_UNDERSCORE;
+          chartype = prop->chartype;
+          OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+               PRIV(ucp_gentype)[chartype] == ucp_N ||
+               chartype == ucp_Mn || chartype == ucp_Pc;
           break;
 
           case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+          if (c > MAX_UTF_CODE_POINT)
+            {
+            OK = FALSE;
+            break;
+            }
+#endif
           cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2];
           for (;;)
             {
@@ -2894,7 +2941,6 @@ for (;;)
         int *local_workspace;
         PCRE2_SIZE *local_offsets;
         RWS_anchor *rws = (RWS_anchor *)RWS;
-        dfa_recursion_info *ri;
         PCRE2_SPTR callpat = start_code + GET(code, 1);
         uint32_t recno = (callpat == mb->start_code)? 0 :
           GET2(callpat, 1 + LINK_SIZE);
@@ -2911,18 +2957,24 @@ for (;;)
         rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;
 
         /* Check for repeating a recursion without advancing the subject
-        pointer. This should catch convoluted mutual recursions. (Some simple
-        cases are caught at compile time.) */
+        pointer or last used character. This should catch convoluted mutual
+        recursions. (Some simple cases are caught at compile time.) */
 
-        for (ri = mb->recursive; ri != NULL; ri = ri->prevrec)
-          if (recno == ri->group_num && ptr == ri->subject_position)
+        for (dfa_recursion_info *ri = mb->recursive;
+             ri != NULL;
+             ri = ri->prevrec)
+          {
+          if (recno == ri->group_num && ptr == ri->subject_position &&
+              mb->last_used_ptr == ri->last_used_ptr)
             return PCRE2_ERROR_RECURSELOOP;
+          }
 
         /* Remember this recursion and where we started it so as to
         catch infinite loops. */
 
         new_recursive.group_num = recno;
         new_recursive.subject_position = ptr;
+        new_recursive.last_used_ptr = mb->last_used_ptr;
         new_recursive.prevrec = mb->recursive;
         mb->recursive = &new_recursive;
 
@@ -3424,7 +3476,7 @@ anchored = (options & (PCRE2_ANCHORED|PCRE2_DFA_RESTART)) != 0 ||
 where to start. */
 
 startline = (re->flags & PCRE2_STARTLINE) != 0;
-firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+firstline = !anchored && (re->overall_options & PCRE2_FIRSTLINE) != 0;
 bumpalong_limit = end_subject;
 
 /* Initialize and set up the fixed fields in the callout block, with a pointer
@@ -3994,8 +4046,9 @@ for (;;)
       match_data->ovector[0] = (PCRE2_SIZE)(start_match - subject);
       match_data->ovector[1] = (PCRE2_SIZE)(end_subject - subject);
       }
+    match_data->subject_length = length;
     match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject);
-    match_data->rightchar = (PCRE2_SIZE)( mb->last_used_ptr - subject);
+    match_data->rightchar = (PCRE2_SIZE)(mb->last_used_ptr - subject);
     match_data->startchar = (PCRE2_SIZE)(start_match - subject);
     match_data->rc = rc;
 

+ 6 - 3
thirdparty/pcre2/src/pcre2_error.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2021 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -82,7 +82,7 @@ static const unsigned char compile_error_texts[] =
   "missing closing parenthesis\0"
   /* 15 */
   "reference to non-existent subpattern\0"
-  "pattern passed as NULL\0"
+  "pattern passed as NULL with non-zero length\0"
   "unrecognised compile-time option bit(s)\0"
   "missing ) after (?# comment\0"
   "parentheses are too deeply nested\0"
@@ -93,7 +93,7 @@ static const unsigned char compile_error_texts[] =
   "internal error: code overflow\0"
   "missing closing parenthesis for condition\0"
   /* 25 */
-  "lookbehind assertion is not fixed length\0"
+  "length of lookbehind assertion is not limited\0"
   "a relative value of zero is not allowed\0"
   "conditional subpattern contains more than two branches\0"
   "assertion expected after (?( or (?(?C)\0"
@@ -187,6 +187,8 @@ static const unsigned char compile_error_texts[] =
   "too many capturing groups (maximum 65535)\0"
   "atomic assertion expected after (?( or (?(?C)\0"
   "\\K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)\0"
+  /* 100 */
+  "branch too long in variable-length lookbehind assertion\0"
   ;
 
 /* Match-time and UTF error texts are in the same format. */
@@ -272,6 +274,7 @@ static const unsigned char match_error_texts[] =
   /* 65 */
   "internal error - duplicate substitution match\0"
   "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching\0"
+  "INTERNAL ERROR: invalid substring offset\0"
   ;
 
 

+ 5 - 5
thirdparty/pcre2/src/pcre2_find_bracket.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2018 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -41,9 +41,9 @@ POSSIBILITY OF SUCH DAMAGE.
 
 /* This module contains a single function that scans through a compiled pattern
 until it finds a capturing bracket with the given number, or, if the number is
-negative, an instance of OP_REVERSE for a lookbehind. The function is called
-from pcre2_compile.c and also from pcre2_study.c when finding the minimum
-matching length. */
+negative, an instance of OP_REVERSE or OP_VREVERSE for a lookbehind. The
+function is called from pcre2_compile.c and also from pcre2_study.c when
+finding the minimum matching length. */
 
 
 #ifdef HAVE_CONFIG_H
@@ -85,7 +85,7 @@ for (;;)
 
   /* Handle lookbehind */
 
-  else if (c == OP_REVERSE)
+  else if (c == OP_REVERSE || c == OP_VREVERSE)
     {
     if (number < 0) return (PCRE2_UCHAR *)code;
     code += PRIV(OP_lengths)[c];

+ 96 - 59
thirdparty/pcre2/src/pcre2_internal.h

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2022 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,24 @@ pcre2test.c with CODE_UNIT_WIDTH == 0. */
 #error The use of both EBCDIC and SUPPORT_UNICODE is not supported.
 #endif
 
+/* When compiling one of the libraries, the value of PCRE2_CODE_UNIT_WIDTH must
+be 8, 16, or 32. AutoTools and CMake ensure that this is always the case, but
+other other building methods may not, so here is a check. It is cut out when
+building pcre2test, bcause that sets the value to zero. No other source should
+be including this file. There is no explicit way of forcing a compile to be
+abandoned, but trying to include a non-existent file seems cleanest. Otherwise
+there will be many irrelevant consequential errors. */
+
+#if (!defined PCRE2_BUILDING_PCRE2TEST && !defined PCRE2_DFTABLES) && \
+  (!defined PCRE2_CODE_UNIT_WIDTH ||     \
+    (PCRE2_CODE_UNIT_WIDTH != 8 &&       \
+     PCRE2_CODE_UNIT_WIDTH != 16 &&      \
+     PCRE2_CODE_UNIT_WIDTH != 32))
+#error PCRE2_CODE_UNIT_WIDTH must be defined as 8, 16, or 32.
+#include <AbandonCompile>
+#endif
+
+
 /* Standard C headers */
 
 #include <ctype.h>
@@ -119,20 +137,20 @@ only if it is not already set. */
 #ifndef PCRE2_EXP_DECL
 #  ifdef _WIN32
 #    ifndef PCRE2_STATIC
-#      define PCRE2_EXP_DECL       extern __declspec(dllexport)
-#      define PCRE2_EXP_DEFN       __declspec(dllexport)
+#      define PCRE2_EXP_DECL		extern __declspec(dllexport)
+#      define PCRE2_EXP_DEFN		__declspec(dllexport)
 #    else
-#      define PCRE2_EXP_DECL       extern
+#      define PCRE2_EXP_DECL		extern PCRE2_EXPORT
 #      define PCRE2_EXP_DEFN
 #    endif
 #  else
 #    ifdef __cplusplus
-#      define PCRE2_EXP_DECL       extern "C"
+#      define PCRE2_EXP_DECL		extern "C" PCRE2_EXPORT
 #    else
-#      define PCRE2_EXP_DECL       extern
+#      define PCRE2_EXP_DECL		extern PCRE2_EXPORT
 #    endif
 #    ifndef PCRE2_EXP_DEFN
-#      define PCRE2_EXP_DEFN       PCRE2_EXP_DECL
+#      define PCRE2_EXP_DEFN		PCRE2_EXP_DECL
 #    endif
 #  endif
 #endif
@@ -156,8 +174,8 @@ pcre2_match() because of the way it backtracks. */
 #define PCRE2_SPTR CUSTOM_SUBJECT_PTR
 #endif
 
-/* When checking for integer overflow in pcre2_compile(), we need to handle
-large integers. If a 64-bit integer type is available, we can use that.
+/* When checking for integer overflow, we need to handle large integers.
+If a 64-bit integer type is available, we can use that.
 Otherwise we have to cast to double, which of course requires floating point
 arithmetic. Handle this by defining a macro for the appropriate type. */
 
@@ -1281,7 +1299,7 @@ match. */
 #define PT_ALNUM      6    /* Alphanumeric - the union of L and N */
 #define PT_SPACE      7    /* Perl space - general category Z plus 9,10,12,13 */
 #define PT_PXSPACE    8    /* POSIX space - Z plus 9,10,11,12,13 */
-#define PT_WORD       9    /* Word - L plus N plus underscore */
+#define PT_WORD       9    /* Word - L, N, Mn, or Pc */
 #define PT_CLIST     10    /* Pseudo-property: match character list */
 #define PT_UCNC      11    /* Universal Character nameable character */
 #define PT_BIDICL    12    /* Specified bidi class */
@@ -1297,6 +1315,7 @@ table. */
 #define PT_PXGRAPH   14    /* [:graph:] - characters that mark the paper */
 #define PT_PXPRINT   15    /* [:print:] - [:graph:] plus non-control spaces */
 #define PT_PXPUNCT   16    /* [:punct:] - punctuation characters */
+#define PT_PXXDIGIT  17    /* [:xdigit:] - hex digits */
 
 /* This value is used when parsing \p and \P escapes to indicate that neither
 \p{script:...} nor \p{scx:...} has been encountered. */
@@ -1327,6 +1346,12 @@ mode rather than an escape sequence. It is also used for [^] in JavaScript
 compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves
 like \N.
 
+ESC_ub is a special return from check_escape() when, in BSUX mode, \u{ is not
+followed by hex digits and }, in which case it should mean a literal "u"
+followed by a literal "{". This hack is necessary for cases like \u{ 12}
+because without it, this is interpreted as u{12} now that spaces are allowed in
+quantifiers.
+
 Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in
 check_escape(). There are tests in the code for an escape greater than ESC_b
 and less than ESC_Z to detect the types that may be repeated. These are the
@@ -1336,7 +1361,7 @@ consume a character, that code will have to change. */
 enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
        ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H,
        ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z,
-       ESC_E, ESC_Q, ESC_g, ESC_k };
+       ESC_E, ESC_Q, ESC_g, ESC_k, ESC_ub };
 
 
 /********************** Opcode definitions ******************/
@@ -1372,8 +1397,8 @@ enum {
   OP_SOD,            /* 1 Start of data: \A */
   OP_SOM,            /* 2 Start of match (subject + offset): \G */
   OP_SET_SOM,        /* 3 Set start of match (\K) */
-  OP_NOT_WORD_BOUNDARY,  /*  4 \B */
-  OP_WORD_BOUNDARY,      /*  5 \b */
+  OP_NOT_WORD_BOUNDARY,  /*  4 \B -- see also OP_NOT_UCP_WORD_BOUNDARY */
+  OP_WORD_BOUNDARY,      /*  5 \b -- see also OP_UCP_WORD_BOUNDARY */
   OP_NOT_DIGIT,          /*  6 \D */
   OP_DIGIT,              /*  7 \d */
   OP_NOT_WHITESPACE,     /*  8 \S */
@@ -1547,78 +1572,85 @@ enum {
   /* The assertions must come before BRA, CBRA, ONCE, and COND. */
 
   OP_REVERSE,        /* 125 Move pointer back - used in lookbehind assertions */
-  OP_ASSERT,         /* 126 Positive lookahead */
-  OP_ASSERT_NOT,     /* 127 Negative lookahead */
-  OP_ASSERTBACK,     /* 128 Positive lookbehind */
-  OP_ASSERTBACK_NOT, /* 129 Negative lookbehind */
-  OP_ASSERT_NA,      /* 130 Positive non-atomic lookahead */
-  OP_ASSERTBACK_NA,  /* 131 Positive non-atomic lookbehind */
+  OP_VREVERSE,       /* 126 Move pointer back - variable */
+  OP_ASSERT,         /* 127 Positive lookahead */
+  OP_ASSERT_NOT,     /* 128 Negative lookahead */
+  OP_ASSERTBACK,     /* 129 Positive lookbehind */
+  OP_ASSERTBACK_NOT, /* 130 Negative lookbehind */
+  OP_ASSERT_NA,      /* 131 Positive non-atomic lookahead */
+  OP_ASSERTBACK_NA,  /* 132 Positive non-atomic lookbehind */
 
   /* ONCE, SCRIPT_RUN, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come
   immediately after the assertions, with ONCE first, as there's a test for >=
   ONCE for a subpattern that isn't an assertion. The POS versions must
   immediately follow the non-POS versions in each case. */
 
-  OP_ONCE,           /* 132 Atomic group, contains captures */
-  OP_SCRIPT_RUN,     /* 133 Non-capture, but check characters' scripts */
-  OP_BRA,            /* 134 Start of non-capturing bracket */
-  OP_BRAPOS,         /* 135 Ditto, with unlimited, possessive repeat */
-  OP_CBRA,           /* 136 Start of capturing bracket */
-  OP_CBRAPOS,        /* 137 Ditto, with unlimited, possessive repeat */
-  OP_COND,           /* 138 Conditional group */
+  OP_ONCE,           /* 133 Atomic group, contains captures */
+  OP_SCRIPT_RUN,     /* 134 Non-capture, but check characters' scripts */
+  OP_BRA,            /* 135 Start of non-capturing bracket */
+  OP_BRAPOS,         /* 136 Ditto, with unlimited, possessive repeat */
+  OP_CBRA,           /* 137 Start of capturing bracket */
+  OP_CBRAPOS,        /* 138 Ditto, with unlimited, possessive repeat */
+  OP_COND,           /* 139 Conditional group */
 
   /* These five must follow the previous five, in the same order. There's a
   check for >= SBRA to distinguish the two sets. */
 
-  OP_SBRA,           /* 139 Start of non-capturing bracket, check empty  */
-  OP_SBRAPOS,        /* 149 Ditto, with unlimited, possessive repeat */
-  OP_SCBRA,          /* 141 Start of capturing bracket, check empty */
-  OP_SCBRAPOS,       /* 142 Ditto, with unlimited, possessive repeat */
-  OP_SCOND,          /* 143 Conditional group, check empty */
+  OP_SBRA,           /* 140 Start of non-capturing bracket, check empty  */
+  OP_SBRAPOS,        /* 141 Ditto, with unlimited, possessive repeat */
+  OP_SCBRA,          /* 142 Start of capturing bracket, check empty */
+  OP_SCBRAPOS,       /* 143 Ditto, with unlimited, possessive repeat */
+  OP_SCOND,          /* 144 Conditional group, check empty */
 
   /* The next two pairs must (respectively) be kept together. */
 
-  OP_CREF,           /* 144 Used to hold a capture number as condition */
-  OP_DNCREF,         /* 145 Used to point to duplicate names as a condition */
-  OP_RREF,           /* 146 Used to hold a recursion number as condition */
-  OP_DNRREF,         /* 147 Used to point to duplicate names as a condition */
-  OP_FALSE,          /* 148 Always false (used by DEFINE and VERSION) */
-  OP_TRUE,           /* 149 Always true (used by VERSION) */
+  OP_CREF,           /* 145 Used to hold a capture number as condition */
+  OP_DNCREF,         /* 146 Used to point to duplicate names as a condition */
+  OP_RREF,           /* 147 Used to hold a recursion number as condition */
+  OP_DNRREF,         /* 148 Used to point to duplicate names as a condition */
+  OP_FALSE,          /* 149 Always false (used by DEFINE and VERSION) */
+  OP_TRUE,           /* 150 Always true (used by VERSION) */
 
-  OP_BRAZERO,        /* 150 These two must remain together and in this */
-  OP_BRAMINZERO,     /* 151 order. */
-  OP_BRAPOSZERO,     /* 152 */
+  OP_BRAZERO,        /* 151 These two must remain together and in this */
+  OP_BRAMINZERO,     /* 152 order. */
+  OP_BRAPOSZERO,     /* 153 */
 
   /* These are backtracking control verbs */
 
-  OP_MARK,           /* 153 always has an argument */
-  OP_PRUNE,          /* 154 */
-  OP_PRUNE_ARG,      /* 155 same, but with argument */
-  OP_SKIP,           /* 156 */
-  OP_SKIP_ARG,       /* 157 same, but with argument */
-  OP_THEN,           /* 158 */
-  OP_THEN_ARG,       /* 159 same, but with argument */
-  OP_COMMIT,         /* 160 */
-  OP_COMMIT_ARG,     /* 161 same, but with argument */
+  OP_MARK,           /* 154 always has an argument */
+  OP_PRUNE,          /* 155 */
+  OP_PRUNE_ARG,      /* 156 same, but with argument */
+  OP_SKIP,           /* 157 */
+  OP_SKIP_ARG,       /* 158 same, but with argument */
+  OP_THEN,           /* 159 */
+  OP_THEN_ARG,       /* 160 same, but with argument */
+  OP_COMMIT,         /* 161 */
+  OP_COMMIT_ARG,     /* 162 same, but with argument */
 
   /* These are forced failure and success verbs. FAIL and ACCEPT do accept an
   argument, but these cases can be compiled as, for example, (*MARK:X)(*FAIL)
   without the need for a special opcode. */
 
-  OP_FAIL,           /* 162 */
-  OP_ACCEPT,         /* 163 */
-  OP_ASSERT_ACCEPT,  /* 164 Used inside assertions */
-  OP_CLOSE,          /* 165 Used before OP_ACCEPT to close open captures */
+  OP_FAIL,           /* 163 */
+  OP_ACCEPT,         /* 164 */
+  OP_ASSERT_ACCEPT,  /* 165 Used inside assertions */
+  OP_CLOSE,          /* 166 Used before OP_ACCEPT to close open captures */
 
   /* This is used to skip a subpattern with a {0} quantifier */
 
-  OP_SKIPZERO,       /* 166 */
+  OP_SKIPZERO,       /* 167 */
 
   /* This is used to identify a DEFINE group during compilation so that it can
   be checked for having only one branch. It is changed to OP_FALSE before
   compilation finishes. */
 
-  OP_DEFINE,         /* 167 */
+  OP_DEFINE,         /* 168 */
+
+  /* These opcodes replace their normal counterparts in UCP mode when
+  PCRE2_EXTRA_ASCII_BSW is not set. */
+
+  OP_NOT_UCP_WORD_BOUNDARY, /* 169 */
+  OP_UCP_WORD_BOUNDARY,     /* 170 */
 
   /* This is not an opcode, but is used to check that tables indexed by opcode
   are the correct length, in order to catch updating errors - there have been
@@ -1664,7 +1696,7 @@ some cases doesn't actually use these names at all). */
   "class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi",  \
   "Recurse", "Callout", "CalloutStr",                             \
   "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos",                  \
-  "Reverse", "Assert", "Assert not",                              \
+  "Reverse", "VReverse", "Assert", "Assert not",                  \
   "Assert back", "Assert back not",                               \
   "Non-atomic assert", "Non-atomic assert back",                  \
   "Once",                                                         \
@@ -1679,7 +1711,7 @@ some cases doesn't actually use these names at all). */
   "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP",                  \
   "*THEN", "*THEN", "*COMMIT", "*COMMIT", "*FAIL",                \
   "*ACCEPT", "*ASSERT_ACCEPT",                                    \
-  "Close", "Skip zero", "Define"
+  "Close", "Skip zero", "Define", "\\B (ucp)", "\\b (ucp)"
 
 
 /* This macro defines the length of fixed length operations in the compiled
@@ -1746,7 +1778,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */
   1+LINK_SIZE,                   /* KetRmax                                */ \
   1+LINK_SIZE,                   /* KetRmin                                */ \
   1+LINK_SIZE,                   /* KetRpos                                */ \
-  1+LINK_SIZE,                   /* Reverse                                */ \
+  1+IMM2_SIZE,                   /* Reverse                                */ \
+  1+2*IMM2_SIZE,                 /* VReverse                               */ \
   1+LINK_SIZE,                   /* Assert                                 */ \
   1+LINK_SIZE,                   /* Assert not                             */ \
   1+LINK_SIZE,                   /* Assert behind                          */ \
@@ -1775,7 +1808,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */
   1, 3,                          /* COMMIT, COMMIT_ARG                     */ \
   1, 1, 1,                       /* FAIL, ACCEPT, ASSERT_ACCEPT            */ \
   1+IMM2_SIZE, 1,                /* CLOSE, SKIPZERO                        */ \
-  1                              /* DEFINE                                 */
+  1,                             /* DEFINE                                 */ \
+  1, 1                           /* \B and \b in UCP mode                  */
 
 /* A magic value for OP_RREF to indicate the "any recursion" condition. */
 
@@ -2042,6 +2076,9 @@ extern void *       _pcre2_memmove(void *, const void *, size_t);
 #endif
 
 #endif  /* PCRE2_CODE_UNIT_WIDTH */
+
+extern BOOL         PRIV(ckd_smul)(PCRE2_SIZE *, int, int);
+
 #endif  /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */
 
 /* End of pcre2_internal.h */

+ 31 - 26
thirdparty/pcre2/src/pcre2_intmodedep.h

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2022 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -572,6 +572,7 @@ typedef struct pcre2_real_compile_context {
   uint16_t newline_convention;
   uint32_t parens_nest_limit;
   uint32_t extra_options;
+  uint32_t max_varlookbehind;
 } pcre2_real_compile_context;
 
 /* The real match context structure. */
@@ -605,12 +606,12 @@ defined specially because it is required in pcre2_serialize_decode() when
 copying the size from possibly unaligned memory into a variable of the same
 type. Use a macro rather than a typedef to avoid compiler warnings when this
 file is included multiple times by pcre2test. LOOKBEHIND_MAX specifies the
-largest lookbehind that is supported. (OP_REVERSE in a pattern has a 16-bit
-argument in 8-bit and 16-bit modes, so we need no more than a 16-bit field
-here.) */
+largest lookbehind that is supported. (OP_REVERSE and OP_VREVERSE in a pattern
+have 16-bit arguments in 8-bit and 16-bit modes, so we need no more than a
+16-bit field here.) */
 
 #undef  CODE_BLOCKSIZE_TYPE
-#define CODE_BLOCKSIZE_TYPE size_t
+#define CODE_BLOCKSIZE_TYPE PCRE2_SIZE
 
 #undef  LOOKBEHIND_MAX
 #define LOOKBEHIND_MAX UINT16_MAX
@@ -658,6 +659,7 @@ typedef struct pcre2_real_match_data {
   PCRE2_SPTR       mark;             /* Pointer to last mark */
   struct heapframe *heapframes;      /* Backtracking frames heap memory */
   PCRE2_SIZE       heapframes_size;  /* Malloc-ed size */
+  PCRE2_SIZE       subject_length;   /* Subject length */
   PCRE2_SIZE       leftchar;         /* Offset to leftmost code unit */
   PCRE2_SIZE       rightchar;        /* Offset to rightmost code unit */
   PCRE2_SIZE       startchar;        /* Offset to starting code unit */
@@ -675,8 +677,8 @@ typedef struct pcre2_real_match_data {
 
 #ifndef PCRE2_PCRE2TEST
 
-/* Structures for checking for mutual recursion when scanning compiled or
-parsed code. */
+/* Structures for checking for mutual function recursion when scanning compiled
+or parsed code. */
 
 typedef struct recurse_check {
   struct recurse_check *prev;
@@ -688,7 +690,7 @@ typedef struct parsed_recurse_check {
   uint32_t *groupptr;
 } parsed_recurse_check;
 
-/* Structure for building a cache when filling in recursion offsets. */
+/* Structure for building a cache when filling in pattern recursion offsets. */
 
 typedef struct recurse_cache {
   PCRE2_SPTR group;
@@ -734,7 +736,6 @@ typedef struct compile_block {
   uint16_t name_entry_size;        /* Size of each entry */
   uint16_t parens_depth;           /* Depth of nested parentheses */
   uint16_t assert_depth;           /* Depth of nested assertions */
-  open_capitem *open_caps;         /* Chain of open capture items */
   named_group *named_groups;       /* Points to vector in pre-compile */
   uint32_t named_group_list_size;  /* Number of entries in the list */
   uint32_t external_options;       /* External (initial) options */
@@ -752,10 +753,11 @@ typedef struct compile_block {
   uint32_t class_range_end;        /* Overall class range end */
   PCRE2_UCHAR nl[4];               /* Newline string when fixed length */
   uint32_t req_varyopt;            /* "After variable item" flag for reqbyte */
-  int  max_lookbehind;             /* Maximum lookbehind (characters) */
+  uint32_t max_varlookbehind;      /* Limit for variable lookbehinds */
+  int  max_lookbehind;             /* Maximum lookbehind encountered (characters) */
   BOOL had_accept;                 /* (*ACCEPT) encountered */
   BOOL had_pruneorskip;            /* (*PRUNE) or (*SKIP) encountered */
-  BOOL had_recurse;                /* Had a recursion or subroutine call */
+  BOOL had_recurse;                /* Had a pattern recursion or subroutine call */
   BOOL dupnames;                   /* Duplicate names exist */
 } compile_block;
 
@@ -773,6 +775,7 @@ call within the pattern when running pcre2_dfa_match(). */
 typedef struct dfa_recursion_info {
   struct dfa_recursion_info *prevrec;
   PCRE2_SPTR subject_position;
+  PCRE2_SPTR last_used_ptr;
   uint32_t group_num;
 } dfa_recursion_info;
 
@@ -793,7 +796,7 @@ typedef struct heapframe {
   PCRE2_SIZE length;         /* Used for character, string, or code lengths */
   PCRE2_SIZE back_frame;     /* Amount to subtract on RRETURN */
   PCRE2_SIZE temp_size;      /* Used for short-term PCRE2_SIZE values */
-  uint32_t rdepth;           /* "Recursion" depth */
+  uint32_t rdepth;           /* Function "recursion" depth within pcre2_match() */
   uint32_t group_frame_type; /* Type information for group frames */
   uint32_t temp_32[4];       /* Used for short-term 32-bit or BOOL values */
   uint8_t return_id;         /* Where to go on in internal "return" */
@@ -826,14 +829,15 @@ typedef struct heapframe {
   allows for exactly the right size ovector for the number of capturing
   parentheses. (See also the comment for pcre2_real_match_data above.) */
 
-  PCRE2_SPTR eptr;           /* MUST BE FIRST */
-  PCRE2_SPTR start_match;    /* Can be adjusted by \K */
-  PCRE2_SPTR mark;           /* Most recent mark on the success path */
-  uint32_t current_recurse;  /* Current (deepest) recursion number */
-  uint32_t capture_last;     /* Most recent capture */
-  PCRE2_SIZE last_group_offset;  /* Saved offset to most recent group frame */
-  PCRE2_SIZE offset_top;     /* Offset after highest capture */
-  PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
+  PCRE2_SPTR eptr;              /* MUST BE FIRST */
+  PCRE2_SPTR start_match;       /* Can be adjusted by \K */
+  PCRE2_SPTR mark;              /* Most recent mark on the success path */
+  PCRE2_SPTR recurse_last_used; /* Last character used at time of pattern recursion */
+  uint32_t current_recurse;     /* Group number of current (deepest) pattern recursion */
+  uint32_t capture_last;        /* Most recent capture */
+  PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */
+  PCRE2_SIZE offset_top;        /* Offset after highest capture */
+  PCRE2_SIZE ovector[131072];   /* Must be last in the structure */
 } heapframe;
 
 /* This typedef is a check that the size of the heapframe structure is a
@@ -858,7 +862,7 @@ doing traditional NFA matching (pcre2_match() and friends). */
 
 typedef struct match_block {
   pcre2_memctl memctl;            /* For general use */
-  PCRE2_SIZE heap_limit;          /* As it says */
+  uint32_t heap_limit;            /* As it says */
   uint32_t match_limit;           /* As it says */
   uint32_t match_limit_depth;     /* As it says */
   uint32_t match_call_count;      /* Number of times a new frame is created */
@@ -875,10 +879,11 @@ typedef struct match_block {
   uint16_t name_count;            /* Number of names in name table */
   uint16_t name_entry_size;       /* Size of entry in names table */
   PCRE2_SPTR name_table;          /* Table of group names */
-  PCRE2_SPTR start_code;          /* For use when recursing */
+  PCRE2_SPTR start_code;          /* For use in pattern recursion */
   PCRE2_SPTR start_subject;       /* Start of the subject string */
   PCRE2_SPTR check_subject;       /* Where UTF-checked from */
-  PCRE2_SPTR end_subject;         /* End of the subject string */
+  PCRE2_SPTR end_subject;         /* Usable end of the subject string */
+  PCRE2_SPTR true_end_subject;    /* Actual end of the subject string */
   PCRE2_SPTR end_match_ptr;       /* Subject position at end match */
   PCRE2_SPTR start_used_ptr;      /* Earliest consulted character */
   PCRE2_SPTR last_used_ptr;       /* Latest consulted character */
@@ -886,7 +891,7 @@ typedef struct match_block {
   PCRE2_SPTR nomatch_mark;        /* Mark pointer to pass back on failure */
   PCRE2_SPTR verb_ecode_ptr;      /* For passing back info */
   PCRE2_SPTR verb_skip_ptr;       /* For passing back a (*SKIP) name */
-  uint32_t verb_current_recurse;  /* Current recurse when (*VERB) happens */
+  uint32_t verb_current_recurse;  /* Current recursion group when (*VERB) happens */
   uint32_t moptions;              /* Match options */
   uint32_t poptions;              /* Pattern options */
   uint32_t skip_arg_count;        /* For counting SKIP_ARGs */
@@ -911,7 +916,7 @@ typedef struct dfa_match_block {
   PCRE2_SPTR last_used_ptr;       /* Latest consulted character */
   const uint8_t *tables;          /* Character tables */
   PCRE2_SIZE start_offset;        /* The start offset value */
-  PCRE2_SIZE heap_limit;          /* As it says */
+  uint32_t heap_limit;            /* As it says */
   PCRE2_SIZE heap_used;           /* As it says */
   uint32_t match_limit;           /* As it says */
   uint32_t match_limit_depth;     /* As it says */
@@ -926,7 +931,7 @@ typedef struct dfa_match_block {
   pcre2_callout_block *cb;        /* Points to a callout block */
   void *callout_data;             /* To pass back to callouts */
   int (*callout)(pcre2_callout_block *,void *);  /* Callout function or NULL */
-  dfa_recursion_info *recursive;  /* Linked list of recursion data */
+  dfa_recursion_info *recursive;  /* Linked list of pattern recursion data */
 } dfa_match_block;
 
 #endif  /* PCRE2_PCRE2TEST */

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 294 - 139
thirdparty/pcre2/src/pcre2_jit_compile.c


+ 15 - 1
thirdparty/pcre2/src/pcre2_jit_match.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2018 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,12 @@ POSSIBILITY OF SUCH DAMAGE.
 #error This file must be included from pcre2_jit_compile.c.
 #endif
 
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+
 #ifdef SUPPORT_JIT
 
 static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_function executable_func)
@@ -171,6 +177,7 @@ if (rc > (int)oveccount)
   rc = 0;
 match_data->code = re;
 match_data->subject = (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)? subject : NULL;
+match_data->subject_length = length;
 match_data->rc = rc;
 match_data->startchar = arguments.startchar_ptr - subject;
 match_data->leftchar = 0;
@@ -178,6 +185,13 @@ match_data->rightchar = 0;
 match_data->mark = arguments.mark_ptr;
 match_data->matchedby = PCRE2_MATCHEDBY_JIT;
 
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+if (rc > 0)
+  __msan_unpoison(match_data->ovector, 2 * rc * sizeof(match_data->ovector[0]));
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+
 return match_data->rc;
 
 #endif  /* SUPPORT_JIT */

+ 29 - 24
thirdparty/pcre2/src/pcre2_jit_neon_inc.h

@@ -82,7 +82,12 @@ POSSIBILITY OF SUCH DAMAGE.
 #  endif
 # endif
 
-static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 *str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars)
+#if (defined(__GNUC__) && __SANITIZE_ADDRESS__) \
+	|| (defined(__clang__) \
+	&& ((__clang_major__ == 3 && __clang_minor__ >= 3) || (__clang_major__ > 3)))
+__attribute__((no_sanitize_address))
+#endif
+static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 **str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars)
 #undef FF_FUN
 {
 quad_word qw;
@@ -171,7 +176,7 @@ else
   }
 # endif
 
-str_ptr += IN_UCHARS(offs1);
+*str_ptr += IN_UCHARS(offs1);
 #endif
 
 #if PCRE2_CODE_UNIT_WIDTH != 8
@@ -183,13 +188,13 @@ restart:;
 #endif
 
 #if defined(FFCPS)
-if (str_ptr >= str_end)
+if (*str_ptr >= str_end)
   return NULL;
-sljit_u8 *p1 = str_ptr - diff;
+sljit_u8 *p1 = *str_ptr - diff;
 #endif
-sljit_s32 align_offset = ((uint64_t)str_ptr & 0xf);
-str_ptr = (sljit_u8 *) ((uint64_t)str_ptr & ~0xf);
-vect_t data = VLD1Q(str_ptr);
+sljit_s32 align_offset = ((uint64_t)*str_ptr & 0xf);
+*str_ptr = (sljit_u8 *) ((uint64_t)*str_ptr & ~0xf);
+vect_t data = VLD1Q(*str_ptr);
 #if PCRE2_CODE_UNIT_WIDTH != 8
 data = VANDQ(data, char_mask);
 #endif
@@ -212,9 +217,9 @@ vect_t prev_data = data;
 # endif
 
 vect_t data2;
-if (p1 < str_ptr)
+if (p1 < *str_ptr)
   {
-  data2 = VLD1Q(str_ptr - diff);
+  data2 = VLD1Q(*str_ptr - diff);
 #if PCRE2_CODE_UNIT_WIDTH != 8
   data2 = VANDQ(data2, char_mask);
 #endif
@@ -242,12 +247,12 @@ if (align_offset < 8)
   qw.dw[0] >>= align_offset * 8;
   if (qw.dw[0])
     {
-    str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8;
+    *str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8;
     goto match;
     }
   if (qw.dw[1])
     {
-    str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
+    *str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
     goto match;
     }
   }
@@ -256,15 +261,15 @@ else
   qw.dw[1] >>= (align_offset - 8) * 8;
   if (qw.dw[1])
     {
-    str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8;
+    *str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8;
     goto match;
     }
   }
-str_ptr += 16;
+*str_ptr += 16;
 
-while (str_ptr < str_end)
+while (*str_ptr < str_end)
   {
-  vect_t orig_data = VLD1Q(str_ptr);
+  vect_t orig_data = VLD1Q(*str_ptr);
 #if PCRE2_CODE_UNIT_WIDTH != 8
   orig_data = VANDQ(orig_data, char_mask);
 #endif
@@ -287,7 +292,7 @@ while (str_ptr < str_end)
 # if defined (FFCPS_DIFF1)
   data2 = VEXTQ(prev_data, data, VECTOR_FACTOR - 1);
 # else
-  data2 = VLD1Q(str_ptr - diff);
+  data2 = VLD1Q(*str_ptr - diff);
 #  if PCRE2_CODE_UNIT_WIDTH != 8
   data2 = VANDQ(data2, char_mask);
 #  endif
@@ -312,11 +317,11 @@ while (str_ptr < str_end)
 
   VST1Q(qw.mem, eq);
   if (qw.dw[0])
-    str_ptr += __builtin_ctzll(qw.dw[0]) / 8;
+    *str_ptr += __builtin_ctzll(qw.dw[0]) / 8;
   else if (qw.dw[1])
-    str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
+    *str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
   else {
-    str_ptr += 16;
+    *str_ptr += 16;
 #if defined (FFCPS_DIFF1)
     prev_data = orig_data;
 #endif
@@ -324,24 +329,24 @@ while (str_ptr < str_end)
   }
 
 match:;
-  if (str_ptr >= str_end)
+  if (*str_ptr >= str_end)
     /* Failed match. */
     return NULL;
 
 #if defined(FF_UTF)
-  if (utf_continue((PCRE2_SPTR)str_ptr - offs1))
+  if (utf_continue((PCRE2_SPTR)*str_ptr - offs1))
     {
     /* Not a match. */
-    str_ptr += IN_UCHARS(1);
+    *str_ptr += IN_UCHARS(1);
     goto restart;
     }
 #endif
 
   /* Match. */
 #if defined (FFCPS)
-  str_ptr -= IN_UCHARS(offs1);
+  *str_ptr -= IN_UCHARS(offs1);
 #endif
-  return str_ptr;
+  return *str_ptr;
   }
 
 /* Failed match. */

+ 779 - 282
thirdparty/pcre2/src/pcre2_jit_simd_inc.h

@@ -42,7 +42,8 @@ POSSIBILITY OF SUCH DAMAGE.
 #if !(defined SUPPORT_VALGRIND)
 
 #if ((defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
-     || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X))
+     || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+     || (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64))
 
 typedef enum {
   vector_compare_match1,
@@ -50,7 +51,27 @@ typedef enum {
   vector_compare_match2,
 } vector_compare_type;
 
-static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void)
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+static SLJIT_INLINE sljit_s32 max_fast_forward_char_pair_offset(void)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+/* The AVX2 code path is currently disabled. */
+/* return sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? 31 : 15; */
+return 15;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+/* The AVX2 code path is currently disabled. */
+/* return sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? 15 : 7; */
+return 7;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+/* The AVX2 code path is currently disabled. */
+/* return sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? 7 : 3; */
+return 3;
+#else
+#error "Unsupported unit width"
+#endif
+}
+#else /* !SLJIT_CONFIG_X86 */
+static SLJIT_INLINE sljit_s32 max_fast_forward_char_pair_offset(void)
 {
 #if PCRE2_CODE_UNIT_WIDTH == 8
 return 15;
@@ -62,6 +83,7 @@ return 3;
 #error "Unsupported unit width"
 #endif
 }
+#endif /* SLJIT_CONFIG_X86 */
 
 #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)
@@ -86,49 +108,35 @@ static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
 {
 sljit_u32 value = chr;
 #if PCRE2_CODE_UNIT_WIDTH == 8
-#define SSE2_COMPARE_TYPE_INDEX 0
+#define SIMD_COMPARE_TYPE_INDEX 0
 return (sljit_s32)((value << 24) | (value << 16) | (value << 8) | value);
 #elif PCRE2_CODE_UNIT_WIDTH == 16
-#define SSE2_COMPARE_TYPE_INDEX 1
+#define SIMD_COMPARE_TYPE_INDEX 1
 return (sljit_s32)((value << 16) | value);
 #elif PCRE2_CODE_UNIT_WIDTH == 32
-#define SSE2_COMPARE_TYPE_INDEX 2
+#define SIMD_COMPARE_TYPE_INDEX 2
 return (sljit_s32)(value);
 #else
 #error "Unsupported unit width"
 #endif
 }
 
-static void load_from_mem_sse2(struct sljit_compiler *compiler, sljit_s32 dst_xmm_reg, sljit_s32 src_general_reg, sljit_s8 offset)
+static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
+  sljit_s32 reg_type, int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
 {
-sljit_u8 instruction[5];
-
-SLJIT_ASSERT(dst_xmm_reg < 8);
-SLJIT_ASSERT(src_general_reg < 8);
-
-/* MOVDQA xmm1, xmm2/m128 */
-instruction[0] = ((sljit_u8)offset & 0xf) == 0 ? 0x66 : 0xf3;
-instruction[1] = 0x0f;
-instruction[2] = 0x6f;
+sljit_u8 instruction[4];
 
-if (offset == 0)
+if (reg_type == SLJIT_SIMD_REG_128)
   {
-  instruction[3] = (dst_xmm_reg << 3) | src_general_reg;
-  sljit_emit_op_custom(compiler, instruction, 4);
-  return;
+  instruction[0] = 0x66;
+  instruction[1] = 0x0f;
+  }
+else
+  {
+  /* Two byte VEX prefix. */
+  instruction[0] = 0xc5;
+  instruction[1] = 0xfd;
   }
-
-instruction[3] = 0x40 | (dst_xmm_reg << 3) | src_general_reg;
-instruction[4] = (sljit_u8)offset;
-sljit_emit_op_custom(compiler, instruction, 5);
-}
-
-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_u8 instruction[4];
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
 
 SLJIT_ASSERT(step >= 0 && step <= 3);
 
@@ -139,8 +147,10 @@ if (compare_type != vector_compare_match2)
     if (compare_type == vector_compare_match1i)
       {
       /* POR xmm1, xmm2/m128 */
-      /* instruction[0] = 0x66; */
-      /* instruction[1] = 0x0f; */
+      if (reg_type == SLJIT_SIMD_REG_256)
+        instruction[1] ^= (dst_ind << 3);
+
+      /* Prefix is filled. */
       instruction[2] = 0xeb;
       instruction[3] = 0xc0 | (dst_ind << 3) | cmp2_ind;
       sljit_emit_op_custom(compiler, instruction, 4);
@@ -152,20 +162,35 @@ if (compare_type != vector_compare_match2)
     return;
 
   /* PCMPEQB/W/D xmm1, xmm2/m128 */
-  /* instruction[0] = 0x66; */
-  /* instruction[1] = 0x0f; */
-  instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+  if (reg_type == SLJIT_SIMD_REG_256)
+    instruction[1] ^= (dst_ind << 3);
+
+  /* Prefix is filled. */
+  instruction[2] = 0x74 + SIMD_COMPARE_TYPE_INDEX;
   instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
   sljit_emit_op_custom(compiler, instruction, 4);
   return;
   }
 
+if (reg_type == SLJIT_SIMD_REG_256)
+  {
+  if (step == 2)
+    return;
+
+  if (step == 0)
+    {
+    step = 2;
+    instruction[1] ^= (dst_ind << 3);
+    }
+  }
+
 switch (step)
   {
   case 0:
+  SLJIT_ASSERT(reg_type == SLJIT_SIMD_REG_128);
+
   /* MOVDQA xmm1, xmm2/m128 */
-  /* instruction[0] = 0x66; */
-  /* instruction[1] = 0x0f; */
+  /* Prefix is filled. */
   instruction[2] = 0x6f;
   instruction[3] = 0xc0 | (tmp_ind << 3) | dst_ind;
   sljit_emit_op_custom(compiler, instruction, 4);
@@ -173,26 +198,29 @@ switch (step)
 
   case 1:
   /* PCMPEQB/W/D xmm1, xmm2/m128 */
-  /* instruction[0] = 0x66; */
-  /* instruction[1] = 0x0f; */
-  instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+  if (reg_type == SLJIT_SIMD_REG_256)
+    instruction[1] ^= (dst_ind << 3);
+
+  /* Prefix is filled. */
+  instruction[2] = 0x74 + SIMD_COMPARE_TYPE_INDEX;
   instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
   sljit_emit_op_custom(compiler, instruction, 4);
   return;
 
   case 2:
   /* PCMPEQB/W/D xmm1, xmm2/m128 */
-  /* instruction[0] = 0x66; */
-  /* instruction[1] = 0x0f; */
-  instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+  /* Prefix is filled. */
+  instruction[2] = 0x74 + SIMD_COMPARE_TYPE_INDEX;
   instruction[3] = 0xc0 | (tmp_ind << 3) | cmp2_ind;
   sljit_emit_op_custom(compiler, instruction, 4);
   return;
 
   case 3:
   /* POR xmm1, xmm2/m128 */
-  /* instruction[0] = 0x66; */
-  /* instruction[1] = 0x0f; */
+  if (reg_type == SLJIT_SIMD_REG_256)
+    instruction[1] ^= (dst_ind << 3);
+
+  /* Prefix is filled. */
   instruction[2] = 0xeb;
   instruction[3] = 0xc0 | (dst_ind << 3) | tmp_ind;
   sljit_emit_op_custom(compiler, instruction, 4);
@@ -200,12 +228,16 @@ switch (step)
   }
 }
 
-#define JIT_HAS_FAST_FORWARD_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SIMD))
 
 static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
 {
 DEFINE_COMPILER;
 sljit_u8 instruction[8];
+/* The AVX2 code path is currently disabled. */
+/* sljit_s32 reg_type = sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? SLJIT_SIMD_REG_256 : SLJIT_SIMD_REG_128; */
+sljit_s32 reg_type = SLJIT_SIMD_REG_128;
+sljit_s32 value;
 struct sljit_label *start;
 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
 struct sljit_label *restart;
@@ -213,12 +245,11 @@ struct sljit_label *restart;
 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 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 data_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR0);
+sljit_s32 cmp1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR1);
+sljit_s32 cmp2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR2);
+sljit_s32 tmp_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR3);
 sljit_u32 bit = 0;
 int i;
 
@@ -241,61 +272,34 @@ if (common->mode == PCRE2_JIT_COMPLETE)
   add_jump(compiler, &common->failed_match, partial_quit[0]);
 
 /* First part (unaligned start) */
-
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
-
-SLJIT_ASSERT(tmp1_reg_ind < 8);
-
-/* MOVD xmm, r/m32 */
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
-instruction[2] = 0x6e;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = SLJIT_SIMD_REG_128 | SLJIT_SIMD_ELEM_32 | SLJIT_SIMD_LANE_ZERO;
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
 
 if (char1 != char2)
-  {
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
-
-  /* MOVD xmm, r/m32 */
-  instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind;
-  sljit_emit_op_custom(compiler, instruction, 4);
-  }
+  sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR2, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
 
 OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
 
-/* PSHUFD xmm1, xmm2/m128, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x70;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind;
-instruction[4] = 0;
-sljit_emit_op_custom(compiler, instruction, 5);
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR1, SLJIT_FR1, 0);
 
 if (char1 != char2)
-  {
-  /* PSHUFD xmm1, xmm2/m128, imm8 */
-  instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind;
-  sljit_emit_op_custom(compiler, instruction, 5);
-  }
+  sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR2, SLJIT_FR2, 0);
 
 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
 restart = LABEL();
 #endif
-OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
-OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
 
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
-for (i = 0; i < 4; i++)
-  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 0x1f : 0xf;
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~value);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, value);
 
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
+
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
 
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
 OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
 OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
 
@@ -306,27 +310,24 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
 /* Second part (aligned) */
 start = LABEL();
 
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 32 : 16;
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
 
 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_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
 for (i = 0; i < 4; i++)
-  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
-
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
 
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
 CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
 
 JUMPHERE(quit);
 
+SLJIT_ASSERT(tmp1_reg_ind < 8);
 /* BSF r32, r/m32 */
 instruction[0] = 0x0f;
 instruction[1] = 0xbc;
@@ -340,7 +341,7 @@ if (common->mode != PCRE2_JIT_COMPLETE)
   JUMPHERE(partial_quit[0]);
   JUMPHERE(partial_quit[1]);
   OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
-  CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+  SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
   }
 else
   add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
@@ -364,22 +365,25 @@ if (common->utf && offset > 0)
 #endif
 }
 
-#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SIMD))
 
 static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
 {
 DEFINE_COMPILER;
 sljit_u8 instruction[8];
+/* The AVX2 code path is currently disabled. */
+/* sljit_s32 reg_type = sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? SLJIT_SIMD_REG_256 : SLJIT_SIMD_REG_128; */
+sljit_s32 reg_type = SLJIT_SIMD_REG_128;
+sljit_s32 value;
 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 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 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 data_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR0);
+sljit_s32 cmp1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR1);
+sljit_s32 cmp2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR2);
+sljit_s32 tmp_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR3);
 sljit_u32 bit = 0;
 int i;
 
@@ -401,57 +405,30 @@ OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
 
 /* First part (unaligned start) */
 
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
-
-SLJIT_ASSERT(tmp1_reg_ind < 8);
-
-/* MOVD xmm, r/m32 */
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
-instruction[2] = 0x6e;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = SLJIT_SIMD_REG_128 | SLJIT_SIMD_ELEM_32 | SLJIT_SIMD_LANE_ZERO;
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
 
 if (char1 != char2)
-  {
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
-
-  /* MOVD xmm, r/m32 */
-  instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind;
-  sljit_emit_op_custom(compiler, instruction, 4);
-  }
+  sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR2, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
 
 OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0);
 
-/* PSHUFD xmm1, xmm2/m128, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x70;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind;
-instruction[4] = 0;
-sljit_emit_op_custom(compiler, instruction, 5);
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR1, SLJIT_FR1, 0);
 
 if (char1 != char2)
-  {
-  /* PSHUFD xmm1, xmm2/m128, imm8 */
-  instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind;
-  sljit_emit_op_custom(compiler, instruction, 5);
-  }
+  sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR2, SLJIT_FR2, 0);
 
-OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
-OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 0x1f : 0xf;
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~value);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, value);
 
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
-for (i = 0; i < 4; i++)
-  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
 
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
 
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
 OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
 OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
 
@@ -462,25 +439,23 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
 /* Second part (aligned) */
 start = LABEL();
 
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 32 : 16;
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
 
 add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
 
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
-for (i = 0; i < 4; i++)
-  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
 
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
 
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
 CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
 
 JUMPHERE(quit);
 
+SLJIT_ASSERT(tmp1_reg_ind < 8);
 /* BSF r32, r/m32 */
 instruction[0] = 0x0f;
 instruction[1] = 0xbc;
@@ -496,29 +471,31 @@ return not_found;
 
 #ifndef _WIN64
 
-#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_SIMD))
 
 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_u8 instruction[8];
+/* The AVX2 code path is currently disabled. */
+/* sljit_s32 reg_type = sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? SLJIT_SIMD_REG_256 : SLJIT_SIMD_REG_128; */
+sljit_s32 reg_type = SLJIT_SIMD_REG_128;
+sljit_s32 value;
 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_u32 diff = IN_UCHARS(offs1 - offs2);
-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 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 data1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR0);
+sljit_s32 data2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR1);
+sljit_s32 cmp1a_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR2);
+sljit_s32 cmp2a_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR3);
+sljit_s32 cmp1b_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR4);
+sljit_s32 cmp2b_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR5);
+sljit_s32 tmp1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR6);
+sljit_s32 tmp2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_TMP_FR0);
 struct sljit_label *start;
 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
 struct sljit_label *restart;
@@ -526,9 +503,8 @@ struct sljit_label *restart;
 struct sljit_jump *jump[2];
 int i;
 
-SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
-SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset()));
-SLJIT_ASSERT(tmp1_reg_ind < 8 && tmp2_reg_ind == 1);
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2 && offs2 >= 0);
+SLJIT_ASSERT(diff <= (unsigned)IN_UCHARS(max_fast_forward_char_pair_offset()));
 
 /* Initialize. */
 if (common->match_end_ptr != 0)
@@ -538,17 +514,12 @@ if (common->match_end_ptr != 0)
   OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
 
   OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0);
-  CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+  SELECT(SLJIT_LESS, STR_END, TMP1, 0, STR_END);
   }
 
 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));
 
-/* MOVD xmm, r/m32 */
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
-instruction[2] = 0x6e;
-
 if (char1a == char1b)
   OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
 else
@@ -569,14 +540,11 @@ else
     }
   }
 
-instruction[3] = 0xc0 | (cmp1a_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = SLJIT_SIMD_REG_128 | SLJIT_SIMD_ELEM_32 | SLJIT_SIMD_LANE_ZERO;
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR2, 0, TMP1, 0);
 
 if (char1a != char1b)
-  {
-  instruction[3] = 0xc0 | (cmp1b_ind << 3) | tmp2_reg_ind;
-  sljit_emit_op_custom(compiler, instruction, 4);
-  }
+  sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR4, 0, TMP2, 0);
 
 if (char2a == char2b)
   OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
@@ -598,38 +566,18 @@ else
     }
   }
 
-instruction[3] = 0xc0 | (cmp2a_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR3, 0, TMP1, 0);
 
 if (char2a != char2b)
-  {
-  instruction[3] = 0xc0 | (cmp2b_ind << 3) | tmp2_reg_ind;
-  sljit_emit_op_custom(compiler, instruction, 4);
-  }
-
-/* PSHUFD xmm1, xmm2/m128, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x70;
-instruction[4] = 0;
-
-instruction[3] = 0xc0 | (cmp1a_ind << 3) | cmp1a_ind;
-sljit_emit_op_custom(compiler, instruction, 5);
+  sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR5, 0, TMP2, 0);
 
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR2, SLJIT_FR2, 0);
 if (char1a != char1b)
-  {
-  instruction[3] = 0xc0 | (cmp1b_ind << 3) | cmp1b_ind;
-  sljit_emit_op_custom(compiler, instruction, 5);
-  }
-
-instruction[3] = 0xc0 | (cmp2a_ind << 3) | cmp2a_ind;
-sljit_emit_op_custom(compiler, instruction, 5);
+  sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR4, SLJIT_FR4, 0);
 
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR3, SLJIT_FR3, 0);
 if (char2a != char2b)
-  {
-  instruction[3] = 0xc0 | (cmp2b_ind << 3) | cmp2b_ind;
-  sljit_emit_op_custom(compiler, instruction, 5);
-  }
+  sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR5, SLJIT_FR5, 0);
 
 #if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
 restart = LABEL();
@@ -637,55 +585,91 @@ restart = LABEL();
 
 OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, diff);
 OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
-OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+value = (reg_type == SLJIT_SIMD_REG_256) ? ~0x1f : ~0xf;
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
 
-load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
 
 jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_PTR, 0);
 
-load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff);
+sljit_emit_simd_mov(compiler, reg_type, SLJIT_FR1, SLJIT_MEM1(STR_PTR), -(sljit_sw)diff);
 jump[1] = JUMP(SLJIT_JUMP);
 
 JUMPHERE(jump[0]);
 
-/* MOVDQA xmm1, xmm2/m128 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x6f;
-instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
-
-/* PSLLDQ xmm1, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x73;
-instruction[3] = 0xc0 | (7 << 3) | data2_ind;
-instruction[4] = diff;
-sljit_emit_op_custom(compiler, instruction, 5);
+if (reg_type == SLJIT_SIMD_REG_256)
+  {
+  if (diff != 16)
+    {
+    /* PSLLDQ ymm1, ymm2, imm8 */
+    instruction[0] = 0xc5;
+    instruction[1] = (sljit_u8)(0xf9 ^ (data2_ind << 3));
+    instruction[2] = 0x73;
+    instruction[3] = 0xc0 | (7 << 3) | data1_ind;
+    instruction[4] = diff & 0xf;
+    sljit_emit_op_custom(compiler, instruction, 5);
+    }
+
+  instruction[0] = 0xc4;
+  instruction[1] = 0xe3;
+  if (diff < 16)
+    {
+    /* VINSERTI128 xmm1, xmm2, xmm3/m128 */
+    /* instruction[0] = 0xc4; */
+    /* instruction[1] = 0xe3; */
+    instruction[2] = (sljit_u8)(0x7d ^ (data2_ind << 3));
+    instruction[3] = 0x38;
+    SLJIT_ASSERT(sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR) <= 7);
+    instruction[4] = 0x40 | (data2_ind << 3) | sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+    instruction[5] = (sljit_u8)(16 - diff);
+    instruction[6] = 1;
+    sljit_emit_op_custom(compiler, instruction, 7);
+    }
+  else
+    {
+    /* VPERM2I128 xmm1, xmm2, xmm3/m128 */
+    /* instruction[0] = 0xc4; */
+    /* instruction[1] = 0xe3; */
+    value = (diff == 16) ? data1_ind : data2_ind;
+    instruction[2] = (sljit_u8)(0x7d ^ (value << 3));
+    instruction[3] = 0x46;
+    instruction[4] = 0xc0 | (data2_ind << 3) | value;
+    instruction[5] = 0x08;
+    sljit_emit_op_custom(compiler, instruction, 6);
+    }
+  }
+else
+  {
+  /* MOVDQA xmm1, xmm2/m128 */
+  instruction[0] = 0x66;
+  instruction[1] = 0x0f;
+  instruction[2] = 0x6f;
+  instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+
+  /* PSLLDQ xmm1, imm8 */
+  /* instruction[0] = 0x66; */
+  /* instruction[1] = 0x0f; */
+  instruction[2] = 0x73;
+  instruction[3] = 0xc0 | (7 << 3) | data2_ind;
+  instruction[4] = diff;
+  sljit_emit_op_custom(compiler, instruction, 5);
+  }
 
 JUMPHERE(jump[1]);
 
-OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 0x1f : 0xf;
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, value);
 
 for (i = 0; i < 4; i++)
   {
-  fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
-  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, reg_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+  fast_forward_char_pair_sse2_compare(compiler, compare1_type, reg_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
   }
 
-/* PAND xmm1, xmm2/m128 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xdb;
-instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
-
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0;
-sljit_emit_op_custom(compiler, instruction, 4);
+sljit_emit_simd_op2(compiler, SLJIT_SIMD_OP2_AND | reg_type, SLJIT_FR0, SLJIT_FR0, SLJIT_FR1);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
 
 /* Ignore matches before the first STR_PTR. */
 OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
@@ -698,36 +682,28 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
 /* Main loop. */
 start = LABEL();
 
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 32 : 16;
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
 add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
 
-load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0);
-load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
+sljit_emit_simd_mov(compiler, reg_type, SLJIT_FR1, SLJIT_MEM1(STR_PTR), -(sljit_sw)diff);
 
 for (i = 0; i < 4; i++)
   {
-  fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
-  fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
+  fast_forward_char_pair_sse2_compare(compiler, compare1_type, reg_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
+  fast_forward_char_pair_sse2_compare(compiler, compare2_type, reg_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
   }
 
-/* PAND xmm1, xmm2/m128 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xdb;
-instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
-
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0;
-sljit_emit_op_custom(compiler, instruction, 4);
+sljit_emit_simd_op2(compiler, SLJIT_SIMD_OP2_AND | reg_type, SLJIT_FR0, SLJIT_FR0, SLJIT_FR1);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
 
 CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
 
 JUMPHERE(jump[0]);
 
+SLJIT_ASSERT(tmp1_reg_ind < 8);
 /* BSF r32, r/m32 */
 instruction[0] = 0x0f;
 instruction[1] = 0xbc;
@@ -762,7 +738,7 @@ if (common->match_end_ptr != 0)
 
 #endif /* !_WIN64 */
 
-#undef SSE2_COMPARE_TYPE_INDEX
+#undef SIMD_COMPARE_TYPE_INDEX
 
 #endif /* SLJIT_CONFIG_X86 */
 
@@ -865,14 +841,14 @@ static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, P
 {
 DEFINE_COMPILER;
 int_char ic;
-struct sljit_jump *partial_quit;
+struct sljit_jump *partial_quit, *quit;
 /* Save temporary registers. */
 OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0);
 OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP3, 0);
 
 /* Prepare function arguments */
 OP1(SLJIT_MOV, SLJIT_R0, 0, STR_END, 0);
-OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0);
+GET_LOCAL_BASE(SLJIT_R1, 0, LOCALS0);
 OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, offset);
 
 if (char1 == char2)
@@ -944,9 +920,14 @@ if (common->mode == PCRE2_JIT_COMPLETE)
 
 /* Fast forward STR_PTR to the result of memchr. */
 OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
-
 if (common->mode != PCRE2_JIT_COMPLETE)
+  {
+  quit = CMP(SLJIT_NOT_ZERO, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
   JUMPHERE(partial_quit);
+  OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
+  SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
+  JUMPHERE(quit);
+  }
 }
 
 typedef enum {
@@ -1068,10 +1049,10 @@ else
   OP2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
 
   OP2U(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, SLJIT_R0, 0);
-  CMOV(SLJIT_LESS, SLJIT_R0, STR_END, 0);
+  SELECT(SLJIT_LESS, SLJIT_R0, STR_END, 0, SLJIT_R0);
   }
 
-OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0); 
+GET_LOCAL_BASE(SLJIT_R1, 0, LOCALS0);
 OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_IMM, offs1);
 OP1(SLJIT_MOV_S32, SLJIT_R3, 0, SLJIT_IMM, offs2);
 ic.c.c1 = char1a;
@@ -1177,7 +1158,7 @@ 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[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | sljit_get_register_index(SLJIT_GP_REGISTER, tmp_general_reg));
   instruction[1] = 0;
   instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x22);
   sljit_emit_op_custom(compiler, instruction, 6);
@@ -1256,8 +1237,8 @@ struct sljit_label *restart;
 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 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
 sljit_s32 data_ind = 0;
 sljit_s32 tmp_ind = 1;
 sljit_s32 cmp1_ind = 2;
@@ -1419,7 +1400,7 @@ if (common->mode != PCRE2_JIT_COMPLETE)
   JUMPHERE(partial_quit[0]);
   JUMPHERE(partial_quit[1]);
   OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
-  CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+  SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
   }
 else
   add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
@@ -1454,8 +1435,8 @@ 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 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 tmp3_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP3);
 sljit_s32 data_ind = 0;
 sljit_s32 tmp_ind = 1;
 sljit_s32 cmp1_ind = 2;
@@ -1624,9 +1605,9 @@ 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 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 tmp2_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP2);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
 sljit_s32 data1_ind = 0;
 sljit_s32 data2_ind = 1;
 sljit_s32 tmp1_ind = 2;
@@ -1674,7 +1655,7 @@ if (common->match_end_ptr != 0)
   OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
 
   OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0);
-  CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+  SELECT(SLJIT_LESS, STR_END, TMP1, 0, STR_END);
   }
 
 OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
@@ -1855,4 +1836,520 @@ if (common->match_end_ptr != 0)
 
 #endif /* SLJIT_CONFIG_S390X */
 
+#if (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64)
+
+#ifdef __linux__
+/* Using getauxval(AT_HWCAP) under Linux for detecting whether LSX is available */
+#include <sys/auxv.h>
+#define LOONGARCH_HWCAP_LSX  (1 << 4)
+#define HAS_LSX_SUPPORT ((getauxval(AT_HWCAP) & LOONGARCH_HWCAP_LSX) != 0)
+#else
+#define HAS_LSX_SUPPORT 0
+#endif
+
+typedef sljit_ins sljit_u32;
+
+#define SI12_IMM_MASK   0x003ffc00
+#define UI5_IMM_MASK    0x00007c00
+#define UI2_IMM_MASK    0x00000c00
+
+#define VD(vd)      ((sljit_ins)vd << 0)
+#define VJ(vj)      ((sljit_ins)vj << 5)
+#define VK(vk)      ((sljit_ins)vk << 10)
+#define RD_V(rd)    ((sljit_ins)rd << 0)
+#define RJ_V(rj)    ((sljit_ins)rj << 5)
+
+#define IMM_SI12(imm)   (((sljit_ins)(imm) << 10) & SI12_IMM_MASK)
+#define IMM_UI5(imm)    (((sljit_ins)(imm) << 10) & UI5_IMM_MASK)
+#define IMM_UI2(imm)    (((sljit_ins)(imm) << 10) & UI2_IMM_MASK)
+
+// LSX OPCODES:
+#define VLD           0x2c000000
+#define VOR_V         0x71268000
+#define VAND_V        0x71260000
+#define VBSLL_V       0x728e0000
+#define VMSKLTZ_B     0x729c4000
+#define VPICKVE2GR_WU 0x72f3e000
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define VREPLGR2VR  0x729f0000
+#define VSEQ        0x70000000
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define VREPLGR2VR  0x729f0400
+#define VSEQ        0x70008000
+#else
+#define VREPLGR2VR  0x729f0800
+#define VSEQ        0x70010000
+#endif
+
+static void fast_forward_char_pair_lsx_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
+  sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
+{
+if (compare_type != vector_compare_match2)
+  {
+  if (compare_type == vector_compare_match1i)
+    {
+    /* VOR.V vd, vj, vk */
+    push_inst(compiler, VOR_V | VD(dst_ind) | VJ(cmp2_ind) | VK(dst_ind));
+    }
+
+  /* VSEQ.B/H/W vd, vj, vk */
+  push_inst(compiler, VSEQ | VD(dst_ind) | VJ(dst_ind) | VK(cmp1_ind));
+  return;
+  }
+
+/* VBSLL.V vd, vj, ui5 */
+push_inst(compiler, VBSLL_V | VD(tmp_ind) | VJ(dst_ind) | IMM_UI5(0));
+
+/* VSEQ.B/H/W vd, vj, vk */
+push_inst(compiler, VSEQ | VD(dst_ind) | VJ(dst_ind) | VK(cmp1_ind));
+
+/* VSEQ.B/H/W vd, vj, vk */
+push_inst(compiler, VSEQ | VD(tmp_ind) | VJ(tmp_ind) | VK(cmp2_ind));
+
+/* VOR vd, vj, vk */
+push_inst(compiler, VOR_V | VD(dst_ind) | VJ(tmp_ind) | VK(dst_ind));
+return;
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD HAS_LSX_SUPPORT
+
+static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+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(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+
+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) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1 | bit);
+
+/* VREPLGR2VR.B/H/W vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp1_ind) | RJ_V(tmp1_reg_ind));
+
+if (char1 != char2)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, bit != 0 ? bit : char2);
+
+  /* VREPLGR2VR.B/H/W vd, rj */
+  push_inst(compiler, VREPLGR2VR | VD(cmp2_ind) | RJ_V(tmp1_reg_ind));
+  }
+
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* 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]);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(quit);
+
+/* CTZ.W rd, rj */
+push_inst(compiler, CTZ_W | RD_V(tmp1_reg_ind) | RJ_V(tmp1_reg_ind));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+  {
+  JUMPHERE(partial_quit[0]);
+  JUMPHERE(partial_quit[1]);
+  OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
+  SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
+  }
+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));
+  OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+  JUMPTO(SLJIT_JUMP, restart);
+
+  JUMPHERE(quit);
+  }
+#endif
+}
+
+#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD HAS_LSX_SUPPORT
+
+static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
+{
+DEFINE_COMPILER;
+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(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+
+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));
+OP1(SLJIT_MOV, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1 | bit);
+
+/* VREPLGR2VR vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp1_ind) | RJ_V(tmp1_reg_ind));
+
+if (char1 != char2)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, bit != 0 ? bit : char2);
+  /* VREPLGR2VR vd, rj */
+  push_inst(compiler, VREPLGR2VR | VD(cmp2_ind) | RJ_V(tmp1_reg_ind));
+  }
+
+OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Second part (aligned) */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(quit);
+
+/* CTZ.W rd, rj */
+push_inst(compiler, CTZ_W | RD_V(tmp1_reg_ind) | RJ_V(tmp1_reg_ind));
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, STR_PTR, 0);
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+
+OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+return not_found;
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD HAS_LSX_SUPPORT
+
+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;
+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_u32 diff = IN_UCHARS(offs1 - offs2);
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 tmp2_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP2);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, 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;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *jump[2];
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
+SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset()));
+
+/* Initialize. */
+if (common->match_end_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
+  OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+
+  OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0);
+  SELECT(SLJIT_LESS, STR_END, TMP1, 0, STR_END);
+  }
+
+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));
+
+if (char1a == char1b)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1a);
+else
+  {
+  bit1 = char1a ^ char1b;
+  if (is_powerof2(bit1))
+    {
+    compare1_type = vector_compare_match1i;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1a | bit1);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, bit1);
+    }
+  else
+    {
+    compare1_type = vector_compare_match2;
+    bit1 = 0;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1a);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, char1b);
+    }
+  }
+
+/* VREPLGR2VR vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp1a_ind) | RJ_V(tmp1_reg_ind));
+
+if (char1a != char1b)
+  {
+  /* VREPLGR2VR vd, rj */
+  push_inst(compiler, VREPLGR2VR | VD(cmp1b_ind) | RJ_V(tmp2_reg_ind));
+  }
+
+if (char2a == char2b)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char2a);
+else
+  {
+  bit2 = char2a ^ char2b;
+  if (is_powerof2(bit2))
+    {
+    compare2_type = vector_compare_match1i;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char2a | bit2);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, bit2);
+    }
+  else
+    {
+    compare2_type = vector_compare_match2;
+    bit2 = 0;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char2a);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, char2b);
+    }
+  }
+
+/* VREPLGR2VR vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp2a_ind) | RJ_V(tmp1_reg_ind));
+
+if (char2a != char2b)
+  {
+  /* VREPLGR2VR vd, rj */
+  push_inst(compiler, VREPLGR2VR | VD(cmp2b_ind) | RJ_V(tmp2_reg_ind));
+  }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, diff);
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data1_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+
+jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_PTR, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data2_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(-(sljit_s8)diff));
+jump[1] = JUMP(SLJIT_JUMP);
+
+JUMPHERE(jump[0]);
+
+/* VBSLL.V vd, vj, ui5 */
+push_inst(compiler, VBSLL_V | VD(data2_ind) | VJ(data1_ind) | IMM_UI5(diff));
+
+JUMPHERE(jump[1]);
+
+fast_forward_char_pair_lsx_compare(compiler, compare2_type, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+fast_forward_char_pair_lsx_compare(compiler, compare1_type, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
+
+/* VAND vd, vj, vk */
+push_inst(compiler, VOR_V | VD(data1_ind) | VJ(data1_ind) | VK(data2_ind));
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp1_ind) | VJ(data1_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp1_ind) | IMM_UI2(0));
+
+/* Ignore matches before the first STR_PTR. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+jump[0] = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* 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));
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data1_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+push_inst(compiler, VLD | VD(data2_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(-(sljit_s8)diff));
+
+fast_forward_char_pair_lsx_compare(compiler, compare1_type, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
+fast_forward_char_pair_lsx_compare(compiler, compare2_type, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
+
+/* VAND.V vd, vj, vk */
+push_inst(compiler, VAND_V | VD(data1_ind) | VJ(data1_ind) | VK(data2_ind));
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp1_ind) | VJ(data1_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp1_ind) | IMM_UI2(0));
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(jump[0]);
+
+/* CTZ.W rd, rj */
+push_inst(compiler, CTZ_W | RD_V(tmp1_reg_ind) | RJ_V(tmp1_reg_ind));
+
+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));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf)
+  {
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1));
+
+  jump[0] = jump_if_utf_char_start(compiler, TMP1);
+
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, restart);
+
+  add_jump(compiler, &common->failed_match, JUMP(SLJIT_JUMP));
+
+  JUMPHERE(jump[0]);
+  }
+#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_LOONGARCH_64 */
+
 #endif /* !SUPPORT_VALGRIND */

+ 5 - 3
thirdparty/pcre2/src/pcre2_maketables.c

@@ -52,8 +52,6 @@ PCRE2_DFTABLES is defined. */
 #  include "pcre2_internal.h"
 #endif
 
-
-
 /*************************************************
 *           Create PCRE2 character tables        *
 *************************************************/
@@ -98,7 +96,11 @@ for (i = 0; i < 256; i++) *p++ = tolower(i);
 
 /* Next the case-flipping table */
 
-for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i);
+for (i = 0; i < 256; i++)
+  {
+  int c = islower(i)? toupper(i) : tolower(i);
+  *p++ = (c < 256)? c : i;
+  }
 
 /* Then the character class tables. Don't try to be clever and save effort on
 exclusive ones - in some locales things may be different.

+ 351 - 118
thirdparty/pcre2/src/pcre2_match.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2015-2022 University of Cambridge
+          New API code Copyright (c) 2015-2024 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,8 @@ POSSIBILITY OF SUCH DAMAGE.
 #include "config.h"
 #endif
 
+#include "pcre2_internal.h"
+
 /* These defines enable debugging code */
 
 /* #define DEBUG_FRAMES_DISPLAY */
@@ -53,6 +55,10 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <stdarg.h>
 #endif
 
+#ifdef DEBUG_SHOW_OPS
+static const char *OP_names[] = { OP_NAME_LIST };
+#endif
+
 /* These defines identify the name of the block containing "static"
 information, and fields within it. */
 
@@ -60,8 +66,6 @@ information, and fields within it. */
 #define PSSTART start_subject   /* Field containing processed string start */
 #define PSEND   end_subject     /* Field containing processed string end */
 
-#include "pcre2_internal.h"
-
 #define RECURSE_UNSET 0xffffffffu  /* Bigger than max group number */
 
 /* Masks for identifying the public options that are permitted at match time. */
@@ -69,7 +73,8 @@ information, and fields within it. */
 #define PUBLIC_MATCH_OPTIONS \
   (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
    PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
-   PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT|PCRE2_COPY_MATCHED_SUBJECT)
+   PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT|PCRE2_COPY_MATCHED_SUBJECT| \
+   PCRE2_DISABLE_RECURSELOOP_CHECK)
 
 #define PUBLIC_JIT_MATCH_OPTIONS \
    (PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\
@@ -150,7 +155,7 @@ changed, the code at RETURN_SWITCH below must be updated in sync.  */
 enum { RM1=1, RM2,  RM3,  RM4,  RM5,  RM6,  RM7,  RM8,  RM9,  RM10,
        RM11,  RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20,
        RM21,  RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30,
-       RM31,  RM32, RM33, RM34, RM35, RM36 };
+       RM31,  RM32, RM33, RM34, RM35, RM36, RM37 };
 
 #ifdef SUPPORT_WIDE_CHARS
 enum { RM100=100, RM101 };
@@ -597,11 +602,12 @@ heapframe *P = NULL;
 
 heapframe *frames_top;  /* End of frames vector */
 heapframe *assert_accept_frame = NULL;  /* For passing back a frame with captures */
-PCRE2_SIZE heapframes_size;   /* Usable size of frames vector */
 PCRE2_SIZE frame_copy_size;   /* Amount to copy when creating a new frame */
 
 /* Local variables that do not need to be preserved over calls to RRMATCH(). */
 
+PCRE2_SPTR branch_end = NULL;
+PCRE2_SPTR branch_start;
 PCRE2_SPTR bracode;     /* Temp pointer to start of group */
 PCRE2_SIZE offset;      /* Used for group offsets */
 PCRE2_SIZE length;      /* Used for various length calculations */
@@ -635,13 +641,10 @@ copied when a new frame is created. */
 
 frame_copy_size = frame_size - offsetof(heapframe, eptr);
 
-/* Set up the first frame and the end of the frames vector. We set the local
-heapframes_size to the usuable amount of the vector, that is, a whole number of
-frames. */
+/* Set up the first frame and the end of the frames vector. */
 
 F = match_data->heapframes;
-heapframes_size = (match_data->heapframes_size / frame_size) * frame_size;
-frames_top = (heapframe *)((char *)F + heapframes_size);
+frames_top = (heapframe *)((char *)F + match_data->heapframes_size);
 
 Frdepth = 0;                        /* "Recursion" depth */
 Fcapture_last = 0;                  /* Number of most recent capture */
@@ -662,35 +665,54 @@ MATCH_RECURSE:
 doubling the size, but constrained by the heap limit (which is in KiB). */
 
 N = (heapframe *)((char *)F + frame_size);
-if (N >= frames_top)
+if ((heapframe *)((char *)N + frame_size) >= frames_top)
   {
   heapframe *new;
-  PCRE2_SIZE newsize = match_data->heapframes_size * 2;
+  PCRE2_SIZE newsize;
+  PCRE2_SIZE usedsize = (char *)N - (char *)(match_data->heapframes);
 
-  if (newsize > mb->heap_limit)
+  if (match_data->heapframes_size >= PCRE2_SIZE_MAX / 2)
     {
-    PCRE2_SIZE maxsize = (mb->heap_limit/frame_size) * frame_size;
-    if (match_data->heapframes_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT;
-    newsize = maxsize;
+    if (match_data->heapframes_size == PCRE2_SIZE_MAX - 1)
+      return PCRE2_ERROR_NOMEMORY;
+    newsize = PCRE2_SIZE_MAX - 1;
     }
+  else
+    newsize = match_data->heapframes_size * 2;
 
+  if (newsize / 1024 >= mb->heap_limit)
+    {
+    PCRE2_SIZE old_size = match_data->heapframes_size / 1024;
+    if (mb->heap_limit <= old_size)
+      return PCRE2_ERROR_HEAPLIMIT;
+    else
+      {
+      PCRE2_SIZE max_delta = 1024 * (mb->heap_limit - old_size);
+      int over_bytes = match_data->heapframes_size % 1024;
+      if (over_bytes) max_delta -= (1024 - over_bytes);
+      newsize = match_data->heapframes_size + max_delta;
+      }
+    }
+
+  /* With a heap limit set, the permitted additional size may not be enough for
+  another frame, so do a final check. */
+
+  if (newsize - usedsize < frame_size) return PCRE2_ERROR_HEAPLIMIT;
   new = match_data->memctl.malloc(newsize, match_data->memctl.memory_data);
   if (new == NULL) return PCRE2_ERROR_NOMEMORY;
-  memcpy(new, match_data->heapframes, heapframes_size);
+  memcpy(new, match_data->heapframes, usedsize);
 
-  F = (heapframe *)((char *)new + ((char *)F - (char *)match_data->heapframes));
-  N = (heapframe *)((char *)F + frame_size);
+  N = (heapframe *)((char *)new + usedsize);
+  F = (heapframe *)((char *)N - frame_size);
 
   match_data->memctl.free(match_data->heapframes, match_data->memctl.memory_data);
   match_data->heapframes = new;
   match_data->heapframes_size = newsize;
-
-  heapframes_size = (newsize / frame_size) * frame_size;
-  frames_top = (heapframe *)((char *)new + heapframes_size);
+  frames_top = (heapframe *)((char *)new + newsize);
   }
 
 #ifdef DEBUG_SHOW_RMATCH
-fprintf(stderr, "++ RMATCH %2d frame=%d", Freturn_id, Frdepth + 1);
+fprintf(stderr, "++ RMATCH %d frame=%d", Freturn_id, Frdepth + 1);
 if (group_frame_type != 0)
   {
   fprintf(stderr, " type=%x ", group_frame_type);
@@ -760,10 +782,16 @@ opcodes. */
 if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT;
 if (Frdepth >= mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT;
 
+#ifdef DEBUG_SHOW_OPS
+fprintf(stderr, "\n++ New frame: type=0x%x subject offset %ld\n",
+  GF_IDMASK(Fgroup_frame_type), Feptr - mb->start_subject);
+#endif
+
 for (;;)
   {
 #ifdef DEBUG_SHOW_OPS
-fprintf(stderr, "++ op=%d\n", *Fecode);
+fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+  OP_names[*Fecode]);
 #endif
 
   Fop = (uint8_t)(*Fecode);  /* Cast needed for 16-bit and 32-bit modes */
@@ -811,15 +839,16 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     assert_accept_frame = F;
     RRETURN(MATCH_ACCEPT);
 
-    /* If recursing, we have to find the most recent recursion. */
+    /* For ACCEPT within a recursion, we have to find the most recent
+    recursion. If not in a recursion, fall through to code that is common with
+    OP_END. */
 
     case OP_ACCEPT:
-    case OP_END:
-
-    /* Handle end of a recursion. */
-
     if (Fcurrent_recurse != RECURSE_UNSET)
       {
+#ifdef DEBUG_SHOW_OPS
+      fprintf(stderr, "++ Accept within recursion\n");
+#endif
       offset = Flast_group_offset;
       for(;;)
         {
@@ -842,27 +871,49 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
       Fecode += 1 + LINK_SIZE;
       continue;
       }
+    /* Fall through */
+
+    /* OP_END itself can never be reached within a recursion because that is
+    picked up when the OP_KET that always precedes OP_END is reached. */
+
+    case OP_END:
 
-    /* Not a recursion. Fail for an empty string match if either PCRE2_NOTEMPTY
-    is set, or if PCRE2_NOTEMPTY_ATSTART is set and we have matched at the
-    start of the subject. In both cases, backtracking will then try other
-    alternatives, if any. */
+    /* Fail for an empty string match if either PCRE2_NOTEMPTY is set, or if
+    PCRE2_NOTEMPTY_ATSTART is set and we have matched at the start of the
+    subject. In both cases, backtracking will then try other alternatives, if
+    any. */
 
     if (Feptr == Fstart_match &&
          ((mb->moptions & PCRE2_NOTEMPTY) != 0 ||
            ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 &&
              Fstart_match == mb->start_subject + mb->start_offset)))
+      {
+#ifdef DEBUG_SHOW_OPS
+      fprintf(stderr, "++ Backtrack because empty string\n");
+#endif
       RRETURN(MATCH_NOMATCH);
+      }
 
-    /* Also fail if PCRE2_ENDANCHORED is set and the end of the match is not
+    /* Fail if PCRE2_ENDANCHORED is set and the end of the match is not
     the end of the subject. After (*ACCEPT) we fail the entire match (at this
-    position) but backtrack on reaching the end of the pattern. */
+    position) but backtrack if we've reached the end of the pattern. This
+    applies whether or not we are in a recursion. */
 
     if (Feptr < mb->end_subject &&
         ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0)
       {
-      if (Fop == OP_END) RRETURN(MATCH_NOMATCH);
-      return MATCH_NOMATCH;
+      if (Fop == OP_END)
+        {
+#ifdef DEBUG_SHOW_OPS
+        fprintf(stderr, "++ Backtrack because not at end (endanchored set)\n");
+#endif
+        RRETURN(MATCH_NOMATCH);
+        }
+
+#ifdef DEBUG_SHOW_OPS
+      fprintf(stderr, "++ Failed ACCEPT not at end (endanchnored set)\n");
+#endif
+      return MATCH_NOMATCH;   /* (*ACCEPT) */
       }
 
     /* We have a successful match of the whole pattern. Record the result and
@@ -2435,6 +2486,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     GETCHARINCTEST(fc, Feptr);
       {
       const uint32_t *cp;
+      uint32_t chartype;
       const ucd_record *prop = GET_UCD(fc);
       BOOL notmatch = Fop == OP_NOTPROP;
 
@@ -2445,9 +2497,10 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
         break;
 
         case PT_LAMP:
-        if ((prop->chartype == ucp_Lu ||
-             prop->chartype == ucp_Ll ||
-             prop->chartype == ucp_Lt) == notmatch)
+        chartype = prop->chartype;
+        if ((chartype == ucp_Lu ||
+             chartype == ucp_Ll ||
+             chartype == ucp_Lt) == notmatch)
           RRETURN(MATCH_NOMATCH);
         break;
 
@@ -2477,8 +2530,9 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
         /* These are specials */
 
         case PT_ALNUM:
-        if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-             PRIV(ucp_gentype)[prop->chartype] == ucp_N) == notmatch)
+        chartype = prop->chartype;
+        if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+             PRIV(ucp_gentype)[chartype] == ucp_N) == notmatch)
           RRETURN(MATCH_NOMATCH);
         break;
 
@@ -2503,13 +2557,22 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
         break;
 
         case PT_WORD:
-        if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-             PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
-             fc == CHAR_UNDERSCORE) == notmatch)
+        chartype = prop->chartype;
+        if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+             PRIV(ucp_gentype)[chartype] == ucp_N ||
+             chartype == ucp_Mn ||
+             chartype == ucp_Pc) == notmatch)
           RRETURN(MATCH_NOMATCH);
         break;
 
         case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+            if (fc > MAX_UTF_CODE_POINT)
+              {
+              if (notmatch) break;;
+              RRETURN(MATCH_NOMATCH);
+              }
+#endif
         cp = PRIV(ucd_caseless_sets) + Fecode[2];
         for (;;)
           {
@@ -2805,16 +2868,17 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
           case PT_WORD:
           for (i = 1; i <= Lmin; i++)
             {
-            int category;
+            int chartype, category;
             if (Feptr >= mb->end_subject)
               {
               SCHECK_PARTIAL();
               RRETURN(MATCH_NOMATCH);
               }
             GETCHARINCTEST(fc, Feptr);
-            category = UCD_CATEGORY(fc);
+            chartype = UCD_CHARTYPE(fc);
+            category = PRIV(ucp_gentype)[chartype];
             if ((category == ucp_L || category == ucp_N ||
-                fc == CHAR_UNDERSCORE) == notmatch)
+                 chartype == ucp_Mn || chartype == ucp_Pc) == notmatch)
               RRETURN(MATCH_NOMATCH);
             }
           break;
@@ -2829,6 +2893,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
               RRETURN(MATCH_NOMATCH);
               }
             GETCHARINCTEST(fc, Feptr);
+#if PCRE2_CODE_UNIT_WIDTH == 32
+            if (fc > MAX_UTF_CODE_POINT)
+              {
+              if (notmatch) continue;
+              RRETURN(MATCH_NOMATCH);
+              }
+#endif
             cp = PRIV(ucd_caseless_sets) + Lpropvalue;
             for (;;)
               {
@@ -3609,7 +3680,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
           case PT_WORD:
           for (;;)
             {
-            int category;
+            int chartype, category;
             RMATCH(Fecode, RM215);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
@@ -3619,10 +3690,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
               RRETURN(MATCH_NOMATCH);
               }
             GETCHARINCTEST(fc, Feptr);
-            category = UCD_CATEGORY(fc);
+            chartype = UCD_CHARTYPE(fc);
+            category = PRIV(ucp_gentype)[chartype];
             if ((category == ucp_L ||
                  category == ucp_N ||
-                 fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+                 chartype == ucp_Mn ||
+                 chartype == ucp_Pc) == (Lctype == OP_NOTPROP))
               RRETURN(MATCH_NOMATCH);
             }
           /* Control never gets here */
@@ -3640,6 +3713,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
               RRETURN(MATCH_NOMATCH);
               }
             GETCHARINCTEST(fc, Feptr);
+#if PCRE2_CODE_UNIT_WIDTH == 32
+            if (fc > MAX_UTF_CODE_POINT)
+              {
+              if (Lctype == OP_NOTPROP) continue;
+              RRETURN(MATCH_NOMATCH);
+              }
+#endif
             cp = PRIV(ucd_caseless_sets) + Lpropvalue;
             for (;;)
               {
@@ -4190,7 +4270,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
           case PT_WORD:
           for (i = Lmin; i < Lmax; i++)
             {
-            int category;
+            int chartype, category;
             int len = 1;
             if (Feptr >= mb->end_subject)
               {
@@ -4198,9 +4278,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
               break;
               }
             GETCHARLENTEST(fc, Feptr, len);
-            category = UCD_CATEGORY(fc);
-            if ((category == ucp_L || category == ucp_N ||
-                 fc == CHAR_UNDERSCORE) == notmatch)
+            chartype = UCD_CHARTYPE(fc);
+            category = PRIV(ucp_gentype)[chartype];
+            if ((category == ucp_L ||
+                 category == ucp_N ||
+                 chartype == ucp_Mn ||
+                 chartype == ucp_Pc) == notmatch)
               break;
             Feptr+= len;
             }
@@ -4217,14 +4300,24 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
               break;
               }
             GETCHARLENTEST(fc, Feptr, len);
-            cp = PRIV(ucd_caseless_sets) + Lpropvalue;
-            for (;;)
+#if PCRE2_CODE_UNIT_WIDTH == 32
+            if (fc > MAX_UTF_CODE_POINT)
               {
-              if (fc < *cp)
-                { if (notmatch) break; else goto GOT_MAX; }
-              if (fc == *cp++)
-                { if (notmatch) goto GOT_MAX; else break; }
+              if (!notmatch) goto GOT_MAX;
+              }
+            else
+#endif
+              {
+              cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+              for (;;)
+                {
+                if (fc < *cp)
+                  { if (notmatch) break; else goto GOT_MAX; }
+                if (fc == *cp++)
+                  { if (notmatch) goto GOT_MAX; else break; }
+                }
               }
+
             Feptr += len;
             }
           GOT_MAX:
@@ -5322,9 +5415,11 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
 
 
     /* ===================================================================== */
-    /* Recursion either matches the current regex, or some subexpression. The
-    offset data is the offset to the starting bracket from the start of the
-    whole pattern. (This is so that it works from duplicated subpatterns.) */
+    /* Pattern recursion either matches the current regex, or some
+    subexpression. The offset data is the offset to the starting bracket from
+    the start of the whole pattern. This is so that it works from duplicated
+    subpatterns. For a whole-pattern recursion, we have to infer the number
+    zero. */
 
 #define Lframe_type F->temp_32[0]
 #define Lstart_branch F->temp_sptr[0]
@@ -5333,9 +5428,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     bracode = mb->start_code + GET(Fecode, 1);
     number = (bracode == mb->start_code)? 0 : GET2(bracode, 1 + LINK_SIZE);
 
-    /* If we are already in a recursion, check for repeating the same one
-    without advancing the subject pointer. This should catch convoluted mutual
-    recursions. (Some simple cases are caught at compile time.) */
+    /* If we are already in a pattern recursion, check for repeating the same
+    one without changing the subject pointer or the last referenced character
+    in the subject. This should catch convoluted mutual recursions; some
+    simple cases are caught at compile time. However, there are rare cases when
+    this check needs to be turned off. In this case, actual recursion loops
+    will be caught by the match or heap limits. */
 
     if (Fcurrent_recurse != RECURSE_UNSET)
       {
@@ -5346,15 +5444,19 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
         P = (heapframe *)((char *)N - frame_size);
         if (N->group_frame_type == (GF_RECURSE | number))
           {
-          if (Feptr == P->eptr) return PCRE2_ERROR_RECURSELOOP;
+          if (Feptr == P->eptr && mb->last_used_ptr == P->recurse_last_used &&
+               (mb->moptions & PCRE2_DISABLE_RECURSELOOP_CHECK) == 0)
+            return PCRE2_ERROR_RECURSELOOP;
           break;
           }
         offset = P->last_group_offset;
         }
       }
 
-    /* Now run the recursion, branch by branch. */
+    /* Remember the current last referenced character and then run the
+    recursion branch by branch. */
 
+    F->recurse_last_used = mb->last_used_ptr;
     Lstart_branch = bracode;
     Lframe_type = GF_RECURSE | number;
 
@@ -5683,13 +5785,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
 
 
     /* ===================================================================== */
-    /* Move the subject pointer back. This occurs only at the start of each
-    branch of a lookbehind assertion. If we are too close to the start to move
-    back, fail. When working with UTF-8 we move back a number of characters,
-    not bytes. */
+    /* Move the subject pointer back by one fixed amount. This occurs at the
+    start of each branch that has a fixed length in a lookbehind assertion. If
+    we are too close to the start to move back, fail. When working with UTF-8
+    we move back a number of characters, not bytes. */
 
     case OP_REVERSE:
-    number = GET(Fecode, 1);
+    number = GET2(Fecode, 1);
 #ifdef SUPPORT_UNICODE
     if (utf)
       {
@@ -5703,7 +5805,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     else
 #endif
 
-    /* No UTF-8 support, or not in UTF-8 mode: count is code unit count */
+    /* No UTF support, or not in UTF mode: count is code unit count */
 
       {
       if ((ptrdiff_t)number > Feptr - mb->start_subject) RRETURN(MATCH_NOMATCH);
@@ -5713,15 +5815,84 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     /* Save the earliest consulted character, then skip to next opcode */
 
     if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr;
-    Fecode += 1 + LINK_SIZE;
+    Fecode += 1 + IMM2_SIZE;
     break;
 
 
+    /* ===================================================================== */
+    /* Move the subject pointer back by a variable amount. This occurs at the
+    start of each branch of a lookbehind assertion when the branch has a
+    variable, but limited, length. A loop is needed to try matching the branch
+    after moving back different numbers of characters. If we are too close to
+    the start to move back even the minimum amount, fail. When working with
+    UTF-8 we move back a number of characters, not bytes. */
+
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Leptr F->temp_sptr[0]
+
+    case OP_VREVERSE:
+    Lmin = GET2(Fecode, 1);
+    Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+    Leptr = Feptr;
+
+    /* Move back by the maximum branch length and then work forwards. This
+    ensures that items such as \d{3,5} get the maximum length, which is
+    relevant for captures, and makes for Perl compatibility. */
+
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      for (i = 0; i < Lmax; i++)
+        {
+        if (Feptr == mb->start_subject)
+          {
+          if (i < Lmin) RRETURN(MATCH_NOMATCH);
+          Lmax = i;
+          break;
+          }
+        Feptr--;
+        BACKCHAR(Feptr);
+        }
+      }
+    else
+#endif
+
+    /* No UTF support or not in UTF mode */
+
+      {
+      ptrdiff_t diff = Feptr - mb->start_subject;
+      uint32_t available = (diff > 65535)? 65535 : ((diff > 0)? diff : 0);
+      if (Lmin > available) RRETURN(MATCH_NOMATCH);
+      if (Lmax > available) Lmax = available;
+      Feptr -= Lmax;
+      }
+
+    /* Now try matching, moving forward one character on failure, until we
+    reach the mimimum back length. */
+
+    for (;;)
+      {
+      RMATCH(Fecode + 1 + 2 * IMM2_SIZE, RM37);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      if (Lmax-- <= Lmin) RRETURN(MATCH_NOMATCH);
+      Feptr++;
+#ifdef SUPPORT_UNICODE
+      if (utf) { FORWARDCHARTEST(Feptr, mb->end_subject); }
+#endif
+      }
+    /* Control never reaches here */
+
+#undef Lmin
+#undef Lmax
+#undef Leptr
+
     /* ===================================================================== */
     /* An alternation is the end of a branch; scan along to find the end of the
     bracketed group. */
 
     case OP_ALT:
+    branch_end = Fecode;
     do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT);
     break;
 
@@ -5729,7 +5900,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     /* ===================================================================== */
     /* The end of a parenthesized group. For all but OP_BRA and OP_COND, the
     starting frame was added to the chained frames in order to remember the
-    starting subject position for the group. */
+    starting subject position for the group. (Not true for OP_BRA when it's a
+    whole pattern recursion, but that is handled separately below.)*/
 
     case OP_KET:
     case OP_KETRMIN:
@@ -5738,8 +5910,14 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
 
     bracode = Fecode - GET(Fecode, 1);
 
-    /* Point N to the frame at the start of the most recent group.
-    Remember the subject pointer at the start of the group. */
+    if (branch_end == NULL) branch_end = Fecode;
+    branch_start = bracode;
+    while (branch_start + GET(branch_start, 1) != branch_end)
+      branch_start += GET(branch_start, 1);
+    branch_end = NULL;
+
+    /* Point N to the frame at the start of the most recent group, and P to its
+    predecessor. Remember the subject pointer at the start of the group. */
 
     if (*bracode != OP_BRA && *bracode != OP_COND)
       {
@@ -5775,27 +5953,64 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
 
     switch (*bracode)
       {
-      case OP_BRA:    /* No need to do anything for these */
-      case OP_COND:
+      /* Whole pattern recursion is handled as a recursion into group 0, but
+      the entire pattern is wrapped in OP_BRA/OP_KET rather than a capturing
+      group - a design mistake: it should perhaps have been capture group 0.
+      Anyway, that means the end of such recursion must be handled here. It is
+      detected by checking for an immediately following OP_END when we are
+      recursing in group 0. If this is not the end of a whole-pattern
+      recursion, there is nothing to be done. */
+
+      case OP_BRA:
+      if (Fcurrent_recurse != 0 || Fecode[1+LINK_SIZE] != OP_END) break;
+
+      /* It is the end of whole-pattern recursion. */
+
+      offset = Flast_group_offset;
+      if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL;
+      N = (heapframe *)((char *)match_data->heapframes + offset);
+      P = (heapframe *)((char *)N - frame_size);
+      Flast_group_offset = P->last_group_offset;
+
+      /* Reinstate the previous set of captures and then carry on after the
+      recursion call. */
+
+      memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
+        Foffset_top * sizeof(PCRE2_SIZE));
+      Foffset_top = P->offset_top;
+      Fcapture_last = P->capture_last;
+      Fcurrent_recurse = P->current_recurse;
+      Fecode = P->ecode + 1 + LINK_SIZE;
+      continue;  /* With next opcode */
+
+      case OP_COND:     /* No need to do anything for these */
       case OP_SCOND:
       break;
 
       /* Non-atomic positive assertions are like OP_BRA, except that the
       subject pointer must be put back to where it was at the start of the
-      assertion. */
+      assertion. For a variable lookbehind, check its end point. */
 
-      case OP_ASSERT_NA:
       case OP_ASSERTBACK_NA:
+      if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
+        RRETURN(MATCH_NOMATCH);
+      /* Fall through */
+
+      case OP_ASSERT_NA:
       if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
       Feptr = P->eptr;
       break;
 
       /* Atomic positive assertions are like OP_ONCE, except that in addition
       the subject pointer must be put back to where it was at the start of the
-      assertion. */
+      assertion. For a variable lookbehind, check its end point. */
 
-      case OP_ASSERT:
       case OP_ASSERTBACK:
+      if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
+        RRETURN(MATCH_NOMATCH);
+      /* Fall through */
+
+      case OP_ASSERT:
       if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
       Feptr = P->eptr;
       /* Fall through */
@@ -5816,10 +6031,15 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
       break;
 
       /* A matching negative assertion returns MATCH, which is turned into
-      NOMATCH at the assertion level. */
+      NOMATCH at the assertion level. For a variable lookbehind, check its end
+      point. */
 
-      case OP_ASSERT_NOT:
       case OP_ASSERTBACK_NOT:
+      if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
+        RRETURN(MATCH_NOMATCH);
+      /* Fall through */
+
+      case OP_ASSERT_NOT:
       RRETURN(MATCH_MATCH);
 
       /* At the end of a script run, apply the script-checking rules. This code
@@ -5830,9 +6050,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
       if (!PRIV(script_run)(P->eptr, Feptr, utf)) RRETURN(MATCH_NOMATCH);
       break;
 
-      /* Whole-pattern recursion is coded as a recurse into group 0, so it
-      won't be picked up here. Instead, we catch it when the OP_END is reached.
-      Other recursion is handled here. */
+      /* Whole-pattern recursion is coded as a recurse into group 0, and is
+      handled with OP_BRA above. Other recursion is handled here. */
 
       case OP_CBRA:
       case OP_CBRAPOS:
@@ -5847,7 +6066,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
         {
         P = (heapframe *)((char *)N - frame_size);
         memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
-          P->offset_top * sizeof(PCRE2_SIZE));
+          Foffset_top * sizeof(PCRE2_SIZE));
         Foffset_top = P->offset_top;
         Fcapture_last = P->capture_last;
         Fcurrent_recurse = P->current_recurse;
@@ -5930,10 +6149,10 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
     if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS;
 
     /* Fall through */
-    /* Unconditional end of subject assertion (\z) */
+    /* Unconditional end of subject assertion (\z). */
 
     case OP_EOD:
-    if (Feptr < mb->end_subject) RRETURN(MATCH_NOMATCH);
+    if (Feptr < mb->true_end_subject) RRETURN(MATCH_NOMATCH);
     if (mb->partial != 0)
       {
       mb->hitend = TRUE;
@@ -6045,6 +6264,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
 
     case OP_NOT_WORD_BOUNDARY:
     case OP_WORD_BOUNDARY:
+    case OP_NOT_UCP_WORD_BOUNDARY:
+    case OP_UCP_WORD_BOUNDARY:
     if (Feptr == mb->check_subject) prev_is_word = FALSE; else
       {
       PCRE2_SPTR lastptr = Feptr - 1;
@@ -6059,13 +6280,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
       fc = *lastptr;
       if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr;
 #ifdef SUPPORT_UNICODE
-      if ((mb->poptions & PCRE2_UCP) != 0)
+      if (Fop == OP_UCP_WORD_BOUNDARY || Fop == OP_NOT_UCP_WORD_BOUNDARY)
         {
-        if (fc == '_') prev_is_word = TRUE; else
-          {
-          int cat = UCD_CATEGORY(fc);
-          prev_is_word = (cat == ucp_L || cat == ucp_N);
-          }
+        int chartype = UCD_CHARTYPE(fc);
+        int category = PRIV(ucp_gentype)[chartype];
+        prev_is_word = (category == ucp_L || category == ucp_N ||
+          chartype == ucp_Mn || chartype == ucp_Pc);
         }
       else
 #endif  /* SUPPORT_UNICODE */
@@ -6093,13 +6313,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
       fc = *Feptr;
       if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr;
 #ifdef SUPPORT_UNICODE
-      if ((mb->poptions & PCRE2_UCP) != 0)
+      if (Fop == OP_UCP_WORD_BOUNDARY || Fop == OP_NOT_UCP_WORD_BOUNDARY)
         {
-        if (fc == '_') cur_is_word = TRUE; else
-          {
-          int cat = UCD_CATEGORY(fc);
-          cur_is_word = (cat == ucp_L || cat == ucp_N);
-          }
+        int chartype = UCD_CHARTYPE(fc);
+        int category = PRIV(ucp_gentype)[chartype];
+        cur_is_word = (category == ucp_L || category == ucp_N ||
+          chartype == ucp_Mn || chartype == ucp_Pc);
         }
       else
 #endif  /* SUPPORT_UNICODE */
@@ -6108,7 +6327,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
 
     /* Now see if the situation is what we want */
 
-    if ((*Fecode++ == OP_WORD_BOUNDARY)?
+    if ((*Fecode++ == OP_WORD_BOUNDARY || Fop == OP_UCP_WORD_BOUNDARY)?
          cur_is_word == prev_is_word : cur_is_word != prev_is_word)
       RRETURN(MATCH_NOMATCH);
     break;
@@ -6254,7 +6473,7 @@ F = (heapframe *)((char *)F - Fback_frame);       /* Backtrack */
 mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */
 
 #ifdef DEBUG_SHOW_RMATCH
-fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id);
+fprintf(stderr, "++ RETURN %d to RM%d\n", rrc, Freturn_id);
 #endif
 
 switch (Freturn_id)
@@ -6263,7 +6482,7 @@ switch (Freturn_id)
   LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16)
   LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24)
   LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32)
-  LBL(33) LBL(34) LBL(35) LBL(36)
+  LBL(33) LBL(34) LBL(35) LBL(36) LBL(37)
 
 #ifdef SUPPORT_WIDE_CHARS
   LBL(100) LBL(101)
@@ -6551,6 +6770,7 @@ if (use_jit)
     match_data, mcontext);
   if (rc != PCRE2_ERROR_JIT_BADOPTION)
     {
+    match_data->subject_length = length;
     if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
       {
       length = CU2BYTES(length + was_zero_terminated);
@@ -6719,7 +6939,7 @@ if (mcontext == NULL)
 else mb->memctl = mcontext->memctl;
 
 anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0;
-firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+firstline = !anchored && (re->overall_options & PCRE2_FIRSTLINE) != 0;
 startline = (re->flags & PCRE2_STARTLINE) != 0;
 bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)?
   true_end_subject : subject + mcontext->offset_limit;
@@ -6742,6 +6962,7 @@ mb->callout_data = mcontext->callout_data;
 mb->start_subject = subject;
 mb->start_offset = start_offset;
 mb->end_subject = end_subject;
+mb->true_end_subject = true_end_subject;
 mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0;
 mb->allowemptypartial = (re->max_lookbehind > 0) ||
     (re->flags & PCRE2_MATCH_EMPTY) != 0;
@@ -6801,7 +7022,7 @@ the pattern. It is not used at all if there are no capturing parentheses.
 
   frame_size                   is the total size of each frame
   match_data->heapframes       is the pointer to the frames vector
-  match_data->heapframes_size  is the total size of the vector
+  match_data->heapframes_size  is the allocated size of the vector
 
 We must pad the frame_size for alignment to ensure subsequent frames are as
 aligned as heapframe. Whilst ovector is word-aligned due to being a PCRE2_SIZE
@@ -6816,7 +7037,7 @@ frame_size = (offsetof(heapframe, ovector) +
 smaller. */
 
 mb->heap_limit = ((mcontext->heap_limit < re->limit_heap)?
-  mcontext->heap_limit : re->limit_heap) * 1024;
+  mcontext->heap_limit : re->limit_heap);
 
 mb->match_limit = (mcontext->match_limit < re->limit_match)?
   mcontext->match_limit : re->limit_match;
@@ -6827,19 +7048,19 @@ mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)?
 /* If a pattern has very many capturing parentheses, the frame size may be very
 large. Set the initial frame vector size to ensure that there are at least 10
 available frames, but enforce a minimum of START_FRAMES_SIZE. If this is
-greater than the heap limit, get as large a vector as possible. Always round
-the size to a multiple of the frame size. */
+greater than the heap limit, get as large a vector as possible. */
 
 heapframes_size = frame_size * 10;
 if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE;
-if (heapframes_size > mb->heap_limit)
+if (heapframes_size / 1024 > mb->heap_limit)
   {
-  if (frame_size > mb->heap_limit ) return PCRE2_ERROR_HEAPLIMIT;
-  heapframes_size = mb->heap_limit;
+  PCRE2_SIZE max_size = 1024 * mb->heap_limit;
+  if (max_size < frame_size) return PCRE2_ERROR_HEAPLIMIT;
+  heapframes_size = max_size;
   }
 
 /* If an existing frame vector in the match_data block is large enough, we can
-use it.Otherwise, free any pre-existing vector and get a new one. */
+use it. Otherwise, free any pre-existing vector and get a new one. */
 
 if (match_data->heapframes_size < heapframes_size)
   {
@@ -7286,9 +7507,17 @@ for(;;)
   mb->end_offset_top = 0;
   mb->skip_arg_count = 0;
 
+#ifdef DEBUG_SHOW_OPS
+  fprintf(stderr, "++ Calling match()\n");
+#endif
+
   rc = match(start_match, mb->start_code, re->top_bracket, frame_size,
     match_data, mb);
 
+#ifdef DEBUG_SHOW_OPS
+  fprintf(stderr, "++ match() returned %d\n\n", rc);
+#endif
+
   if (mb->hitend && start_partial == NULL)
     {
     start_partial = mb->start_used_ptr;
@@ -7436,6 +7665,7 @@ if (utf && end_subject != true_end_subject &&
     if (start_match >= true_end_subject)
       {
       rc = MATCH_NOMATCH;  /* In case it was partial */
+      match_partial = NULL;
       break;
       }
 
@@ -7485,6 +7715,7 @@ if (rc == MATCH_MATCH)
   {
   match_data->rc = ((int)mb->end_offset_top >= 2 * match_data->oveccount)?
     0 : (int)mb->end_offset_top/2 + 1;
+  match_data->subject_length = length;
   match_data->startchar = start_match - subject;
   match_data->leftchar = mb->start_used_ptr - subject;
   match_data->rightchar = ((mb->last_used_ptr > mb->end_match_ptr)?
@@ -7499,6 +7730,7 @@ if (rc == MATCH_MATCH)
     match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
     }
   else match_data->subject = subject;
+
   return match_data->rc;
   }
 
@@ -7520,6 +7752,7 @@ PCRE2_ERROR_PARTIAL. */
 else if (match_partial != NULL)
   {
   match_data->subject = subject;
+  match_data->subject_length = length;
   match_data->ovector[0] = match_partial - subject;
   match_data->ovector[1] = end_subject - subject;
   match_data->startchar = match_partial - subject;

+ 12 - 0
thirdparty/pcre2/src/pcre2_match_data.c

@@ -170,4 +170,16 @@ return offsetof(pcre2_match_data, ovector) +
   2 * (match_data->oveccount) * sizeof(PCRE2_SIZE);
 }
 
+
+
+/*************************************************
+*             Get heapframes size                *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION
+pcre2_get_match_data_heapframes_size(pcre2_match_data *match_data)
+{
+return match_data->heapframes_size;
+}
+
 /* End of pcre2_match_data.c */

+ 97 - 7
thirdparty/pcre2/src/pcre2_study.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2021 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -256,6 +256,7 @@ for (;;)
     /* Skip over things that don't match chars */
 
     case OP_REVERSE:
+    case OP_VREVERSE:
     case OP_CREF:
     case OP_DNCREF:
     case OP_RREF:
@@ -273,6 +274,8 @@ for (;;)
     case OP_DOLLM:
     case OP_NOT_WORD_BOUNDARY:
     case OP_WORD_BOUNDARY:
+    case OP_NOT_UCP_WORD_BOUNDARY:
+    case OP_UCP_WORD_BOUNDARY:
     cc += PRIV(OP_lengths)[*cc];
     break;
 
@@ -976,6 +979,7 @@ do
   while (try_next)    /* Loop for items in this branch */
     {
     int rc;
+    PCRE2_SPTR ncode;
     uint8_t *classmap = NULL;
 #ifdef SUPPORT_WIDE_CHARS
     PCRE2_UCHAR xclassflags;
@@ -1054,6 +1058,7 @@ do
       case OP_REF:
       case OP_REFI:
       case OP_REVERSE:
+      case OP_VREVERSE:
       case OP_RREF:
       case OP_SCOND:
       case OP_SET_SOM:
@@ -1101,13 +1106,100 @@ do
 
       case OP_WORD_BOUNDARY:
       case OP_NOT_WORD_BOUNDARY:
+      case OP_UCP_WORD_BOUNDARY:
+      case OP_NOT_UCP_WORD_BOUNDARY:
       tcode++;
       break;
 
-      /* If we hit a bracket or a positive lookahead assertion, recurse to set
-      bits from within the subpattern. If it can't find anything, we have to
-      give up. If it finds some mandatory character(s), we are done for this
-      branch. Otherwise, carry on scanning after the subpattern. */
+      /* For a positive lookahead assertion, inspect what immediately follows,
+      ignoring intermediate assertions and callouts. If the next item is one
+      that sets a mandatory character, skip this assertion. Otherwise, treat it
+      the same as other bracket groups. */
+
+      case OP_ASSERT:
+      case OP_ASSERT_NA:
+      ncode = tcode + GET(tcode, 1);
+      while (*ncode == OP_ALT) ncode += GET(ncode, 1);
+      ncode += 1 + LINK_SIZE;
+
+      /* Skip irrelevant items */
+
+      for (BOOL done = FALSE; !done;)
+        {
+        switch (*ncode)
+          {
+          case OP_ASSERT:
+          case OP_ASSERT_NOT:
+          case OP_ASSERTBACK:
+          case OP_ASSERTBACK_NOT:
+          case OP_ASSERT_NA:
+          case OP_ASSERTBACK_NA:
+          ncode += GET(ncode, 1);
+          while (*ncode == OP_ALT) ncode += GET(ncode, 1);
+          ncode += 1 + LINK_SIZE;
+          break;
+
+          case OP_WORD_BOUNDARY:
+          case OP_NOT_WORD_BOUNDARY:
+          case OP_UCP_WORD_BOUNDARY:
+          case OP_NOT_UCP_WORD_BOUNDARY:
+          ncode++;
+          break;
+
+          case OP_CALLOUT:
+          ncode += PRIV(OP_lengths)[OP_CALLOUT];
+          break;
+
+          case OP_CALLOUT_STR:
+          ncode += GET(ncode, 1 + 2*LINK_SIZE);
+          break;
+
+          default:
+          done = TRUE;
+          break;
+          }
+        }
+
+      /* Now check the next significant item. */
+
+      switch(*ncode)
+        {
+        default:
+        break;
+
+        case OP_PROP:
+        if (ncode[1] != PT_CLIST) break;
+        /* Fall through */
+        case OP_ANYNL:
+        case OP_CHAR:
+        case OP_CHARI:
+        case OP_EXACT:
+        case OP_EXACTI:
+        case OP_HSPACE:
+        case OP_MINPLUS:
+        case OP_MINPLUSI:
+        case OP_PLUS:
+        case OP_PLUSI:
+        case OP_POSPLUS:
+        case OP_POSPLUSI:
+        case OP_VSPACE:
+        /* Note that these types will only be present in non-UCP mode. */
+        case OP_DIGIT:
+        case OP_NOT_DIGIT:
+        case OP_WORDCHAR:
+        case OP_NOT_WORDCHAR:
+        case OP_WHITESPACE:
+        case OP_NOT_WHITESPACE:
+        tcode = ncode;
+        continue;   /* With the following significant opcode */
+        }
+      /* Fall through */
+
+      /* For a group bracket or a positive assertion without an immediately
+      following mandatory setting, recurse to set bits from within the
+      subpattern. If it can't find anything, we have to give up. If it finds
+      some mandatory character(s), we are done for this branch. Otherwise,
+      carry on scanning after the subpattern. */
 
       case OP_BRA:
       case OP_SBRA:
@@ -1119,8 +1211,6 @@ do
       case OP_SCBRAPOS:
       case OP_ONCE:
       case OP_SCRIPT_RUN:
-      case OP_ASSERT:
-      case OP_ASSERT_NA:
       rc = set_start_bits(re, tcode, utf, ucp, depthptr);
       if (rc == SSB_DONE)
         {

+ 5 - 2
thirdparty/pcre2/src/pcre2_substring.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2018 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -309,6 +309,7 @@ Returns:         if successful: 0
                    PCRE2_ERROR_NOSUBSTRING: no such substring
                    PCRE2_ERROR_UNAVAILABLE: ovector is too small
                    PCRE2_ERROR_UNSET: substring is not set
+                   PCRE2_ERROR_INVALIDOFFSET: internal error, should not occur
 */
 
 PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
@@ -341,6 +342,8 @@ else  /* Matched using pcre2_dfa_match() */
 
 left = match_data->ovector[stringnumber*2];
 right = match_data->ovector[stringnumber*2+1];
+if (left > match_data->subject_length || right > match_data->subject_length)
+  return PCRE2_ERROR_INVALIDOFFSET;
 if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left;
 return 0;
 }
@@ -442,7 +445,7 @@ Returns:      nothing
 */
 
 PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
-pcre2_substring_list_free(PCRE2_SPTR *list)
+pcre2_substring_list_free(PCRE2_UCHAR **list)
 {
 if (list != NULL)
   {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 484 - 484
thirdparty/pcre2/src/pcre2_ucd.c


+ 25 - 23
thirdparty/pcre2/src/pcre2_ucp.h

@@ -166,29 +166,29 @@ enum {
 /* These are the bidi class values. */
 
 enum {
-  ucp_bidiAL,   /* Arabic letter */
-  ucp_bidiAN,   /* Arabic number */
-  ucp_bidiB,    /* Paragraph separator */
-  ucp_bidiBN,   /* Boundary neutral */
-  ucp_bidiCS,   /* Common separator */
-  ucp_bidiEN,   /* European number */
-  ucp_bidiES,   /* European separator */
-  ucp_bidiET,   /* European terminator */
-  ucp_bidiFSI,  /* First strong isolate */
-  ucp_bidiL,    /* Left to right */
-  ucp_bidiLRE,  /* Left to right embedding */
-  ucp_bidiLRI,  /* Left to right isolate */
-  ucp_bidiLRO,  /* Left to right override */
-  ucp_bidiNSM,  /* Non-spacing mark */
-  ucp_bidiON,   /* Other neutral */
-  ucp_bidiPDF,  /* Pop directional format */
-  ucp_bidiPDI,  /* Pop directional isolate */
-  ucp_bidiR,    /* Right to left */
-  ucp_bidiRLE,  /* Right to left embedding */
-  ucp_bidiRLI,  /* Right to left isolate */
-  ucp_bidiRLO,  /* Right to left override */
-  ucp_bidiS,    /* Segment separator */
-  ucp_bidiWS,   /* White space */
+  ucp_bidiAL,   /* Arabic_Letter */
+  ucp_bidiAN,   /* Arabic_Number */
+  ucp_bidiB,    /* Paragraph_Separator */
+  ucp_bidiBN,   /* Boundary_Neutral */
+  ucp_bidiCS,   /* Common_Separator */
+  ucp_bidiEN,   /* European_Number */
+  ucp_bidiES,   /* European_Separator */
+  ucp_bidiET,   /* European_Terminator */
+  ucp_bidiFSI,  /* First_Strong_Isolate */
+  ucp_bidiL,    /* Left_To_Right */
+  ucp_bidiLRE,  /* Left_To_Right_Embedding */
+  ucp_bidiLRI,  /* Left_To_Right_Isolate */
+  ucp_bidiLRO,  /* Left_To_Right_Override */
+  ucp_bidiNSM,  /* Nonspacing_Mark */
+  ucp_bidiON,   /* Other_Neutral */
+  ucp_bidiPDF,  /* Pop_Directional_Format */
+  ucp_bidiPDI,  /* Pop_Directional_Isolate */
+  ucp_bidiR,    /* Right_To_Left */
+  ucp_bidiRLE,  /* Right_To_Left_Embedding */
+  ucp_bidiRLI,  /* Right_To_Left_Isolate */
+  ucp_bidiRLO,  /* Right_To_Left_Override */
+  ucp_bidiS,    /* Segment_Separator */
+  ucp_bidiWS,   /* White_Space */
 };
 
 /* These are grapheme break properties. The Extended Pictographic property
@@ -380,6 +380,8 @@ enum {
   ucp_Tangsa,
   ucp_Toto,
   ucp_Vithkuqi,
+  ucp_Kawi,
+  ucp_Nag_Mundari,
 
   /* This must be last */
   ucp_Script_Count

+ 269 - 260
thirdparty/pcre2/src/pcre2_ucptables.c

@@ -265,6 +265,7 @@ the "loose matching" rules that Unicode advises and Perl uses. */
 #define STRING_kana0 STR_k STR_a STR_n STR_a "\0"
 #define STRING_kannada0 STR_k STR_a STR_n STR_n STR_a STR_d STR_a "\0"
 #define STRING_katakana0 STR_k STR_a STR_t STR_a STR_k STR_a STR_n STR_a "\0"
+#define STRING_kawi0 STR_k STR_a STR_w STR_i "\0"
 #define STRING_kayahli0 STR_k STR_a STR_y STR_a STR_h STR_l STR_i "\0"
 #define STRING_khar0 STR_k STR_h STR_a STR_r "\0"
 #define STRING_kharoshthi0 STR_k STR_h STR_a STR_r STR_o STR_s STR_h STR_t STR_h STR_i "\0"
@@ -347,6 +348,8 @@ the "loose matching" rules that Unicode advises and Perl uses. */
 #define STRING_mymr0 STR_m STR_y STR_m STR_r "\0"
 #define STRING_n0 STR_n "\0"
 #define STRING_nabataean0 STR_n STR_a STR_b STR_a STR_t STR_a STR_e STR_a STR_n "\0"
+#define STRING_nagm0 STR_n STR_a STR_g STR_m "\0"
+#define STRING_nagmundari0 STR_n STR_a STR_g STR_m STR_u STR_n STR_d STR_a STR_r STR_i "\0"
 #define STRING_nand0 STR_n STR_a STR_n STR_d "\0"
 #define STRING_nandinagari0 STR_n STR_a STR_n STR_d STR_i STR_n STR_a STR_g STR_a STR_r STR_i "\0"
 #define STRING_narb0 STR_n STR_a STR_r STR_b "\0"
@@ -753,6 +756,7 @@ const char PRIV(utt_names)[] =
   STRING_kana0
   STRING_kannada0
   STRING_katakana0
+  STRING_kawi0
   STRING_kayahli0
   STRING_khar0
   STRING_kharoshthi0
@@ -835,6 +839,8 @@ const char PRIV(utt_names)[] =
   STRING_mymr0
   STRING_n0
   STRING_nabataean0
+  STRING_nagm0
+  STRING_nagmundari0
   STRING_nand0
   STRING_nandinagari0
   STRING_narb0
@@ -1241,280 +1247,283 @@ const ucp_type_table PRIV(utt)[] = {
   { 1665, PT_SCX, ucp_Katakana },
   { 1670, PT_SCX, ucp_Kannada },
   { 1678, PT_SCX, ucp_Katakana },
-  { 1687, PT_SCX, ucp_Kayah_Li },
-  { 1695, PT_SC, ucp_Kharoshthi },
+  { 1687, PT_SC, ucp_Kawi },
+  { 1692, PT_SCX, ucp_Kayah_Li },
   { 1700, PT_SC, ucp_Kharoshthi },
-  { 1711, PT_SC, ucp_Khitan_Small_Script },
-  { 1729, PT_SC, ucp_Khmer },
-  { 1735, PT_SC, ucp_Khmer },
-  { 1740, PT_SCX, ucp_Khojki },
+  { 1705, PT_SC, ucp_Kharoshthi },
+  { 1716, PT_SC, ucp_Khitan_Small_Script },
+  { 1734, PT_SC, ucp_Khmer },
+  { 1740, PT_SC, ucp_Khmer },
   { 1745, PT_SCX, ucp_Khojki },
-  { 1752, PT_SCX, ucp_Khudawadi },
-  { 1762, PT_SC, ucp_Khitan_Small_Script },
-  { 1767, PT_SCX, ucp_Kannada },
-  { 1772, PT_SCX, ucp_Kaithi },
-  { 1777, PT_GC, ucp_L },
-  { 1779, PT_LAMP, 0 },
-  { 1782, PT_SC, ucp_Tai_Tham },
-  { 1787, PT_SC, ucp_Lao },
-  { 1791, PT_SC, ucp_Lao },
-  { 1796, PT_SCX, ucp_Latin },
-  { 1802, PT_SCX, ucp_Latin },
-  { 1807, PT_LAMP, 0 },
-  { 1810, PT_SC, ucp_Lepcha },
+  { 1750, PT_SCX, ucp_Khojki },
+  { 1757, PT_SCX, ucp_Khudawadi },
+  { 1767, PT_SC, ucp_Khitan_Small_Script },
+  { 1772, PT_SCX, ucp_Kannada },
+  { 1777, PT_SCX, ucp_Kaithi },
+  { 1782, PT_GC, ucp_L },
+  { 1784, PT_LAMP, 0 },
+  { 1787, PT_SC, ucp_Tai_Tham },
+  { 1792, PT_SC, ucp_Lao },
+  { 1796, PT_SC, ucp_Lao },
+  { 1801, PT_SCX, ucp_Latin },
+  { 1807, PT_SCX, ucp_Latin },
+  { 1812, PT_LAMP, 0 },
   { 1815, PT_SC, ucp_Lepcha },
-  { 1822, PT_SCX, ucp_Limbu },
+  { 1820, PT_SC, ucp_Lepcha },
   { 1827, PT_SCX, ucp_Limbu },
-  { 1833, PT_SCX, ucp_Linear_A },
-  { 1838, PT_SCX, ucp_Linear_B },
-  { 1843, PT_SCX, ucp_Linear_A },
-  { 1851, PT_SCX, ucp_Linear_B },
-  { 1859, PT_SC, ucp_Lisu },
-  { 1864, PT_PC, ucp_Ll },
-  { 1867, PT_PC, ucp_Lm },
-  { 1870, PT_PC, ucp_Lo },
-  { 1873, PT_BOOL, ucp_Logical_Order_Exception },
-  { 1877, PT_BOOL, ucp_Logical_Order_Exception },
-  { 1899, PT_BOOL, ucp_Lowercase },
-  { 1905, PT_BOOL, ucp_Lowercase },
-  { 1915, PT_PC, ucp_Lt },
-  { 1918, PT_PC, ucp_Lu },
-  { 1921, PT_SC, ucp_Lycian },
+  { 1832, PT_SCX, ucp_Limbu },
+  { 1838, PT_SCX, ucp_Linear_A },
+  { 1843, PT_SCX, ucp_Linear_B },
+  { 1848, PT_SCX, ucp_Linear_A },
+  { 1856, PT_SCX, ucp_Linear_B },
+  { 1864, PT_SC, ucp_Lisu },
+  { 1869, PT_PC, ucp_Ll },
+  { 1872, PT_PC, ucp_Lm },
+  { 1875, PT_PC, ucp_Lo },
+  { 1878, PT_BOOL, ucp_Logical_Order_Exception },
+  { 1882, PT_BOOL, ucp_Logical_Order_Exception },
+  { 1904, PT_BOOL, ucp_Lowercase },
+  { 1910, PT_BOOL, ucp_Lowercase },
+  { 1920, PT_PC, ucp_Lt },
+  { 1923, PT_PC, ucp_Lu },
   { 1926, PT_SC, ucp_Lycian },
-  { 1933, PT_SC, ucp_Lydian },
+  { 1931, PT_SC, ucp_Lycian },
   { 1938, PT_SC, ucp_Lydian },
-  { 1945, PT_GC, ucp_M },
-  { 1947, PT_SCX, ucp_Mahajani },
-  { 1956, PT_SCX, ucp_Mahajani },
-  { 1961, PT_SC, ucp_Makasar },
+  { 1943, PT_SC, ucp_Lydian },
+  { 1950, PT_GC, ucp_M },
+  { 1952, PT_SCX, ucp_Mahajani },
+  { 1961, PT_SCX, ucp_Mahajani },
   { 1966, PT_SC, ucp_Makasar },
-  { 1974, PT_SCX, ucp_Malayalam },
-  { 1984, PT_SCX, ucp_Mandaic },
+  { 1971, PT_SC, ucp_Makasar },
+  { 1979, PT_SCX, ucp_Malayalam },
   { 1989, PT_SCX, ucp_Mandaic },
-  { 1997, PT_SCX, ucp_Manichaean },
+  { 1994, PT_SCX, ucp_Mandaic },
   { 2002, PT_SCX, ucp_Manichaean },
-  { 2013, PT_SC, ucp_Marchen },
+  { 2007, PT_SCX, ucp_Manichaean },
   { 2018, PT_SC, ucp_Marchen },
-  { 2026, PT_SCX, ucp_Masaram_Gondi },
-  { 2039, PT_BOOL, ucp_Math },
-  { 2044, PT_PC, ucp_Mc },
-  { 2047, PT_PC, ucp_Me },
-  { 2050, PT_SC, ucp_Medefaidrin },
-  { 2062, PT_SC, ucp_Medefaidrin },
-  { 2067, PT_SC, ucp_Meetei_Mayek },
-  { 2079, PT_SC, ucp_Mende_Kikakui },
+  { 2023, PT_SC, ucp_Marchen },
+  { 2031, PT_SCX, ucp_Masaram_Gondi },
+  { 2044, PT_BOOL, ucp_Math },
+  { 2049, PT_PC, ucp_Mc },
+  { 2052, PT_PC, ucp_Me },
+  { 2055, PT_SC, ucp_Medefaidrin },
+  { 2067, PT_SC, ucp_Medefaidrin },
+  { 2072, PT_SC, ucp_Meetei_Mayek },
   { 2084, PT_SC, ucp_Mende_Kikakui },
-  { 2097, PT_SC, ucp_Meroitic_Cursive },
-  { 2102, PT_SC, ucp_Meroitic_Hieroglyphs },
-  { 2107, PT_SC, ucp_Meroitic_Cursive },
-  { 2123, PT_SC, ucp_Meroitic_Hieroglyphs },
-  { 2143, PT_SC, ucp_Miao },
-  { 2148, PT_SCX, ucp_Malayalam },
-  { 2153, PT_PC, ucp_Mn },
-  { 2156, PT_SCX, ucp_Modi },
-  { 2161, PT_SCX, ucp_Mongolian },
+  { 2089, PT_SC, ucp_Mende_Kikakui },
+  { 2102, PT_SC, ucp_Meroitic_Cursive },
+  { 2107, PT_SC, ucp_Meroitic_Hieroglyphs },
+  { 2112, PT_SC, ucp_Meroitic_Cursive },
+  { 2128, PT_SC, ucp_Meroitic_Hieroglyphs },
+  { 2148, PT_SC, ucp_Miao },
+  { 2153, PT_SCX, ucp_Malayalam },
+  { 2158, PT_PC, ucp_Mn },
+  { 2161, PT_SCX, ucp_Modi },
   { 2166, PT_SCX, ucp_Mongolian },
-  { 2176, PT_SC, ucp_Mro },
-  { 2180, PT_SC, ucp_Mro },
-  { 2185, PT_SC, ucp_Meetei_Mayek },
-  { 2190, PT_SCX, ucp_Multani },
+  { 2171, PT_SCX, ucp_Mongolian },
+  { 2181, PT_SC, ucp_Mro },
+  { 2185, PT_SC, ucp_Mro },
+  { 2190, PT_SC, ucp_Meetei_Mayek },
   { 2195, PT_SCX, ucp_Multani },
-  { 2203, PT_SCX, ucp_Myanmar },
-  { 2211, PT_SCX, ucp_Myanmar },
-  { 2216, PT_GC, ucp_N },
-  { 2218, PT_SC, ucp_Nabataean },
-  { 2228, PT_SCX, ucp_Nandinagari },
-  { 2233, PT_SCX, ucp_Nandinagari },
-  { 2245, PT_SC, ucp_Old_North_Arabian },
-  { 2250, PT_SC, ucp_Nabataean },
-  { 2255, PT_BOOL, ucp_Noncharacter_Code_Point },
-  { 2261, PT_PC, ucp_Nd },
-  { 2264, PT_SC, ucp_Newa },
-  { 2269, PT_SC, ucp_New_Tai_Lue },
-  { 2279, PT_SCX, ucp_Nko },
-  { 2283, PT_SCX, ucp_Nko },
-  { 2288, PT_PC, ucp_Nl },
-  { 2291, PT_PC, ucp_No },
-  { 2294, PT_BOOL, ucp_Noncharacter_Code_Point },
-  { 2316, PT_SC, ucp_Nushu },
-  { 2321, PT_SC, ucp_Nushu },
-  { 2327, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
-  { 2348, PT_SC, ucp_Ogham },
-  { 2353, PT_SC, ucp_Ogham },
-  { 2359, PT_SC, ucp_Ol_Chiki },
-  { 2367, PT_SC, ucp_Ol_Chiki },
-  { 2372, PT_SC, ucp_Old_Hungarian },
-  { 2385, PT_SC, ucp_Old_Italic },
-  { 2395, PT_SC, ucp_Old_North_Arabian },
-  { 2411, PT_SCX, ucp_Old_Permic },
-  { 2421, PT_SC, ucp_Old_Persian },
-  { 2432, PT_SC, ucp_Old_Sogdian },
-  { 2443, PT_SC, ucp_Old_South_Arabian },
-  { 2459, PT_SC, ucp_Old_Turkic },
-  { 2469, PT_SCX, ucp_Old_Uyghur },
-  { 2479, PT_SCX, ucp_Oriya },
-  { 2485, PT_SC, ucp_Old_Turkic },
-  { 2490, PT_SCX, ucp_Oriya },
-  { 2495, PT_SC, ucp_Osage },
-  { 2501, PT_SC, ucp_Osage },
-  { 2506, PT_SC, ucp_Osmanya },
-  { 2511, PT_SC, ucp_Osmanya },
-  { 2519, PT_SCX, ucp_Old_Uyghur },
-  { 2524, PT_GC, ucp_P },
-  { 2526, PT_SC, ucp_Pahawh_Hmong },
-  { 2538, PT_SC, ucp_Palmyrene },
-  { 2543, PT_SC, ucp_Palmyrene },
-  { 2553, PT_BOOL, ucp_Pattern_Syntax },
-  { 2560, PT_BOOL, ucp_Pattern_Syntax },
-  { 2574, PT_BOOL, ucp_Pattern_White_Space },
-  { 2592, PT_BOOL, ucp_Pattern_White_Space },
-  { 2598, PT_SC, ucp_Pau_Cin_Hau },
-  { 2603, PT_SC, ucp_Pau_Cin_Hau },
-  { 2613, PT_PC, ucp_Pc },
-  { 2616, PT_BOOL, ucp_Prepended_Concatenation_Mark },
-  { 2620, PT_PC, ucp_Pd },
-  { 2623, PT_PC, ucp_Pe },
-  { 2626, PT_SCX, ucp_Old_Permic },
-  { 2631, PT_PC, ucp_Pf },
-  { 2634, PT_SCX, ucp_Phags_Pa },
-  { 2639, PT_SCX, ucp_Phags_Pa },
-  { 2647, PT_SC, ucp_Inscriptional_Pahlavi },
-  { 2652, PT_SCX, ucp_Psalter_Pahlavi },
-  { 2657, PT_SC, ucp_Phoenician },
-  { 2662, PT_SC, ucp_Phoenician },
-  { 2673, PT_PC, ucp_Pi },
-  { 2676, PT_SC, ucp_Miao },
-  { 2681, PT_PC, ucp_Po },
-  { 2684, PT_BOOL, ucp_Prepended_Concatenation_Mark },
-  { 2711, PT_SC, ucp_Inscriptional_Parthian },
-  { 2716, PT_PC, ucp_Ps },
-  { 2719, PT_SCX, ucp_Psalter_Pahlavi },
-  { 2734, PT_SCX, ucp_Coptic },
-  { 2739, PT_SC, ucp_Inherited },
-  { 2744, PT_BOOL, ucp_Quotation_Mark },
-  { 2750, PT_BOOL, ucp_Quotation_Mark },
-  { 2764, PT_BOOL, ucp_Radical },
-  { 2772, PT_BOOL, ucp_Regional_Indicator },
-  { 2790, PT_SC, ucp_Rejang },
-  { 2797, PT_BOOL, ucp_Regional_Indicator },
-  { 2800, PT_SC, ucp_Rejang },
-  { 2805, PT_SCX, ucp_Hanifi_Rohingya },
-  { 2810, PT_SC, ucp_Runic },
-  { 2816, PT_SC, ucp_Runic },
-  { 2821, PT_GC, ucp_S },
-  { 2823, PT_SC, ucp_Samaritan },
-  { 2833, PT_SC, ucp_Samaritan },
-  { 2838, PT_SC, ucp_Old_South_Arabian },
-  { 2843, PT_SC, ucp_Saurashtra },
-  { 2848, PT_SC, ucp_Saurashtra },
-  { 2859, PT_PC, ucp_Sc },
-  { 2862, PT_BOOL, ucp_Soft_Dotted },
-  { 2865, PT_BOOL, ucp_Sentence_Terminal },
-  { 2882, PT_SC, ucp_SignWriting },
-  { 2887, PT_SCX, ucp_Sharada },
-  { 2895, PT_SC, ucp_Shavian },
-  { 2903, PT_SC, ucp_Shavian },
+  { 2200, PT_SCX, ucp_Multani },
+  { 2208, PT_SCX, ucp_Myanmar },
+  { 2216, PT_SCX, ucp_Myanmar },
+  { 2221, PT_GC, ucp_N },
+  { 2223, PT_SC, ucp_Nabataean },
+  { 2233, PT_SC, ucp_Nag_Mundari },
+  { 2238, PT_SC, ucp_Nag_Mundari },
+  { 2249, PT_SCX, ucp_Nandinagari },
+  { 2254, PT_SCX, ucp_Nandinagari },
+  { 2266, PT_SC, ucp_Old_North_Arabian },
+  { 2271, PT_SC, ucp_Nabataean },
+  { 2276, PT_BOOL, ucp_Noncharacter_Code_Point },
+  { 2282, PT_PC, ucp_Nd },
+  { 2285, PT_SC, ucp_Newa },
+  { 2290, PT_SC, ucp_New_Tai_Lue },
+  { 2300, PT_SCX, ucp_Nko },
+  { 2304, PT_SCX, ucp_Nko },
+  { 2309, PT_PC, ucp_Nl },
+  { 2312, PT_PC, ucp_No },
+  { 2315, PT_BOOL, ucp_Noncharacter_Code_Point },
+  { 2337, PT_SC, ucp_Nushu },
+  { 2342, PT_SC, ucp_Nushu },
+  { 2348, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
+  { 2369, PT_SC, ucp_Ogham },
+  { 2374, PT_SC, ucp_Ogham },
+  { 2380, PT_SC, ucp_Ol_Chiki },
+  { 2388, PT_SC, ucp_Ol_Chiki },
+  { 2393, PT_SC, ucp_Old_Hungarian },
+  { 2406, PT_SC, ucp_Old_Italic },
+  { 2416, PT_SC, ucp_Old_North_Arabian },
+  { 2432, PT_SCX, ucp_Old_Permic },
+  { 2442, PT_SC, ucp_Old_Persian },
+  { 2453, PT_SC, ucp_Old_Sogdian },
+  { 2464, PT_SC, ucp_Old_South_Arabian },
+  { 2480, PT_SC, ucp_Old_Turkic },
+  { 2490, PT_SCX, ucp_Old_Uyghur },
+  { 2500, PT_SCX, ucp_Oriya },
+  { 2506, PT_SC, ucp_Old_Turkic },
+  { 2511, PT_SCX, ucp_Oriya },
+  { 2516, PT_SC, ucp_Osage },
+  { 2522, PT_SC, ucp_Osage },
+  { 2527, PT_SC, ucp_Osmanya },
+  { 2532, PT_SC, ucp_Osmanya },
+  { 2540, PT_SCX, ucp_Old_Uyghur },
+  { 2545, PT_GC, ucp_P },
+  { 2547, PT_SC, ucp_Pahawh_Hmong },
+  { 2559, PT_SC, ucp_Palmyrene },
+  { 2564, PT_SC, ucp_Palmyrene },
+  { 2574, PT_BOOL, ucp_Pattern_Syntax },
+  { 2581, PT_BOOL, ucp_Pattern_Syntax },
+  { 2595, PT_BOOL, ucp_Pattern_White_Space },
+  { 2613, PT_BOOL, ucp_Pattern_White_Space },
+  { 2619, PT_SC, ucp_Pau_Cin_Hau },
+  { 2624, PT_SC, ucp_Pau_Cin_Hau },
+  { 2634, PT_PC, ucp_Pc },
+  { 2637, PT_BOOL, ucp_Prepended_Concatenation_Mark },
+  { 2641, PT_PC, ucp_Pd },
+  { 2644, PT_PC, ucp_Pe },
+  { 2647, PT_SCX, ucp_Old_Permic },
+  { 2652, PT_PC, ucp_Pf },
+  { 2655, PT_SCX, ucp_Phags_Pa },
+  { 2660, PT_SCX, ucp_Phags_Pa },
+  { 2668, PT_SC, ucp_Inscriptional_Pahlavi },
+  { 2673, PT_SCX, ucp_Psalter_Pahlavi },
+  { 2678, PT_SC, ucp_Phoenician },
+  { 2683, PT_SC, ucp_Phoenician },
+  { 2694, PT_PC, ucp_Pi },
+  { 2697, PT_SC, ucp_Miao },
+  { 2702, PT_PC, ucp_Po },
+  { 2705, PT_BOOL, ucp_Prepended_Concatenation_Mark },
+  { 2732, PT_SC, ucp_Inscriptional_Parthian },
+  { 2737, PT_PC, ucp_Ps },
+  { 2740, PT_SCX, ucp_Psalter_Pahlavi },
+  { 2755, PT_SCX, ucp_Coptic },
+  { 2760, PT_SC, ucp_Inherited },
+  { 2765, PT_BOOL, ucp_Quotation_Mark },
+  { 2771, PT_BOOL, ucp_Quotation_Mark },
+  { 2785, PT_BOOL, ucp_Radical },
+  { 2793, PT_BOOL, ucp_Regional_Indicator },
+  { 2811, PT_SC, ucp_Rejang },
+  { 2818, PT_BOOL, ucp_Regional_Indicator },
+  { 2821, PT_SC, ucp_Rejang },
+  { 2826, PT_SCX, ucp_Hanifi_Rohingya },
+  { 2831, PT_SC, ucp_Runic },
+  { 2837, PT_SC, ucp_Runic },
+  { 2842, PT_GC, ucp_S },
+  { 2844, PT_SC, ucp_Samaritan },
+  { 2854, PT_SC, ucp_Samaritan },
+  { 2859, PT_SC, ucp_Old_South_Arabian },
+  { 2864, PT_SC, ucp_Saurashtra },
+  { 2869, PT_SC, ucp_Saurashtra },
+  { 2880, PT_PC, ucp_Sc },
+  { 2883, PT_BOOL, ucp_Soft_Dotted },
+  { 2886, PT_BOOL, ucp_Sentence_Terminal },
+  { 2903, PT_SC, ucp_SignWriting },
   { 2908, PT_SCX, ucp_Sharada },
-  { 2913, PT_SC, ucp_Siddham },
-  { 2918, PT_SC, ucp_Siddham },
-  { 2926, PT_SC, ucp_SignWriting },
-  { 2938, PT_SCX, ucp_Khudawadi },
-  { 2943, PT_SCX, ucp_Sinhala },
-  { 2948, PT_SCX, ucp_Sinhala },
-  { 2956, PT_PC, ucp_Sk },
-  { 2959, PT_PC, ucp_Sm },
-  { 2962, PT_PC, ucp_So },
-  { 2965, PT_BOOL, ucp_Soft_Dotted },
-  { 2976, PT_SCX, ucp_Sogdian },
-  { 2981, PT_SCX, ucp_Sogdian },
-  { 2989, PT_SC, ucp_Old_Sogdian },
-  { 2994, PT_SC, ucp_Sora_Sompeng },
-  { 2999, PT_SC, ucp_Sora_Sompeng },
-  { 3011, PT_SC, ucp_Soyombo },
-  { 3016, PT_SC, ucp_Soyombo },
-  { 3024, PT_BOOL, ucp_White_Space },
-  { 3030, PT_BOOL, ucp_Sentence_Terminal },
-  { 3036, PT_SC, ucp_Sundanese },
-  { 3041, PT_SC, ucp_Sundanese },
-  { 3051, PT_SCX, ucp_Syloti_Nagri },
-  { 3056, PT_SCX, ucp_Syloti_Nagri },
-  { 3068, PT_SCX, ucp_Syriac },
-  { 3073, PT_SCX, ucp_Syriac },
-  { 3080, PT_SCX, ucp_Tagalog },
-  { 3088, PT_SCX, ucp_Tagbanwa },
-  { 3093, PT_SCX, ucp_Tagbanwa },
-  { 3102, PT_SCX, ucp_Tai_Le },
-  { 3108, PT_SC, ucp_Tai_Tham },
-  { 3116, PT_SC, ucp_Tai_Viet },
-  { 3124, PT_SCX, ucp_Takri },
-  { 3129, PT_SCX, ucp_Takri },
-  { 3135, PT_SCX, ucp_Tai_Le },
-  { 3140, PT_SC, ucp_New_Tai_Lue },
-  { 3145, PT_SCX, ucp_Tamil },
-  { 3151, PT_SCX, ucp_Tamil },
-  { 3156, PT_SC, ucp_Tangut },
-  { 3161, PT_SC, ucp_Tangsa },
-  { 3168, PT_SC, ucp_Tangut },
-  { 3175, PT_SC, ucp_Tai_Viet },
-  { 3180, PT_SCX, ucp_Telugu },
-  { 3185, PT_SCX, ucp_Telugu },
-  { 3192, PT_BOOL, ucp_Terminal_Punctuation },
-  { 3197, PT_BOOL, ucp_Terminal_Punctuation },
-  { 3217, PT_SC, ucp_Tifinagh },
-  { 3222, PT_SCX, ucp_Tagalog },
-  { 3227, PT_SCX, ucp_Thaana },
-  { 3232, PT_SCX, ucp_Thaana },
-  { 3239, PT_SC, ucp_Thai },
-  { 3244, PT_SC, ucp_Tibetan },
-  { 3252, PT_SC, ucp_Tibetan },
-  { 3257, PT_SC, ucp_Tifinagh },
-  { 3266, PT_SCX, ucp_Tirhuta },
-  { 3271, PT_SCX, ucp_Tirhuta },
-  { 3279, PT_SC, ucp_Tangsa },
-  { 3284, PT_SC, ucp_Toto },
-  { 3289, PT_SC, ucp_Ugaritic },
-  { 3294, PT_SC, ucp_Ugaritic },
-  { 3303, PT_BOOL, ucp_Unified_Ideograph },
-  { 3309, PT_BOOL, ucp_Unified_Ideograph },
-  { 3326, PT_SC, ucp_Unknown },
-  { 3334, PT_BOOL, ucp_Uppercase },
-  { 3340, PT_BOOL, ucp_Uppercase },
-  { 3350, PT_SC, ucp_Vai },
-  { 3354, PT_SC, ucp_Vai },
-  { 3359, PT_BOOL, ucp_Variation_Selector },
-  { 3377, PT_SC, ucp_Vithkuqi },
-  { 3382, PT_SC, ucp_Vithkuqi },
-  { 3391, PT_BOOL, ucp_Variation_Selector },
-  { 3394, PT_SC, ucp_Wancho },
-  { 3401, PT_SC, ucp_Warang_Citi },
-  { 3406, PT_SC, ucp_Warang_Citi },
-  { 3417, PT_SC, ucp_Wancho },
-  { 3422, PT_BOOL, ucp_White_Space },
-  { 3433, PT_BOOL, ucp_White_Space },
-  { 3440, PT_ALNUM, 0 },
-  { 3444, PT_BOOL, ucp_XID_Continue },
-  { 3449, PT_BOOL, ucp_XID_Continue },
-  { 3461, PT_BOOL, ucp_XID_Start },
-  { 3466, PT_BOOL, ucp_XID_Start },
-  { 3475, PT_SC, ucp_Old_Persian },
-  { 3480, PT_PXSPACE, 0 },
-  { 3484, PT_SPACE, 0 },
-  { 3488, PT_SC, ucp_Cuneiform },
-  { 3493, PT_UCNC, 0 },
-  { 3497, PT_WORD, 0 },
-  { 3501, PT_SCX, ucp_Yezidi },
-  { 3506, PT_SCX, ucp_Yezidi },
-  { 3513, PT_SCX, ucp_Yi },
-  { 3516, PT_SCX, ucp_Yi },
-  { 3521, PT_GC, ucp_Z },
-  { 3523, PT_SC, ucp_Zanabazar_Square },
-  { 3539, PT_SC, ucp_Zanabazar_Square },
-  { 3544, PT_SC, ucp_Inherited },
-  { 3549, PT_PC, ucp_Zl },
-  { 3552, PT_PC, ucp_Zp },
-  { 3555, PT_PC, ucp_Zs },
-  { 3558, PT_SC, ucp_Common },
-  { 3563, PT_SC, ucp_Unknown }
+  { 2916, PT_SC, ucp_Shavian },
+  { 2924, PT_SC, ucp_Shavian },
+  { 2929, PT_SCX, ucp_Sharada },
+  { 2934, PT_SC, ucp_Siddham },
+  { 2939, PT_SC, ucp_Siddham },
+  { 2947, PT_SC, ucp_SignWriting },
+  { 2959, PT_SCX, ucp_Khudawadi },
+  { 2964, PT_SCX, ucp_Sinhala },
+  { 2969, PT_SCX, ucp_Sinhala },
+  { 2977, PT_PC, ucp_Sk },
+  { 2980, PT_PC, ucp_Sm },
+  { 2983, PT_PC, ucp_So },
+  { 2986, PT_BOOL, ucp_Soft_Dotted },
+  { 2997, PT_SCX, ucp_Sogdian },
+  { 3002, PT_SCX, ucp_Sogdian },
+  { 3010, PT_SC, ucp_Old_Sogdian },
+  { 3015, PT_SC, ucp_Sora_Sompeng },
+  { 3020, PT_SC, ucp_Sora_Sompeng },
+  { 3032, PT_SC, ucp_Soyombo },
+  { 3037, PT_SC, ucp_Soyombo },
+  { 3045, PT_BOOL, ucp_White_Space },
+  { 3051, PT_BOOL, ucp_Sentence_Terminal },
+  { 3057, PT_SC, ucp_Sundanese },
+  { 3062, PT_SC, ucp_Sundanese },
+  { 3072, PT_SCX, ucp_Syloti_Nagri },
+  { 3077, PT_SCX, ucp_Syloti_Nagri },
+  { 3089, PT_SCX, ucp_Syriac },
+  { 3094, PT_SCX, ucp_Syriac },
+  { 3101, PT_SCX, ucp_Tagalog },
+  { 3109, PT_SCX, ucp_Tagbanwa },
+  { 3114, PT_SCX, ucp_Tagbanwa },
+  { 3123, PT_SCX, ucp_Tai_Le },
+  { 3129, PT_SC, ucp_Tai_Tham },
+  { 3137, PT_SC, ucp_Tai_Viet },
+  { 3145, PT_SCX, ucp_Takri },
+  { 3150, PT_SCX, ucp_Takri },
+  { 3156, PT_SCX, ucp_Tai_Le },
+  { 3161, PT_SC, ucp_New_Tai_Lue },
+  { 3166, PT_SCX, ucp_Tamil },
+  { 3172, PT_SCX, ucp_Tamil },
+  { 3177, PT_SC, ucp_Tangut },
+  { 3182, PT_SC, ucp_Tangsa },
+  { 3189, PT_SC, ucp_Tangut },
+  { 3196, PT_SC, ucp_Tai_Viet },
+  { 3201, PT_SCX, ucp_Telugu },
+  { 3206, PT_SCX, ucp_Telugu },
+  { 3213, PT_BOOL, ucp_Terminal_Punctuation },
+  { 3218, PT_BOOL, ucp_Terminal_Punctuation },
+  { 3238, PT_SC, ucp_Tifinagh },
+  { 3243, PT_SCX, ucp_Tagalog },
+  { 3248, PT_SCX, ucp_Thaana },
+  { 3253, PT_SCX, ucp_Thaana },
+  { 3260, PT_SC, ucp_Thai },
+  { 3265, PT_SC, ucp_Tibetan },
+  { 3273, PT_SC, ucp_Tibetan },
+  { 3278, PT_SC, ucp_Tifinagh },
+  { 3287, PT_SCX, ucp_Tirhuta },
+  { 3292, PT_SCX, ucp_Tirhuta },
+  { 3300, PT_SC, ucp_Tangsa },
+  { 3305, PT_SC, ucp_Toto },
+  { 3310, PT_SC, ucp_Ugaritic },
+  { 3315, PT_SC, ucp_Ugaritic },
+  { 3324, PT_BOOL, ucp_Unified_Ideograph },
+  { 3330, PT_BOOL, ucp_Unified_Ideograph },
+  { 3347, PT_SC, ucp_Unknown },
+  { 3355, PT_BOOL, ucp_Uppercase },
+  { 3361, PT_BOOL, ucp_Uppercase },
+  { 3371, PT_SC, ucp_Vai },
+  { 3375, PT_SC, ucp_Vai },
+  { 3380, PT_BOOL, ucp_Variation_Selector },
+  { 3398, PT_SC, ucp_Vithkuqi },
+  { 3403, PT_SC, ucp_Vithkuqi },
+  { 3412, PT_BOOL, ucp_Variation_Selector },
+  { 3415, PT_SC, ucp_Wancho },
+  { 3422, PT_SC, ucp_Warang_Citi },
+  { 3427, PT_SC, ucp_Warang_Citi },
+  { 3438, PT_SC, ucp_Wancho },
+  { 3443, PT_BOOL, ucp_White_Space },
+  { 3454, PT_BOOL, ucp_White_Space },
+  { 3461, PT_ALNUM, 0 },
+  { 3465, PT_BOOL, ucp_XID_Continue },
+  { 3470, PT_BOOL, ucp_XID_Continue },
+  { 3482, PT_BOOL, ucp_XID_Start },
+  { 3487, PT_BOOL, ucp_XID_Start },
+  { 3496, PT_SC, ucp_Old_Persian },
+  { 3501, PT_PXSPACE, 0 },
+  { 3505, PT_SPACE, 0 },
+  { 3509, PT_SC, ucp_Cuneiform },
+  { 3514, PT_UCNC, 0 },
+  { 3518, PT_WORD, 0 },
+  { 3522, PT_SCX, ucp_Yezidi },
+  { 3527, PT_SCX, ucp_Yezidi },
+  { 3534, PT_SCX, ucp_Yi },
+  { 3537, PT_SCX, ucp_Yi },
+  { 3542, PT_GC, ucp_Z },
+  { 3544, PT_SC, ucp_Zanabazar_Square },
+  { 3560, PT_SC, ucp_Zanabazar_Square },
+  { 3565, PT_SC, ucp_Inherited },
+  { 3570, PT_PC, ucp_Zl },
+  { 3573, PT_PC, ucp_Zp },
+  { 3576, PT_PC, ucp_Zs },
+  { 3579, PT_SC, ucp_Common },
+  { 3584, PT_SC, ucp_Unknown }
 };
 
 const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);

+ 24 - 24
thirdparty/pcre2/src/pcre2_valid_utf.c

@@ -171,7 +171,7 @@ for (p = string; length > 0; p++)
 
   if (((d = *(++p)) & 0xc0) != 0x80)
     {
-    *erroroffset = (int)(p - string) - 1;
+    *erroroffset = (PCRE2_SIZE)(p - string) - 1;
     return PCRE2_ERROR_UTF8_ERR6;
     }
 
@@ -186,7 +186,7 @@ for (p = string; length > 0; p++)
 
     case 1: if ((c & 0x3e) == 0)
       {
-      *erroroffset = (int)(p - string) - 1;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 1;
       return PCRE2_ERROR_UTF8_ERR15;
       }
     break;
@@ -198,17 +198,17 @@ for (p = string; length > 0; p++)
     case 2:
     if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
       {
-      *erroroffset = (int)(p - string) - 2;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 2;
       return PCRE2_ERROR_UTF8_ERR7;
       }
     if (c == 0xe0 && (d & 0x20) == 0)
       {
-      *erroroffset = (int)(p - string) - 2;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 2;
       return PCRE2_ERROR_UTF8_ERR16;
       }
     if (c == 0xed && d >= 0xa0)
       {
-      *erroroffset = (int)(p - string) - 2;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 2;
       return PCRE2_ERROR_UTF8_ERR14;
       }
     break;
@@ -220,22 +220,22 @@ for (p = string; length > 0; p++)
     case 3:
     if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
       {
-      *erroroffset = (int)(p - string) - 2;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 2;
       return PCRE2_ERROR_UTF8_ERR7;
       }
     if ((*(++p) & 0xc0) != 0x80)     /* Fourth byte */
       {
-      *erroroffset = (int)(p - string) - 3;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 3;
       return PCRE2_ERROR_UTF8_ERR8;
       }
     if (c == 0xf0 && (d & 0x30) == 0)
       {
-      *erroroffset = (int)(p - string) - 3;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 3;
       return PCRE2_ERROR_UTF8_ERR17;
       }
     if (c > 0xf4 || (c == 0xf4 && d > 0x8f))
       {
-      *erroroffset = (int)(p - string) - 3;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 3;
       return PCRE2_ERROR_UTF8_ERR13;
       }
     break;
@@ -251,22 +251,22 @@ for (p = string; length > 0; p++)
     case 4:
     if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
       {
-      *erroroffset = (int)(p - string) - 2;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 2;
       return PCRE2_ERROR_UTF8_ERR7;
       }
     if ((*(++p) & 0xc0) != 0x80)     /* Fourth byte */
       {
-      *erroroffset = (int)(p - string) - 3;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 3;
       return PCRE2_ERROR_UTF8_ERR8;
       }
     if ((*(++p) & 0xc0) != 0x80)     /* Fifth byte */
       {
-      *erroroffset = (int)(p - string) - 4;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 4;
       return PCRE2_ERROR_UTF8_ERR9;
       }
     if (c == 0xf8 && (d & 0x38) == 0)
       {
-      *erroroffset = (int)(p - string) - 4;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 4;
       return PCRE2_ERROR_UTF8_ERR18;
       }
     break;
@@ -277,27 +277,27 @@ for (p = string; length > 0; p++)
     case 5:
     if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
       {
-      *erroroffset = (int)(p - string) - 2;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 2;
       return PCRE2_ERROR_UTF8_ERR7;
       }
     if ((*(++p) & 0xc0) != 0x80)     /* Fourth byte */
       {
-      *erroroffset = (int)(p - string) - 3;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 3;
       return PCRE2_ERROR_UTF8_ERR8;
       }
     if ((*(++p) & 0xc0) != 0x80)     /* Fifth byte */
       {
-      *erroroffset = (int)(p - string) - 4;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 4;
       return PCRE2_ERROR_UTF8_ERR9;
       }
     if ((*(++p) & 0xc0) != 0x80)     /* Sixth byte */
       {
-      *erroroffset = (int)(p - string) - 5;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 5;
       return PCRE2_ERROR_UTF8_ERR10;
       }
     if (c == 0xfc && (d & 0x3c) == 0)
       {
-      *erroroffset = (int)(p - string) - 5;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 5;
       return PCRE2_ERROR_UTF8_ERR19;
       }
     break;
@@ -309,7 +309,7 @@ for (p = string; length > 0; p++)
 
   if (ab > 3)
     {
-    *erroroffset = (int)(p - string) - ab;
+    *erroroffset = (PCRE2_SIZE)(p - string) - ab;
     return (ab == 4)? PCRE2_ERROR_UTF8_ERR11 : PCRE2_ERROR_UTF8_ERR12;
     }
   }
@@ -340,21 +340,21 @@ for (p = string; length > 0; p++)
     /* High surrogate. Must be a followed by a low surrogate. */
     if (length == 0)
       {
-      *erroroffset = p - string;
+      *erroroffset = (PCRE2_SIZE)(p - string);
       return PCRE2_ERROR_UTF16_ERR1;
       }
     p++;
     length--;
     if ((*p & 0xfc00) != 0xdc00)
       {
-      *erroroffset = p - string - 1;
+      *erroroffset = (PCRE2_SIZE)(p - string) - 1;
       return PCRE2_ERROR_UTF16_ERR2;
       }
     }
   else
     {
     /* Isolated low surrogate. Always an error. */
-    *erroroffset = p - string;
+    *erroroffset = (PCRE2_SIZE)(p - string);
     return PCRE2_ERROR_UTF16_ERR3;
     }
   }
@@ -379,14 +379,14 @@ for (p = string; length > 0; length--, p++)
     /* Normal UTF-32 code point. Neither high nor low surrogate. */
     if (c > 0x10ffffu)
       {
-      *erroroffset = p - string;
+      *erroroffset = (PCRE2_SIZE)(p - string);
       return PCRE2_ERROR_UTF32_ERR2;
       }
     }
   else
     {
     /* A surrogate */
-    *erroroffset = p - string;
+    *erroroffset = (PCRE2_SIZE)(p - string);
     return PCRE2_ERROR_UTF32_ERR1;
     }
   }

+ 36 - 17
thirdparty/pcre2/src/pcre2_xclass.c

@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
 
                        Written by Philip Hazel
      Original API code Copyright (c) 1997-2012 University of Cambridge
-          New API code Copyright (c) 2016-2022 University of Cambridge
+          New API code Copyright (c) 2016-2023 University of Cambridge
 
 -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without
@@ -133,6 +133,7 @@ while ((t = *data++) != XCL_END)
 #ifdef SUPPORT_UNICODE
   else  /* XCL_PROP & XCL_NOTPROP */
     {
+    int chartype;
     const ucd_record *prop = GET_UCD(c);
     BOOL isprop = t == XCL_PROP;
     BOOL ok;
@@ -144,8 +145,9 @@ while ((t = *data++) != XCL_END)
       break;
 
       case PT_LAMP:
-      if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
-           prop->chartype == ucp_Lt) == isprop) return !negated;
+      chartype = prop->chartype;
+      if ((chartype == ucp_Lu || chartype == ucp_Ll ||
+           chartype == ucp_Lt) == isprop) return !negated;
       break;
 
       case PT_GC:
@@ -168,8 +170,9 @@ while ((t = *data++) != XCL_END)
       break;
 
       case PT_ALNUM:
-      if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-           PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop)
+      chartype = prop->chartype;
+      if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+           PRIV(ucp_gentype)[chartype] == ucp_N) == isprop)
         return !negated;
       break;
 
@@ -194,9 +197,10 @@ while ((t = *data++) != XCL_END)
       break;
 
       case PT_WORD:
-      if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
-           PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE)
-             == isprop)
+      chartype = prop->chartype;
+      if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+           PRIV(ucp_gentype)[chartype] == ucp_N ||
+           chartype == ucp_Mn || chartype == ucp_Pc) == isprop)
         return !negated;
       break;
 
@@ -238,9 +242,10 @@ while ((t = *data++) != XCL_END)
       */
 
       case PT_PXGRAPH:
-      if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z &&
-            (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
-              (prop->chartype == ucp_Cf &&
+      chartype = prop->chartype;
+      if ((PRIV(ucp_gentype)[chartype] != ucp_Z &&
+            (PRIV(ucp_gentype)[chartype] != ucp_C ||
+              (chartype == ucp_Cf &&
                 c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069))
          )) == isprop)
         return !negated;
@@ -250,10 +255,11 @@ while ((t = *data++) != XCL_END)
       not Zl and not Zp, and U+180E. */
 
       case PT_PXPRINT:
-      if ((prop->chartype != ucp_Zl &&
-           prop->chartype != ucp_Zp &&
-            (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
-              (prop->chartype == ucp_Cf &&
+      chartype = prop->chartype;
+      if ((chartype != ucp_Zl &&
+           chartype != ucp_Zp &&
+            (PRIV(ucp_gentype)[chartype] != ucp_C ||
+              (chartype == ucp_Cf &&
                 c != 0x061c && (c < 0x2066 || c > 0x2069))
          )) == isprop)
         return !negated;
@@ -264,8 +270,21 @@ while ((t = *data++) != XCL_END)
       compatibility (these are $+<=>^`|~). */
 
       case PT_PXPUNCT:
-      if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P ||
-            (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop)
+      chartype = prop->chartype;
+      if ((PRIV(ucp_gentype)[chartype] == ucp_P ||
+            (c < 128 && PRIV(ucp_gentype)[chartype] == ucp_S)) == isprop)
+        return !negated;
+      break;
+
+      /* Perl has two sets of hex digits */
+
+      case PT_PXXDIGIT:
+      if (((c >= CHAR_0 && c <= CHAR_9) ||
+           (c >= CHAR_A && c <= CHAR_F) ||
+           (c >= CHAR_a && c <= CHAR_f) ||
+           (c >= 0xff10 && c <= 0xff19) ||  /* Fullwidth digits */
+           (c >= 0xff21 && c <= 0xff26) ||  /* Fullwidth letters */
+           (c >= 0xff41 && c <= 0xff46)) == isprop)
         return !negated;
       break;
 

+ 133 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c

@@ -0,0 +1,133 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+/*
+   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 or where MAP_JIT is
+   required.
+   On non-macOS systems, returns MAP_JIT if it is defined.
+*/
+#include <TargetConditionals.h>
+
+#if (defined(TARGET_OS_OSX) && TARGET_OS_OSX) || (TARGET_OS_MAC && !TARGET_OS_IPHONE)
+
+#if defined(SLJIT_CONFIG_X86) && SLJIT_CONFIG_X86
+
+#include <sys/utsname.h>
+#include <stdlib.h>
+
+#define SLJIT_MAP_JIT	(get_map_jit_flag())
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+
+static SLJIT_INLINE int get_map_jit_flag(void)
+{
+	size_t page_size;
+	void *ptr;
+	struct utsname name;
+	static int map_jit_flag = -1;
+
+	if (map_jit_flag < 0) {
+		map_jit_flag = 0;
+		uname(&name);
+
+		/* Kernel version for 10.14.0 (Mojave) or later */
+		if (atoi(name.release) >= 18) {
+			page_size = get_page_alignment() + 1;
+			/* 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);
+
+			if (ptr != MAP_FAILED)
+				munmap(ptr, page_size);
+			else
+				map_jit_flag = MAP_JIT;
+		}
+	}
+	return map_jit_flag;
+}
+
+#elif defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM
+
+#include <AvailabilityMacros.h>
+#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)
+{
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 110000
+	if (__builtin_available(macos 11, *))
+#endif /* BigSur */
+	pthread_jit_write_protect_np(enable_exec);
+}
+
+#elif defined(SLJIT_CONFIG_PPC) && SLJIT_CONFIG_PPC
+
+#define SLJIT_MAP_JIT	(0)
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+
+#else
+#error "Unsupported architecture"
+#endif /* SLJIT_CONFIG */
+
+#else /* !TARGET_OS_OSX */
+
+#ifdef MAP_JIT
+#define SLJIT_MAP_JIT	(MAP_JIT)
+#else
+#define SLJIT_MAP_JIT	(0)
+#endif
+
+#endif /* TARGET_OS_OSX */
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+	void *retval;
+	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+	int flags = MAP_PRIVATE;
+	int fd = -1;
+
+	flags |= MAP_ANON | SLJIT_MAP_JIT;
+
+	retval = mmap(NULL, size, prot, flags, fd, 0);
+	if (retval == MAP_FAILED)
+		return NULL;
+
+	SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0);
+
+	return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	munmap(chunk, size);
+}
+
+#include "sljitExecAllocatorCore.c"

+ 330 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c

@@ -0,0 +1,330 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   This file contains a simple executable memory allocator
+
+   It is assumed, that executable code blocks are usually medium (or sometimes
+   large) memory blocks, and the allocator is not too frequently called (less
+   optimized than other allocators). Thus, using it as a generic allocator is
+   not suggested.
+
+   How does it work:
+     Memory is allocated in continuous memory areas called chunks by alloc_chunk()
+     Chunk format:
+     [ block ][ block ] ... [ block ][ block terminator ]
+
+   All blocks and the block terminator is started with block_header. The block
+   header contains the size of the previous and the next block. These sizes
+   can also contain special values.
+     Block size:
+       0 - The block is a free_block, with a different size member.
+       1 - The block is a block terminator.
+       n - The block is used at the moment, and the value contains its size.
+     Previous block size:
+       0 - This is the first block of the memory chunk.
+       n - The size of the previous block.
+
+   Using these size values we can go forward or backward on the block chain.
+   The unused blocks are stored in a chain list pointed by free_blocks. This
+   list is useful if we need to find a suitable memory area when the allocator
+   is called.
+
+   When a block is freed, the new free block is connected to its adjacent free
+   blocks if possible.
+
+     [ free block ][ used block ][ free block ]
+   and "used block" is freed, the three blocks are connected together:
+     [           one big free block           ]
+*/
+
+/* Expected functions:
+     alloc_chunk / free_chunk :
+       * allocate executable system memory chunks
+       * the size is always divisible by CHUNK_SIZE
+     SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
+       * provided as part of sljitUtils
+       * only the allocator requires this lock, sljit is fully thread safe
+         as it only uses local variables
+
+   Supported defines:
+     SLJIT_HAS_CHUNK_HEADER - (optional) sljit_chunk_header is defined
+     SLJIT_HAS_EXECUTABLE_OFFSET - (optional) has executable offset data
+     SLJIT_UPDATE_WX_FLAGS - (optional) update WX flags
+*/
+
+#ifdef SLJIT_HAS_CHUNK_HEADER
+#define CHUNK_HEADER_SIZE (sizeof(struct sljit_chunk_header))
+#else /* !SLJIT_HAS_CHUNK_HEADER */
+#define CHUNK_HEADER_SIZE 0
+#endif /* SLJIT_HAS_CHUNK_HEADER */
+
+#ifndef SLJIT_UPDATE_WX_FLAGS
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+#endif /* SLJIT_UPDATE_WX_FLAGS */
+
+#ifndef CHUNK_SIZE
+/* 64 KByte if not specified. */
+#define CHUNK_SIZE	(sljit_uw)0x10000
+#endif /* CHUNK_SIZE */
+
+struct block_header {
+	sljit_uw size;
+	sljit_uw prev_size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+	sljit_sw executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+};
+
+struct free_block {
+	struct block_header header;
+	struct free_block *next;
+	struct free_block *prev;
+	sljit_uw size;
+};
+
+#define AS_BLOCK_HEADER(base, offset) \
+	((struct block_header*)(((sljit_u8*)base) + offset))
+#define AS_FREE_BLOCK(base, offset) \
+	((struct free_block*)(((sljit_u8*)base) + offset))
+#define MEM_START(base)		((void*)((base) + 1))
+#define CHUNK_MASK		(~(CHUNK_SIZE - 1))
+#define ALIGN_SIZE(size)	(((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7)
+#define CHUNK_EXTRA_SIZE	(sizeof(struct block_header) + CHUNK_HEADER_SIZE)
+
+static struct free_block* free_blocks;
+static sljit_uw allocated_size;
+static sljit_uw total_size;
+
+static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
+{
+	free_block->header.size = 0;
+	free_block->size = size;
+
+	free_block->next = free_blocks;
+	free_block->prev = NULL;
+	if (free_blocks)
+		free_blocks->prev = free_block;
+	free_blocks = free_block;
+}
+
+static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
+{
+	if (free_block->next)
+		free_block->next->prev = free_block->prev;
+
+	if (free_block->prev)
+		free_block->prev->next = free_block->next;
+	else {
+		SLJIT_ASSERT(free_blocks == free_block);
+		free_blocks = free_block->next;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+	struct block_header *header;
+	struct block_header *next_header;
+	struct free_block *free_block;
+	sljit_uw chunk_size;
+
+#ifdef SLJIT_HAS_CHUNK_HEADER
+	struct sljit_chunk_header *chunk_header;
+#else /* !SLJIT_HAS_CHUNK_HEADER */
+	void *chunk_header;
+#endif /* SLJIT_HAS_CHUNK_HEADER */
+
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+	sljit_sw executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+
+	if (size < (64 - sizeof(struct block_header)))
+		size = (64 - sizeof(struct block_header));
+	size = ALIGN_SIZE(size);
+
+	SLJIT_ALLOCATOR_LOCK();
+	free_block = free_blocks;
+	while (free_block) {
+		if (free_block->size >= size) {
+			chunk_size = free_block->size;
+			SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
+			if (chunk_size > size + 64) {
+				/* We just cut a block from the end of the free block. */
+				chunk_size -= size;
+				free_block->size = chunk_size;
+				header = AS_BLOCK_HEADER(free_block, chunk_size);
+				header->prev_size = chunk_size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+				header->executable_offset = free_block->header.executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+				AS_BLOCK_HEADER(header, size)->prev_size = size;
+			}
+			else {
+				sljit_remove_free_block(free_block);
+				header = (struct block_header*)free_block;
+				size = chunk_size;
+			}
+			allocated_size += size;
+			header->size = size;
+			SLJIT_ALLOCATOR_UNLOCK();
+			return MEM_START(header);
+		}
+		free_block = free_block->next;
+	}
+
+	chunk_size = (size + CHUNK_EXTRA_SIZE + CHUNK_SIZE - 1) & CHUNK_MASK;
+
+	chunk_header = alloc_chunk(chunk_size);
+	if (!chunk_header) {
+		SLJIT_ALLOCATOR_UNLOCK();
+		return NULL;
+	}
+
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+	executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header);
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+
+	chunk_size -= CHUNK_EXTRA_SIZE;
+	total_size += chunk_size;
+
+	header = (struct block_header*)(((sljit_u8*)chunk_header) + CHUNK_HEADER_SIZE);
+
+	header->prev_size = 0;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+	header->executable_offset = executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+
+	if (chunk_size > size + 64) {
+		/* Cut the allocated space into a free and a used block. */
+		allocated_size += size;
+		header->size = size;
+		chunk_size -= size;
+
+		free_block = AS_FREE_BLOCK(header, size);
+		free_block->header.prev_size = size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+		free_block->header.executable_offset = executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+		sljit_insert_free_block(free_block, chunk_size);
+		next_header = AS_BLOCK_HEADER(free_block, chunk_size);
+	}
+	else {
+		/* All space belongs to this allocation. */
+		allocated_size += chunk_size;
+		header->size = chunk_size;
+		next_header = AS_BLOCK_HEADER(header, chunk_size);
+	}
+	SLJIT_ALLOCATOR_UNLOCK();
+	next_header->size = 1;
+	next_header->prev_size = chunk_size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+	next_header->executable_offset = executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+	return MEM_START(header);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	struct block_header *header;
+	struct free_block* free_block;
+
+	SLJIT_ALLOCATOR_LOCK();
+	header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+	header = AS_BLOCK_HEADER(header, -header->executable_offset);
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+	allocated_size -= header->size;
+
+	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
+
+	/* Connecting free blocks together if possible. */
+
+	/* If header->prev_size == 0, free_block will equal to header.
+	   In this case, free_block->header.size will be > 0. */
+	free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
+	if (SLJIT_UNLIKELY(!free_block->header.size)) {
+		free_block->size += header->size;
+		header = AS_BLOCK_HEADER(free_block, free_block->size);
+		header->prev_size = free_block->size;
+	}
+	else {
+		free_block = (struct free_block*)header;
+		sljit_insert_free_block(free_block, header->size);
+	}
+
+	header = AS_BLOCK_HEADER(free_block, free_block->size);
+	if (SLJIT_UNLIKELY(!header->size)) {
+		free_block->size += ((struct free_block*)header)->size;
+		sljit_remove_free_block((struct free_block*)header);
+		header = AS_BLOCK_HEADER(free_block, free_block->size);
+		header->prev_size = free_block->size;
+	}
+
+	/* The whole chunk is free. */
+	if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
+		/* If this block is freed, we still have (allocated_size / 2) free space. */
+		if (total_size - free_block->size > (allocated_size * 3 / 2)) {
+			total_size -= free_block->size;
+			sljit_remove_free_block(free_block);
+			free_chunk(free_block, free_block->size + CHUNK_EXTRA_SIZE);
+		}
+	}
+
+	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
+	SLJIT_ALLOCATOR_UNLOCK();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+	struct free_block* free_block;
+	struct free_block* next_free_block;
+
+	SLJIT_ALLOCATOR_LOCK();
+	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
+
+	free_block = free_blocks;
+	while (free_block) {
+		next_free_block = free_block->next;
+		if (!free_block->header.prev_size && 
+				AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
+			total_size -= free_block->size;
+			sljit_remove_free_block(free_block);
+			free_chunk(free_block, free_block->size + CHUNK_EXTRA_SIZE);
+		}
+		free_block = next_free_block;
+	}
+
+	SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
+	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
+	SLJIT_ALLOCATOR_UNLOCK();
+}
+
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr)
+{
+	return ((struct block_header *)(ptr))[-1].executable_offset;
+}
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */

+ 89 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c

@@ -0,0 +1,89 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/mman.h>
+#include <sys/procctl.h>
+
+#ifdef PROC_WXMAP_CTL
+static SLJIT_INLINE int sljit_is_wx_block(void)
+{
+	static int wx_block = -1;
+	if (wx_block < 0) {
+		int sljit_wx_enable = PROC_WX_MAPPINGS_PERMIT;
+		wx_block = !!procctl(P_PID, 0, PROC_WXMAP_CTL, &sljit_wx_enable);
+	}
+	return wx_block;
+}
+
+#define SLJIT_IS_WX_BLOCK sljit_is_wx_block()
+#else /* !PROC_WXMAP_CTL */
+#define SLJIT_IS_WX_BLOCK (1)
+#endif /* PROC_WXMAP_CTL */
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+	void *retval;
+	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+	int flags = MAP_PRIVATE;
+	int fd = -1;
+
+#ifdef PROT_MAX
+	prot |= PROT_MAX(prot);
+#endif
+
+#ifdef MAP_ANON
+	flags |= MAP_ANON;
+#else /* !MAP_ANON */
+	if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
+		return NULL;
+
+	fd = dev_zero;
+#endif /* MAP_ANON */
+
+retry:
+	retval = mmap(NULL, size, prot, flags, fd, 0);
+	if (retval == MAP_FAILED) {
+		if (!SLJIT_IS_WX_BLOCK)
+			goto retry;
+
+		return NULL;
+	}
+
+	/* HardenedBSD's mmap lies, so check permissions again. */
+	if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
+		munmap(retval, size);
+		return NULL;
+	}
+
+	return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	munmap(chunk, size);
+}
+
+#include "sljitExecAllocatorCore.c"

+ 62 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c

@@ -0,0 +1,62 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+	void *retval;
+	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+	int flags = MAP_PRIVATE;
+	int fd = -1;
+
+#ifdef PROT_MAX
+	prot |= PROT_MAX(prot);
+#endif
+
+#ifdef MAP_ANON
+	flags |= MAP_ANON;
+#else /* !MAP_ANON */
+	if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
+		return NULL;
+
+	fd = dev_zero;
+#endif /* MAP_ANON */
+
+	retval = mmap(NULL, size, prot, flags, fd, 0);
+	if (retval == MAP_FAILED)
+		return NULL;
+
+	return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	munmap(chunk, size);
+}
+
+#include "sljitExecAllocatorCore.c"

+ 40 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c

@@ -0,0 +1,40 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+	return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	SLJIT_UNUSED_ARG(size);
+	VirtualFree(chunk, 0, MEM_RELEASE);
+}
+
+#include "sljitExecAllocatorCore.c"

+ 72 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c

@@ -0,0 +1,72 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define SLJIT_HAS_CHUNK_HEADER
+#define SLJIT_HAS_EXECUTABLE_OFFSET
+
+struct sljit_chunk_header {
+	void *executable;
+};
+
+/*
+ * MAP_REMAPDUP is a NetBSD extension available sinde 8.0, make sure to
+ * adjust your feature macros (ex: -D_NETBSD_SOURCE) as needed
+ */
+static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size)
+{
+	struct sljit_chunk_header *retval;
+
+	retval = (struct sljit_chunk_header *)mmap(NULL, size,
+			PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC),
+			MAP_ANON | MAP_SHARED, -1, 0);
+
+	if (retval == MAP_FAILED)
+		return NULL;
+
+	retval->executable = mremap(retval, size, NULL, size, MAP_REMAPDUP);
+	if (retval->executable == MAP_FAILED) {
+		munmap((void *)retval, size);
+		return NULL;
+	}
+
+	if (mprotect(retval->executable, size, PROT_READ | PROT_EXEC) == -1) {
+		munmap(retval->executable, size);
+		munmap((void *)retval, size);
+		return NULL;
+	}
+
+	return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1;
+
+	munmap(header->executable, size);
+	munmap((void *)header, size);
+}
+
+#include "sljitExecAllocatorCore.c"

+ 172 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c

@@ -0,0 +1,172 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define SLJIT_HAS_CHUNK_HEADER
+#define SLJIT_HAS_EXECUTABLE_OFFSET
+
+struct sljit_chunk_header {
+	void *executable;
+};
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef O_NOATIME
+#define O_NOATIME 0
+#endif
+
+/* this is a linux extension available since kernel 3.11 */
+#ifndef O_TMPFILE
+#define O_TMPFILE 0x404000
+#endif
+
+#ifndef _GNU_SOURCE
+char *secure_getenv(const char *name);
+int mkostemp(char *template, int flags);
+#endif
+
+static SLJIT_INLINE int create_tempfile(void)
+{
+	int fd;
+	char tmp_name[256];
+	size_t tmp_name_len = 0;
+	char *dir;
+	struct stat st;
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+	mode_t mode;
+#endif
+
+#ifdef HAVE_MEMFD_CREATE
+	/* this is a GNU extension, make sure to use -D_GNU_SOURCE */
+	fd = memfd_create("sljit", MFD_CLOEXEC);
+	if (fd != -1) {
+		fchmod(fd, 0);
+		return fd;
+	}
+#endif
+
+	dir = secure_getenv("TMPDIR");
+
+	if (dir) {
+		size_t len = strlen(dir);
+		if (len > 0 && len < sizeof(tmp_name)) {
+			if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode)) {
+				memcpy(tmp_name, dir, len + 1);
+				tmp_name_len = len;
+			}
+		}
+	}
+
+#ifdef P_tmpdir
+	if (!tmp_name_len) {
+		tmp_name_len = strlen(P_tmpdir);
+		if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name))
+			strcpy(tmp_name, P_tmpdir);
+	}
+#endif
+	if (!tmp_name_len) {
+		strcpy(tmp_name, "/tmp");
+		tmp_name_len = 4;
+	}
+
+	SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
+
+	if (tmp_name_len > 1 && tmp_name[tmp_name_len - 1] == '/')
+		tmp_name[--tmp_name_len] = '\0';
+
+	fd = open(tmp_name, O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0);
+	if (fd != -1)
+		return fd;
+
+	if (tmp_name_len >= sizeof(tmp_name) - 7)
+		return -1;
+
+	strcpy(tmp_name + tmp_name_len, "/XXXXXX");
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+	mode = umask(0777);
+#endif
+	fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+	umask(mode);
+#else
+	fchmod(fd, 0);
+#endif
+
+	if (fd == -1)
+		return -1;
+
+	if (unlink(tmp_name)) {
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size)
+{
+	struct sljit_chunk_header *retval;
+	int fd;
+
+	fd = create_tempfile();
+	if (fd == -1)
+		return NULL;
+
+	if (ftruncate(fd, (off_t)size)) {
+		close(fd);
+		return NULL;
+	}
+
+	retval = (struct sljit_chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+	if (retval == MAP_FAILED) {
+		close(fd);
+		return NULL;
+	}
+
+	retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
+
+	if (retval->executable == MAP_FAILED) {
+		munmap((void *)retval, size);
+		close(fd);
+		return NULL;
+	}
+
+	close(fd);
+	return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1;
+
+	munmap(header->executable, size);
+	munmap((void *)header, size);
+}
+
+#include "sljitExecAllocatorCore.c"

+ 141 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c

@@ -0,0 +1,141 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   This file contains a simple W^X executable memory allocator
+
+   In *NIX, MAP_ANON is required (that is considered a feature) so make
+   sure to set the right availability macros for your system or the code
+   will fail to build.
+
+   If your system doesn't support mapping of anonymous pages (ex: IRIX) it
+   is also likely that it doesn't need this allocator and should be using
+   the standard one instead.
+
+   It allocates a separate map for each code block and may waste a lot of
+   memory, because whatever was requested, will be rounded up to the page
+   size (minimum 4KB, but could be even bigger).
+
+   It changes the page permissions (RW <-> RX) as needed and therefore, if you
+   will be updating the code after it has been generated, need to make sure to
+   block any concurrent execution, or could result in a SIGBUS, that could
+   even manifest itself at a different address than the one that was being
+   modified.
+
+   Only use if you are unable to use the regular allocator because of security
+   restrictions and adding exceptions to your application or the system are
+   not possible.
+*/
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+	sljit_update_wx_flags((from), (to), (enable_exec))
+
+#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+#include <pthread.h>
+#define SLJIT_SE_LOCK()		pthread_mutex_lock(&se_lock)
+#define SLJIT_SE_UNLOCK()	pthread_mutex_unlock(&se_lock)
+#else
+#define SLJIT_SE_LOCK()
+#define SLJIT_SE_UNLOCK()
+#endif /* !SLJIT_SINGLE_THREADED */
+
+#define SLJIT_WX_IS_BLOCK(ptr, size) generic_check_is_wx_block(ptr, size)
+
+static SLJIT_INLINE int generic_check_is_wx_block(void *ptr, sljit_uw size)
+{
+	if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC)))
+		return !!mprotect(ptr, size, PROT_READ | PROT_WRITE);
+
+	return 1;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+	static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+	static int wx_block = -1;
+	int prot = PROT_READ | PROT_WRITE;
+	sljit_uw* ptr;
+
+	if (SLJIT_UNLIKELY(wx_block > 0))
+		return NULL;
+
+#ifdef PROT_MAX
+	prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
+#endif
+
+	size += sizeof(sljit_uw);
+	ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+
+	if (ptr == MAP_FAILED)
+		return NULL;
+
+	if (SLJIT_UNLIKELY(wx_block < 0)) {
+		SLJIT_SE_LOCK();
+		wx_block = SLJIT_WX_IS_BLOCK(ptr, size);
+		SLJIT_SE_UNLOCK();
+		if (SLJIT_UNLIKELY(wx_block)) {
+			munmap((void *)ptr, size);
+			return NULL;
+		}
+	}
+
+	*ptr++ = size;
+	return ptr;
+}
+
+#undef SLJIT_SE_UNLOCK
+#undef SLJIT_SE_LOCK
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1;
+	munmap((void*)start_ptr, *start_ptr);
+}
+
+static void sljit_update_wx_flags(void *from, void *to, int enable_exec)
+{
+	sljit_uw page_mask = (sljit_uw)get_page_alignment();
+	sljit_uw start = (sljit_uw)from;
+	sljit_uw end = (sljit_uw)to;
+	int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
+
+	SLJIT_ASSERT(start < end);
+
+	start &= ~page_mask;
+	end = (end + page_mask) & ~page_mask;
+
+	mprotect((void*)start, end - start, prot);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+	/* This allocator does not keep unused memory for future allocations. */
+}

+ 102 - 0
thirdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c

@@ -0,0 +1,102 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   This file contains a simple W^X executable memory allocator
+
+   In *NIX, MAP_ANON is required (that is considered a feature) so make
+   sure to set the right availability macros for your system or the code
+   will fail to build.
+
+   If your system doesn't support mapping of anonymous pages (ex: IRIX) it
+   is also likely that it doesn't need this allocator and should be using
+   the standard one instead.
+
+   It allocates a separate map for each code block and may waste a lot of
+   memory, because whatever was requested, will be rounded up to the page
+   size (minimum 4KB, but could be even bigger).
+
+   It changes the page permissions (RW <-> RX) as needed and therefore, if you
+   will be updating the code after it has been generated, need to make sure to
+   block any concurrent execution, or could result in a SIGBUS, that could
+   even manifest itself at a different address than the one that was being
+   modified.
+
+   Only use if you are unable to use the regular allocator because of security
+   restrictions and adding exceptions to your application or the system are
+   not possible.
+*/
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+	sljit_update_wx_flags((from), (to), (enable_exec))
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+	sljit_uw *ptr;
+
+	size += sizeof(sljit_uw);
+	ptr = (sljit_uw*)VirtualAlloc(NULL, size,
+				MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+
+	if (!ptr)
+		return NULL;
+
+	*ptr++ = size;
+
+	return ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw);
+#if defined(SLJIT_DEBUG) && SLJIT_DEBUG
+	sljit_uw page_mask = (sljit_uw)get_page_alignment();
+
+	SLJIT_ASSERT(!(start & page_mask));
+#endif
+	VirtualFree((void*)start, 0, MEM_RELEASE);
+}
+
+static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
+{
+	DWORD oldprot;
+	sljit_uw page_mask = (sljit_uw)get_page_alignment();
+	sljit_uw start = (sljit_uw)from;
+	sljit_uw end = (sljit_uw)to;
+	DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE;
+
+	SLJIT_ASSERT(start < end);
+
+	start &= ~page_mask;
+	end = (end + page_mask) & ~page_mask;
+
+	VirtualProtect((void*)start, end - start, prot, &oldprot);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+	/* This allocator does not keep unused memory for future allocations. */
+}

+ 3 - 23
thirdparty/pcre2/src/sljit/sljitConfig.h

@@ -38,28 +38,6 @@ extern "C" {
   non-zero value.
 */
 
-/* --------------------------------------------------------------------- */
-/*  Architecture                                                         */
-/* --------------------------------------------------------------------- */
-
-/* Architecture selection. */
-/* #define SLJIT_CONFIG_X86_32 1 */
-/* #define SLJIT_CONFIG_X86_64 1 */
-/* #define SLJIT_CONFIG_ARM_V5 1 */
-/* #define SLJIT_CONFIG_ARM_V7 1 */
-/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
-/* #define SLJIT_CONFIG_ARM_64 1 */
-/* #define SLJIT_CONFIG_PPC_32 1 */
-/* #define SLJIT_CONFIG_PPC_64 1 */
-/* #define SLJIT_CONFIG_MIPS_32 1 */
-/* #define SLJIT_CONFIG_MIPS_64 1 */
-/* #define SLJIT_CONFIG_RISCV_32 1 */
-/* #define SLJIT_CONFIG_RISCV_64 1 */
-/* #define SLJIT_CONFIG_S390X 1 */
-
-/* #define SLJIT_CONFIG_AUTO 1 */
-/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
-
 /* --------------------------------------------------------------------- */
 /*  Utilities                                                            */
 /* --------------------------------------------------------------------- */
@@ -96,7 +74,9 @@ extern "C" {
 
 /* Executable code allocation:
    If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
-   define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
+   define SLJIT_MALLOC_EXEC and SLJIT_FREE_EXEC.
+   Optionally, depending on the implementation used for the allocator,
+   SLJIT_EXEC_OFFSET and SLJIT_UPDATE_WX_FLAGS might also be needed. */
 #ifndef SLJIT_EXECUTABLE_ALLOCATOR
 /* Enabled by default. */
 #define SLJIT_EXECUTABLE_ALLOCATOR 1

+ 188 - 0
thirdparty/pcre2/src/sljit/sljitConfigCPU.h

@@ -0,0 +1,188 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SLJIT_CONFIG_CPU_H_
+#define SLJIT_CONFIG_CPU_H_
+
+/* --------------------------------------------------------------------- */
+/*  Architecture                                                         */
+/* --------------------------------------------------------------------- */
+
+/* Architecture selection. */
+/* #define SLJIT_CONFIG_X86_32 1 */
+/* #define SLJIT_CONFIG_X86_64 1 */
+/* #define SLJIT_CONFIG_ARM_V6 1 */
+/* #define SLJIT_CONFIG_ARM_V7 1 */
+/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
+/* #define SLJIT_CONFIG_ARM_64 1 */
+/* #define SLJIT_CONFIG_PPC_32 1 */
+/* #define SLJIT_CONFIG_PPC_64 1 */
+/* #define SLJIT_CONFIG_MIPS_32 1 */
+/* #define SLJIT_CONFIG_MIPS_64 1 */
+/* #define SLJIT_CONFIG_RISCV_32 1 */
+/* #define SLJIT_CONFIG_RISCV_64 1 */
+/* #define SLJIT_CONFIG_S390X 1 */
+/* #define SLJIT_CONFIG_LOONGARCH_64 */
+
+/* #define SLJIT_CONFIG_AUTO 1 */
+/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
+
+/*****************/
+/* Sanity check. */
+/*****************/
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+	+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+	+ (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) \
+	+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+	+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+	+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+	+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+	+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+	+ (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
+	+ (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
+	+ (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+	+ (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) \
+	+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
+	+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
+#error "Multiple architectures are selected"
+#endif
+
+#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+	&& !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+	&& !(defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) \
+	&& !(defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	&& !(defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+	&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	&& !(defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+	&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+	&& !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+	&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+	&& !(defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
+	&& !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
+	&& !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+	&& !(defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) \
+	&& !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) \
+	&& !(defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
+#if defined SLJIT_CONFIG_AUTO && !SLJIT_CONFIG_AUTO
+#error "An architecture must be selected"
+#else /* SLJIT_CONFIG_AUTO */
+#define SLJIT_CONFIG_AUTO 1
+#endif /* !SLJIT_CONFIG_AUTO */
+#endif /* !SLJIT_CONFIG */
+
+/********************************************************/
+/* Automatic CPU detection (requires compiler support). */
+/********************************************************/
+
+#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
+#ifndef _WIN32
+
+#if defined(__i386__) || defined(__i386)
+#define SLJIT_CONFIG_X86_32 1
+#elif defined(__x86_64__)
+#define SLJIT_CONFIG_X86_64 1
+#elif defined(__aarch64__)
+#define SLJIT_CONFIG_ARM_64 1
+#elif defined(__thumb2__)
+#define SLJIT_CONFIG_ARM_THUMB2 1
+#elif (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \
+	((defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7S__)) \
+	 || (defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH_8R__)) \
+	 || (defined(__ARM_ARCH_9A__)))
+#define SLJIT_CONFIG_ARM_V7 1
+#elif defined(__arm__) || defined (__ARM__)
+#define SLJIT_CONFIG_ARM_V6 1
+#elif defined(__ppc64__) || defined(__powerpc64__) || (defined(_ARCH_PPC64) && defined(__64BIT__)) || (defined(_POWER) && defined(__64BIT__))
+#define SLJIT_CONFIG_PPC_64 1
+#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
+#define SLJIT_CONFIG_PPC_32 1
+#elif defined(__mips__) && !defined(_LP64)
+#define SLJIT_CONFIG_MIPS_32 1
+#elif defined(__mips64)
+#define SLJIT_CONFIG_MIPS_64 1
+#elif defined (__riscv_xlen) && (__riscv_xlen == 32)
+#define SLJIT_CONFIG_RISCV_32 1
+#elif defined (__riscv_xlen) && (__riscv_xlen == 64)
+#define SLJIT_CONFIG_RISCV_64 1
+#elif defined (__loongarch_lp64)
+#define SLJIT_CONFIG_LOONGARCH_64 1
+#elif defined(__s390x__)
+#define SLJIT_CONFIG_S390X 1
+#else
+/* Unsupported architecture */
+#define SLJIT_CONFIG_UNSUPPORTED 1
+#endif
+
+#else /* _WIN32 */
+
+#if defined(_M_X64) || defined(__x86_64__)
+#define SLJIT_CONFIG_X86_64 1
+#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__)
+#define SLJIT_CONFIG_ARM_THUMB2 1
+#elif (defined(_M_ARM) && _M_ARM >= 7)
+#define SLJIT_CONFIG_ARM_V7 1
+#elif defined(_ARM_)
+#define SLJIT_CONFIG_ARM_V6 1
+#elif defined(_M_ARM64) || defined(__aarch64__)
+#define SLJIT_CONFIG_ARM_64 1
+#else
+#define SLJIT_CONFIG_X86_32 1
+#endif
+
+#endif /* !_WIN32 */
+#endif /* SLJIT_CONFIG_AUTO */
+
+#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+#undef SLJIT_EXECUTABLE_ALLOCATOR
+#endif /* SLJIT_CONFIG_UNSUPPORTED */
+
+/******************************/
+/* CPU family type detection. */
+/******************************/
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#define SLJIT_CONFIG_ARM_32 1
+#endif
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+#define SLJIT_CONFIG_X86 1
+#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+#define SLJIT_CONFIG_ARM 1
+#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define SLJIT_CONFIG_PPC 1
+#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+#define SLJIT_CONFIG_MIPS 1
+#elif (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) || (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+#define SLJIT_CONFIG_RISCV 1
+#elif (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64)
+#define SLJIT_CONFIG_LOONGARCH 1
+#endif
+
+#endif /* SLJIT_CONFIG_CPU_H_ */

+ 184 - 154
thirdparty/pcre2/src/sljit/sljitConfigInternal.h

@@ -61,6 +61,8 @@ extern "C" {
      SLJIT_BIG_ENDIAN : big endian architecture
      SLJIT_UNALIGNED : unaligned memory accesses for non-fpu operations are supported
      SLJIT_FPU_UNALIGNED : unaligned memory accesses for fpu operations are supported
+     SLJIT_MASKED_SHIFT : all word shifts are always masked
+     SLJIT_MASKED_SHIFT32 : all 32 bit shifts are always masked
      SLJIT_INDIRECT_CALL : see SLJIT_FUNC_ADDR() for more information
 
    Constants:
@@ -70,6 +72,8 @@ extern "C" {
      SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
      SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
      SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
+     SLJIT_NUMBER_OF_TEMPORARY_REGISTERS : number of available temporary registers
+     SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS : number of available temporary floating point registers
      SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
      SLJIT_F32_SHIFT : the shift required to apply when accessing
                        a single precision floating point array by index
@@ -79,141 +83,27 @@ extern "C" {
                             the scratch register index of ecx is stored in this variable
      SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
      SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
+     SLJIT_CONV_MAX_FLOAT : result when a floating point value is converted to integer
+                            and the floating point value is higher than the maximum integer value
+                            (possible values: SLJIT_CONV_RESULT_MAX_INT or SLJIT_CONV_RESULT_MIN_INT)
+     SLJIT_CONV_MIN_FLOAT : result when a floating point value is converted to integer
+                            and the floating point value is lower than the minimum integer value
+                            (possible values: SLJIT_CONV_RESULT_MAX_INT or SLJIT_CONV_RESULT_MIN_INT)
+     SLJIT_CONV_NAN_FLOAT : result when a NaN floating point value is converted to integer
+                            (possible values: SLJIT_CONV_RESULT_MAX_INT, SLJIT_CONV_RESULT_MIN_INT,
+                            or SLJIT_CONV_RESULT_ZERO)
 
    Other macros:
+     SLJIT_TMP_R0 .. R9 : accessing temporary registers
+     SLJIT_TMP_R(i) : accessing temporary registers
+     SLJIT_TMP_FR0 .. FR9 : accessing temporary floating point registers
+     SLJIT_TMP_FR(i) : accessing temporary floating point registers
      SLJIT_FUNC : calling convention attribute for both calling JIT from C and C calling back from JIT
      SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (platform independent helper)
+     SLJIT_F64_SECOND(reg) : provides the register index of the second 32 bit part of a 64 bit
+                             floating point register when SLJIT_HAS_F64_AS_F32_PAIR returns non-zero
 */
 
-/*****************/
-/* Sanity check. */
-/*****************/
-
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
-	+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
-	+ (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
-	+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
-	+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
-	+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
-	+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
-	+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
-	+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
-	+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
-	+ (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
-	+ (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
-	+ (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
-	+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
-	+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
-#error "Multiple architectures are selected"
-#endif
-
-#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
-	&& !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
-	&& !(defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
-	&& !(defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
-	&& !(defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
-	&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
-	&& !(defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
-	&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
-	&& !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
-	&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
-	&& !(defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
-	&& !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
-	&& !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
-	&& !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) \
-	&& !(defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
-#if defined SLJIT_CONFIG_AUTO && !SLJIT_CONFIG_AUTO
-#error "An architecture must be selected"
-#else /* SLJIT_CONFIG_AUTO */
-#define SLJIT_CONFIG_AUTO 1
-#endif /* !SLJIT_CONFIG_AUTO */
-#endif /* !SLJIT_CONFIG */
-
-/********************************************************/
-/* Automatic CPU detection (requires compiler support). */
-/********************************************************/
-
-#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
-
-#ifndef _WIN32
-
-#if defined(__i386__) || defined(__i386)
-#define SLJIT_CONFIG_X86_32 1
-#elif defined(__x86_64__)
-#define SLJIT_CONFIG_X86_64 1
-#elif defined(__arm__) || defined(__ARM__)
-#ifdef __thumb2__
-#define SLJIT_CONFIG_ARM_THUMB2 1
-#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
-#define SLJIT_CONFIG_ARM_V7 1
-#else
-#define SLJIT_CONFIG_ARM_V5 1
-#endif
-#elif defined (__aarch64__)
-#define SLJIT_CONFIG_ARM_64 1
-#elif defined(__ppc64__) || defined(__powerpc64__) || (defined(_ARCH_PPC64) && defined(__64BIT__)) || (defined(_POWER) && defined(__64BIT__))
-#define SLJIT_CONFIG_PPC_64 1
-#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
-#define SLJIT_CONFIG_PPC_32 1
-#elif defined(__mips__) && !defined(_LP64)
-#define SLJIT_CONFIG_MIPS_32 1
-#elif defined(__mips64)
-#define SLJIT_CONFIG_MIPS_64 1
-#elif defined (__riscv_xlen) && (__riscv_xlen == 32)
-#define SLJIT_CONFIG_RISCV_32 1
-#elif defined (__riscv_xlen) && (__riscv_xlen == 64)
-#define SLJIT_CONFIG_RISCV_64 1
-#elif defined(__s390x__)
-#define SLJIT_CONFIG_S390X 1
-#else
-/* Unsupported architecture */
-#define SLJIT_CONFIG_UNSUPPORTED 1
-#endif
-
-#else /* _WIN32 */
-
-#if defined(_M_X64) || defined(__x86_64__)
-#define SLJIT_CONFIG_X86_64 1
-#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__)
-#define SLJIT_CONFIG_ARM_THUMB2 1
-#elif (defined(_M_ARM) && _M_ARM >= 7)
-#define SLJIT_CONFIG_ARM_V7 1
-#elif defined(_ARM_)
-#define SLJIT_CONFIG_ARM_V5 1
-#elif defined(_M_ARM64) || defined(__aarch64__)
-#define SLJIT_CONFIG_ARM_64 1
-#else
-#define SLJIT_CONFIG_X86_32 1
-#endif
-
-#endif /* !_WIN32 */
-#endif /* SLJIT_CONFIG_AUTO */
-
-#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
-#undef SLJIT_EXECUTABLE_ALLOCATOR
-#endif
-
-/******************************/
-/* CPU family type detection. */
-/******************************/
-
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
-	|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
-#define SLJIT_CONFIG_ARM_32 1
-#endif
-
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
-#define SLJIT_CONFIG_X86 1
-#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
-#define SLJIT_CONFIG_ARM 1
-#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-#define SLJIT_CONFIG_PPC 1
-#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
-#define SLJIT_CONFIG_MIPS 1
-#elif (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) || (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-#define SLJIT_CONFIG_RISCV 1
-#endif
-
 /***********************************************************/
 /* Intel Control-flow Enforcement Technology (CET) spport. */
 /***********************************************************/
@@ -328,6 +218,10 @@ extern "C" {
 /* Instruction cache flush. */
 /****************************/
 
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+#endif
+
 /*
  * TODO:
  *
@@ -368,7 +262,7 @@ extern "C" {
 /* Not required to implement on archs with unified caches. */
 #define SLJIT_CACHE_FLUSH(from, to)
 
-#elif defined __APPLE__
+#elif defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
 
 /* Supported by all macs since Mac OS 10.5.
    However, it does not work on non-jailbroken iOS devices,
@@ -433,14 +327,15 @@ typedef signed int sljit_s32;
 #if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
 /* Just to have something. */
 #define SLJIT_WORD_SHIFT 0
-typedef unsigned long int sljit_uw;
-typedef long int sljit_sw;
+typedef unsigned int sljit_uw;
+typedef int sljit_sw;
 #elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
 	&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
 	&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
 	&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
 	&& !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
-	&& !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+	&& !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+	&& !(defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64)
 #define SLJIT_32BIT_ARCHITECTURE 1
 #define SLJIT_WORD_SHIFT 2
 typedef unsigned int sljit_uw;
@@ -476,12 +371,42 @@ typedef double sljit_f64;
 #define SLJIT_F32_SHIFT 2
 #define SLJIT_F64_SHIFT 3
 
+#define SLJIT_CONV_RESULT_MAX_INT 0
+#define SLJIT_CONV_RESULT_MIN_INT 1
+#define SLJIT_CONV_RESULT_ZERO 2
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#elif (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_ZERO
+#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#elif (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#else
+#error "Result for float to integer conversion is not defined"
+#endif
+
 #ifndef SLJIT_W
 
 /* Defining long constants. */
-#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
-#define SLJIT_W(w)	(w##l)
-#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
 #ifdef _WIN64
 #define SLJIT_W(w)	(w##ll)
 #else /* !windows */
@@ -521,9 +446,10 @@ typedef double sljit_f64;
 /* Auto detecting mips revision. */
 #if (defined __mips_isa_rev) && (__mips_isa_rev >= 6)
 #define SLJIT_MIPS_REV 6
-#elif (defined __mips_isa_rev && __mips_isa_rev >= 1) \
-	|| (defined __clang__ && defined _MIPS_ARCH_OCTEON) \
-	|| (defined __clang__ && defined _MIPS_ARCH_P5600)
+#elif defined(__mips_isa_rev) && __mips_isa_rev >= 1
+#define SLJIT_MIPS_REV __mips_isa_rev
+#elif defined(__clang__) \
+	&& (defined(_MIPS_ARCH_OCTEON) || defined(_MIPS_ARCH_P5600))
 /* clang either forgets to define (clang-7) __mips_isa_rev at all
  * or sets it to zero (clang-8,-9) for -march=octeon (MIPS64 R2+)
  * and -march=p5600 (MIPS32 R5).
@@ -562,7 +488,8 @@ typedef double sljit_f64;
 	|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
 	|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
 	|| (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
-	|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+	|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+	|| (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
 #define SLJIT_UNALIGNED 1
 #endif
 
@@ -574,7 +501,8 @@ typedef double sljit_f64;
 	|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
 	|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
 	|| (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
-	|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+	|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+	|| (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
 #define SLJIT_FPU_UNALIGNED 1
 #endif
 
@@ -594,6 +522,19 @@ typedef double sljit_f64;
 #define SLJIT_FUNC
 #endif /* !SLJIT_FUNC */
 
+/* Disable instrumentation for these functions as they may not be sound */
+#ifndef SLJIT_FUNC_ATTRIBUTE
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define SLJIT_FUNC_ATTRIBUTE __attribute__((no_sanitize("memory")))
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+#endif
+
+#ifndef SLJIT_FUNC_ATTRIBUTE
+#define SLJIT_FUNC_ATTRIBUTE
+#endif
+
 #ifndef SLJIT_INDIRECT_CALL
 #if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (!defined _CALL_ELF || _CALL_ELF == 1)) \
 	|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
@@ -631,12 +572,14 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
 #if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
 SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 #define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
-#else
-#define SLJIT_EXEC_OFFSET(ptr) 0
 #endif
 
 #endif /* SLJIT_EXECUTABLE_ALLOCATOR */
 
+#ifndef SLJIT_EXEC_OFFSET
+#define SLJIT_EXEC_OFFSET(ptr) 0
+#endif
+
 /**********************************************/
 /* Registers and locals offset determination. */
 /**********************************************/
@@ -645,15 +588,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 
 #define SLJIT_NUMBER_OF_REGISTERS 12
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 7
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 1
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 7
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
 #define SLJIT_LOCALS_OFFSET_BASE (8 * SSIZE_OF(sw))
 #define SLJIT_PREF_SHIFT_REG SLJIT_R2
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
 
 #elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
 
 #define SLJIT_NUMBER_OF_REGISTERS 13
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 2
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
 #ifndef _WIN64
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
@@ -664,37 +613,39 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 #define SLJIT_LOCALS_OFFSET_BASE (4 * SSIZE_OF(sw))
 #endif /* !_WIN64 */
 #define SLJIT_PREF_SHIFT_REG SLJIT_R3
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
 
-#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
-
-#define SLJIT_NUMBER_OF_REGISTERS 12
-#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
-#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14
-#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
-#define SLJIT_LOCALS_OFFSET_BASE 0
-
-#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32)
 
 #define SLJIT_NUMBER_OF_REGISTERS 12
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 2
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
 #define SLJIT_LOCALS_OFFSET_BASE 0
 
 #elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
 
 #define SLJIT_NUMBER_OF_REGISTERS 26
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 3
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
 #define SLJIT_LOCALS_OFFSET_BASE (2 * (sljit_s32)sizeof(sljit_sw))
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
 
 #elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
 
 #define SLJIT_NUMBER_OF_REGISTERS 23
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 3
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 18
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
 #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
 #define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * (sljit_s32)sizeof(sljit_sw))
 #elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
@@ -717,14 +668,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 29
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
 #endif
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 3
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
 
 #elif (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
 
 #define SLJIT_NUMBER_OF_REGISTERS 23
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 12
-#define SLJIT_LOCALS_OFFSET_BASE 0
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
+#define SLJIT_LOCALS_OFFSET_BASE 0
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
 
 #elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
 
@@ -751,16 +710,34 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 
 #define SLJIT_NUMBER_OF_REGISTERS 12
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 3
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
 #define SLJIT_LOCALS_OFFSET_BASE SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE
+#define SLJIT_MASKED_SHIFT 1
+
+#elif (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+
+#define SLJIT_NUMBER_OF_REGISTERS 23
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
+#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
+#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
+#define SLJIT_LOCALS_OFFSET_BASE 0
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
 
 #elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
 
+/* Just to have something. */
 #define SLJIT_NUMBER_OF_REGISTERS 0
 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 0
 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 0
 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 0
 #define SLJIT_LOCALS_OFFSET_BASE 0
 
 #endif
@@ -773,6 +750,45 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 #define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
 	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
 
+/**********************************/
+/* Temporary register management. */
+/**********************************/
+
+#define SLJIT_TMP_REGISTER_BASE (SLJIT_NUMBER_OF_REGISTERS + 2)
+#define SLJIT_TMP_FREGISTER_BASE (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+
+/* WARNING: Accessing temporary registers is not recommended, because they
+   are also used by the JIT compiler for various computations. Using them
+   might have any side effects including incorrect operations and crashes,
+   so use them at your own risk. The machine registers themselves might have
+   limitations, e.g. the r0 register on s390x / ppc cannot be used as
+   base address for memory operations. */
+
+/* Temporary registers */
+#define SLJIT_TMP_R0		(SLJIT_TMP_REGISTER_BASE + 0)
+#define SLJIT_TMP_R1		(SLJIT_TMP_REGISTER_BASE + 1)
+#define SLJIT_TMP_R2		(SLJIT_TMP_REGISTER_BASE + 2)
+#define SLJIT_TMP_R3		(SLJIT_TMP_REGISTER_BASE + 3)
+#define SLJIT_TMP_R4		(SLJIT_TMP_REGISTER_BASE + 4)
+#define SLJIT_TMP_R5		(SLJIT_TMP_REGISTER_BASE + 5)
+#define SLJIT_TMP_R6		(SLJIT_TMP_REGISTER_BASE + 6)
+#define SLJIT_TMP_R7		(SLJIT_TMP_REGISTER_BASE + 7)
+#define SLJIT_TMP_R8		(SLJIT_TMP_REGISTER_BASE + 8)
+#define SLJIT_TMP_R9		(SLJIT_TMP_REGISTER_BASE + 9)
+#define SLJIT_TMP_R(i)		(SLJIT_TMP_REGISTER_BASE + (i))
+
+#define SLJIT_TMP_FR0		(SLJIT_TMP_FREGISTER_BASE + 0)
+#define SLJIT_TMP_FR1		(SLJIT_TMP_FREGISTER_BASE + 1)
+#define SLJIT_TMP_FR2		(SLJIT_TMP_FREGISTER_BASE + 2)
+#define SLJIT_TMP_FR3		(SLJIT_TMP_FREGISTER_BASE + 3)
+#define SLJIT_TMP_FR4		(SLJIT_TMP_FREGISTER_BASE + 4)
+#define SLJIT_TMP_FR5		(SLJIT_TMP_FREGISTER_BASE + 5)
+#define SLJIT_TMP_FR6		(SLJIT_TMP_FREGISTER_BASE + 6)
+#define SLJIT_TMP_FR7		(SLJIT_TMP_FREGISTER_BASE + 7)
+#define SLJIT_TMP_FR8		(SLJIT_TMP_FREGISTER_BASE + 8)
+#define SLJIT_TMP_FR9		(SLJIT_TMP_FREGISTER_BASE + 9)
+#define SLJIT_TMP_FR(i)		(SLJIT_TMP_FREGISTER_BASE + (i))
+
 /********************************/
 /* CPU status flags management. */
 /********************************/
@@ -781,10 +797,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
 	|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
 	|| (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \
 	|| (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
-	|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+	|| (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+	|| (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
 #define SLJIT_HAS_STATUS_FLAGS_STATE 1
 #endif
 
+/***************************************/
+/* Floating point register management. */
+/***************************************/
+
+#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
+	|| (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define SLJIT_F64_SECOND(reg) \
+	((reg) + SLJIT_FS0 + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS)
+#else /* !SLJIT_CONFIG_ARM_32 && !SLJIT_CONFIG_MIPS_32 */
+#define SLJIT_F64_SECOND(reg) \
+	(reg)
+#endif /* SLJIT_CONFIG_ARM_32 || SLJIT_CONFIG_MIPS_32 */
+
 /*************************************/
 /* Debug and verbose related macros. */
 /*************************************/

+ 3 - 0
thirdparty/pcre2/src/sljit/sljitExecAllocator.c

@@ -152,6 +152,9 @@ static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
 {
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000
 	pthread_jit_write_protect_np(enable_exec);
+#elif defined(__clang__)
+	if (__builtin_available(macOS 11.0, *))
+		pthread_jit_write_protect_np(enable_exec);
 #else
 #error "Must target Big Sur or newer"
 #endif /* BigSur */

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 500 - 169
thirdparty/pcre2/src/sljit/sljitLir.c


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 414 - 198
thirdparty/pcre2/src/sljit/sljitLir.h


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 226 - 175
thirdparty/pcre2/src/sljit/sljitNativeARM_32.c


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 434 - 194
thirdparty/pcre2/src/sljit/sljitNativeARM_64.c


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 405 - 144
thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c


+ 3158 - 0
thirdparty/pcre2/src/sljit/sljitNativeLOONGARCH_64.c

@@ -0,0 +1,3158 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+	return "LOONGARCH" SLJIT_CPUINFO;
+}
+
+typedef sljit_u32 sljit_ins;
+
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_REG3	(SLJIT_NUMBER_OF_REGISTERS + 4)
+#define TMP_ZERO	0
+
+/* Flags are kept in volatile registers. */
+#define EQUAL_FLAG	(SLJIT_NUMBER_OF_REGISTERS + 5)
+#define RETURN_ADDR_REG	TMP_REG2
+#define OTHER_FLAG	(SLJIT_NUMBER_OF_REGISTERS + 6)
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
+	0, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 22, 31, 30, 29, 28, 27, 26, 25, 24, 23, 3, 13, 1, 14, 12, 15
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+	0, 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 31, 30, 29, 28, 27, 26, 25, 24, 8, 9
+};
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+/*
+LoongArch instructions are 32 bits wide, belonging to 9 basic instruction formats (and variants of them):
+
+| Format name  | Composition                 |
+| 2R           | Opcode + Rj + Rd            |
+| 3R           | Opcode + Rk + Rj + Rd       |
+| 4R           | Opcode + Ra + Rk + Rj + Rd  |
+| 2RI8         | Opcode + I8 + Rj + Rd       |
+| 2RI12        | Opcode + I12 + Rj + Rd      |
+| 2RI14        | Opcode + I14 + Rj + Rd      |
+| 2RI16        | Opcode + I16 + Rj + Rd      |
+| 1RI21        | Opcode + I21L + Rj + I21H   |
+| I26          | Opcode + I26L + I26H        |
+
+Rd is the destination register operand, while Rj, Rk and Ra (“a” stands for “additional”) are the source register operands.
+I8/I12/I14/I16/I21/I26 are immediate operands of respective width. The longer I21 and I26 are stored in separate higher and
+lower parts in the instruction word, denoted by the “L” and “H” suffixes. */
+
+#define RD(rd) ((sljit_ins)reg_map[rd])
+#define RJ(rj) ((sljit_ins)reg_map[rj] << 5)
+#define RK(rk) ((sljit_ins)reg_map[rk] << 10)
+#define RA(ra) ((sljit_ins)reg_map[ra] << 15)
+
+#define FD(fd) ((sljit_ins)reg_map[fd])
+#define FRD(fd) ((sljit_ins)freg_map[fd])
+#define FRJ(fj) ((sljit_ins)freg_map[fj] << 5)
+#define FRK(fk) ((sljit_ins)freg_map[fk] << 10)
+#define FRA(fa) ((sljit_ins)freg_map[fa] << 15)
+
+#define IMM_I8(imm) (((sljit_ins)(imm)&0xff) << 10)
+#define IMM_I12(imm) (((sljit_ins)(imm)&0xfff) << 10)
+#define IMM_I14(imm) (((sljit_ins)(imm)&0xfff3) << 10)
+#define IMM_I16(imm) (((sljit_ins)(imm)&0xffff) << 10)
+#define IMM_I21(imm) ((((sljit_ins)(imm)&0xffff) << 10) | (((sljit_ins)(imm) >> 16) & 0x1f))
+#define IMM_I26(imm) ((((sljit_ins)(imm)&0xffff) << 10) | (((sljit_ins)(imm) >> 16) & 0x3ff))
+
+#define OPC_I26(opc) ((sljit_ins)(opc) << 26)
+#define OPC_1RI21(opc) ((sljit_ins)(opc) << 26)
+#define OPC_2RI16(opc) ((sljit_ins)(opc) << 26)
+#define OPC_2RI14(opc) ((sljit_ins)(opc) << 24)
+#define OPC_2RI12(opc) ((sljit_ins)(opc) << 22)
+#define OPC_2RI8(opc) ((sljit_ins)(opc) << 18)
+#define OPC_4R(opc) ((sljit_ins)(opc) << 20)
+#define OPC_3R(opc) ((sljit_ins)(opc) << 15)
+#define OPC_2R(opc) ((sljit_ins)(opc) << 10)
+#define OPC_1RI20(opc) ((sljit_ins)(opc) << 25)
+
+/* Arithmetic operation instructions */
+#define ADD_W OPC_3R(0x20)
+#define ADD_D OPC_3R(0x21)
+#define SUB_W OPC_3R(0x22)
+#define SUB_D OPC_3R(0x23)
+#define ADDI_W OPC_2RI12(0xa)
+#define ADDI_D OPC_2RI12(0xb)
+#define ANDI OPC_2RI12(0xd)
+#define ORI OPC_2RI12(0xe)
+#define XORI OPC_2RI12(0xf)
+#define ADDU16I_D OPC_2RI16(0x4)
+#define LU12I_W OPC_1RI20(0xa)
+#define LU32I_D OPC_1RI20(0xb)
+#define LU52I_D OPC_2RI12(0xc)
+#define SLT OPC_3R(0x24)
+#define SLTU OPC_3R(0x25)
+#define SLTI OPC_2RI12(0x8)
+#define SLTUI OPC_2RI12(0x9)
+#define PCADDI OPC_1RI20(0xc)
+#define PCALAU12I OPC_1RI20(0xd)
+#define PCADDU12I OPC_1RI20(0xe)
+#define PCADDU18I OPC_1RI20(0xf)
+#define NOR OPC_3R(0x28)
+#define AND OPC_3R(0x29)
+#define OR OPC_3R(0x2a)
+#define XOR OPC_3R(0x2b)
+#define ORN OPC_3R(0x2c)
+#define ANDN OPC_3R(0x2d)
+#define MUL_W OPC_3R(0x38)
+#define MULH_W OPC_3R(0x39)
+#define MULH_WU OPC_3R(0x3a)
+#define MUL_D OPC_3R(0x3b)
+#define MULH_D OPC_3R(0x3c)
+#define MULH_DU OPC_3R(0x3d)
+#define MULW_D_W OPC_3R(0x3e)
+#define MULW_D_WU OPC_3R(0x3f)
+#define DIV_W OPC_3R(0x40)
+#define MOD_W OPC_3R(0x41)
+#define DIV_WU OPC_3R(0x42)
+#define MOD_WU OPC_3R(0x43)
+#define DIV_D OPC_3R(0x44)
+#define MOD_D OPC_3R(0x45)
+#define DIV_DU OPC_3R(0x46)
+#define MOD_DU OPC_3R(0x47)
+
+/* Bit-shift instructions */
+#define SLL_W OPC_3R(0x2e)
+#define SRL_W OPC_3R(0x2f)
+#define SRA_W OPC_3R(0x30)
+#define SLL_D OPC_3R(0x31)
+#define SRL_D OPC_3R(0x32)
+#define SRA_D OPC_3R(0x33)
+#define ROTR_W OPC_3R(0x36)
+#define ROTR_D OPC_3R(0x37)
+#define SLLI_W OPC_3R(0x81)
+#define SLLI_D ((sljit_ins)(0x41) << 16)
+#define SRLI_W OPC_3R(0x89)
+#define SRLI_D ((sljit_ins)(0x45) << 16)
+#define SRAI_W OPC_3R(0x91)
+#define SRAI_D ((sljit_ins)(0x49) << 16)
+#define ROTRI_W OPC_3R(0x99)
+#define ROTRI_D ((sljit_ins)(0x4d) << 16)
+
+/* Bit-manipulation instructions */
+#define CLO_W OPC_2R(0x4)
+#define CLZ_W OPC_2R(0x5)
+#define CTO_W OPC_2R(0x6)
+#define CTZ_W OPC_2R(0x7)
+#define CLO_D OPC_2R(0x8)
+#define CLZ_D OPC_2R(0x9)
+#define CTO_D OPC_2R(0xa)
+#define CTZ_D OPC_2R(0xb)
+#define REVB_2H OPC_2R(0xc)
+#define REVB_4H OPC_2R(0xd)
+#define REVB_2W OPC_2R(0xe)
+#define REVB_D OPC_2R(0xf)
+#define REVH_2W OPC_2R(0x10)
+#define REVH_D OPC_2R(0x11)
+#define BITREV_4B OPC_2R(0x12)
+#define BITREV_8B OPC_2R(0x13)
+#define BITREV_W OPC_2R(0x14)
+#define BITREV_D OPC_2R(0x15)
+#define EXT_W_H OPC_2R(0x16)
+#define EXT_W_B OPC_2R(0x17)
+#define BSTRINS_W (0x1 << 22 | 1 << 21)
+#define BSTRPICK_W (0x1 << 22 | 1 << 21 | 1 << 15)
+#define BSTRINS_D (0x2 << 22)
+#define BSTRPICK_D (0x3 << 22)
+
+/* Branch instructions */
+#define BEQZ  OPC_1RI21(0x10)
+#define BNEZ  OPC_1RI21(0x11)
+#define JIRL  OPC_2RI16(0x13)
+#define B     OPC_I26(0x14)
+#define BL    OPC_I26(0x15)
+#define BEQ   OPC_2RI16(0x16)
+#define BNE   OPC_2RI16(0x17)
+#define BLT   OPC_2RI16(0x18)
+#define BGE   OPC_2RI16(0x19)
+#define BLTU  OPC_2RI16(0x1a)
+#define BGEU  OPC_2RI16(0x1b)
+
+/* Memory access instructions */
+#define LD_B OPC_2RI12(0xa0)
+#define LD_H OPC_2RI12(0xa1)
+#define LD_W OPC_2RI12(0xa2)
+#define LD_D OPC_2RI12(0xa3)
+
+#define ST_B OPC_2RI12(0xa4)
+#define ST_H OPC_2RI12(0xa5)
+#define ST_W OPC_2RI12(0xa6)
+#define ST_D OPC_2RI12(0xa7)
+
+#define LD_BU OPC_2RI12(0xa8)
+#define LD_HU OPC_2RI12(0xa9)
+#define LD_WU OPC_2RI12(0xaa)
+
+#define LDX_B OPC_3R(0x7000)
+#define LDX_H OPC_3R(0x7008)
+#define LDX_W OPC_3R(0x7010)
+#define LDX_D OPC_3R(0x7018)
+
+#define STX_B OPC_3R(0x7020)
+#define STX_H OPC_3R(0x7028)
+#define STX_W OPC_3R(0x7030)
+#define STX_D OPC_3R(0x7038)
+
+#define LDX_BU OPC_3R(0x7040)
+#define LDX_HU OPC_3R(0x7048)
+#define LDX_WU OPC_3R(0x7050)
+
+#define PRELD OPC_2RI12(0xab)
+
+/* Atomic memory access instructions */
+#define LL_W OPC_2RI14(0x20)
+#define SC_W OPC_2RI14(0x21)
+#define LL_D OPC_2RI14(0x22)
+#define SC_D OPC_2RI14(0x23)
+
+/* LoongArch V1.10 Instructions */
+#define AMCAS_B OPC_3R(0x70B0)
+#define AMCAS_H OPC_3R(0x70B1)
+#define AMCAS_W OPC_3R(0x70B2)
+#define AMCAS_D OPC_3R(0x70B3)
+
+/* Other instructions */
+#define BREAK OPC_3R(0x54)
+#define DBGCALL OPC_3R(0x55)
+#define SYSCALL OPC_3R(0x56)
+
+/* Basic Floating-Point Instructions */
+/* Floating-Point Arithmetic Operation Instructions */
+#define FADD_S  OPC_3R(0x201)
+#define FADD_D  OPC_3R(0x202)
+#define FSUB_S  OPC_3R(0x205)
+#define FSUB_D  OPC_3R(0x206)
+#define FMUL_S  OPC_3R(0x209)
+#define FMUL_D  OPC_3R(0x20a)
+#define FDIV_S  OPC_3R(0x20d)
+#define FDIV_D  OPC_3R(0x20e)
+#define FCMP_COND_S  OPC_4R(0xc1)
+#define FCMP_COND_D  OPC_4R(0xc2)
+#define FCOPYSIGN_S  OPC_3R(0x225)
+#define FCOPYSIGN_D  OPC_3R(0x226)
+#define FSEL  OPC_4R(0xd0)
+#define FABS_S  OPC_2R(0x4501)
+#define FABS_D  OPC_2R(0x4502)
+#define FNEG_S  OPC_2R(0x4505)
+#define FNEG_D  OPC_2R(0x4506)
+#define FMOV_S  OPC_2R(0x4525)
+#define FMOV_D  OPC_2R(0x4526)
+
+/* Floating-Point Conversion Instructions */
+#define FCVT_S_D  OPC_2R(0x4646)
+#define FCVT_D_S  OPC_2R(0x4649)
+#define FTINTRZ_W_S  OPC_2R(0x46a1)
+#define FTINTRZ_W_D  OPC_2R(0x46a2)
+#define FTINTRZ_L_S  OPC_2R(0x46a9)
+#define FTINTRZ_L_D  OPC_2R(0x46aa)
+#define FFINT_S_W  OPC_2R(0x4744)
+#define FFINT_S_L  OPC_2R(0x4746)
+#define FFINT_D_W  OPC_2R(0x4748)
+#define FFINT_D_L  OPC_2R(0x474a)
+
+/* Floating-Point Move Instructions */
+#define FMOV_S  OPC_2R(0x4525)
+#define FMOV_D  OPC_2R(0x4526)
+#define MOVGR2FR_W  OPC_2R(0x4529)
+#define MOVGR2FR_D  OPC_2R(0x452a)
+#define MOVGR2FRH_W  OPC_2R(0x452b)
+#define MOVFR2GR_S  OPC_2R(0x452d)
+#define MOVFR2GR_D  OPC_2R(0x452e)
+#define MOVFRH2GR_S  OPC_2R(0x452f)
+#define MOVGR2FCSR  OPC_2R(0x4530)
+#define MOVFCSR2GR  OPC_2R(0x4532)
+#define MOVFR2CF  OPC_2R(0x4534)
+#define MOVCF2FR  OPC_2R(0x4535)
+#define MOVGR2CF  OPC_2R(0x4536)
+#define MOVCF2GR  OPC_2R(0x4537)
+
+/* Floating-Point Branch Instructions */
+#define BCEQZ OPC_I26(0x12)
+#define BCNEZ OPC_I26(0x12)
+
+/* Floating-Point Common Memory Access Instructions */
+#define FLD_S OPC_2RI12(0xac)
+#define FLD_D OPC_2RI12(0xae)
+#define FST_S OPC_2RI12(0xad)
+#define FST_D OPC_2RI12(0xaf)
+
+#define FLDX_S OPC_3R(0x7060)
+#define FLDX_D OPC_3R(0x7068)
+#define FSTX_S OPC_3R(0x7070)
+#define FSTX_D OPC_3R(0x7078)
+
+#define I12_MAX (0x7ff)
+#define I12_MIN (-0x800)
+#define BRANCH16_MAX (0x7fff << 2)
+#define BRANCH16_MIN (-(0x8000 << 2))
+#define BRANCH21_MAX (0xfffff << 2)
+#define BRANCH21_MIN (-(0x100000 << 2))
+#define JUMP_MAX (0x1ffffff << 2)
+#define JUMP_MIN (-(0x2000000 << 2))
+#define JIRL_MAX (0x7fff << 2)
+#define JIRL_MIN (-(0x8000 << 2))
+
+#define S32_MAX		(0x7fffffffl)
+#define S32_MIN		(-0x80000000l)
+#define S52_MAX		(0x7ffffffffffffl)
+
+#define INST(inst, type) ((sljit_ins)((type & SLJIT_32) ? inst##_W : inst##_D))
+
+/* LoongArch CPUCFG register for feature detection */
+#define LOONGARCH_CFG2			0x02
+#define LOONGARCH_FEATURE_LAMCAS	(1 << 28)
+
+static sljit_u32 cpu_feature_list = 0;
+
+static SLJIT_INLINE sljit_u32 get_cpu_features(void)
+{
+	if (cpu_feature_list == 0)
+		__asm__ ("cpucfg %0, %1" : "+&r"(cpu_feature_list) : "r"(LOONGARCH_CFG2));
+	return cpu_feature_list;
+}
+
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+{
+	sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+	sljit_uw target_addr;
+	sljit_ins *inst;
+
+	inst = (sljit_ins *)jump->addr;
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		goto exit;
+
+	if (jump->flags & JUMP_ADDR)
+		target_addr = jump->u.target;
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
+	}
+
+	diff = (sljit_sw)target_addr - (sljit_sw)inst - executable_offset;
+
+	if (jump->flags & IS_COND) {
+		inst--;
+		diff += SSIZE_OF(ins);
+
+		if (diff >= BRANCH16_MIN && diff <= BRANCH16_MAX) {
+			jump->flags |= PATCH_B;
+			inst[0] = (inst[0] & 0xfc0003ff) ^ 0x4000000;
+			jump->addr = (sljit_uw)inst;
+			return inst;
+		}
+
+		inst++;
+		diff -= SSIZE_OF(ins);
+	}
+
+	if (diff >= JUMP_MIN && diff <= JUMP_MAX) {
+		if (jump->flags & IS_COND) {
+			inst[-1] |= (sljit_ins)IMM_I16(2);
+		}
+
+		jump->flags |= PATCH_J;
+		return inst;
+	}
+
+	if (diff >= S32_MIN && diff <= S32_MAX) {
+		if (jump->flags & IS_COND)
+			inst[-1] |= (sljit_ins)IMM_I16(3);
+
+		jump->flags |= PATCH_REL32;
+		inst[1] = inst[0];
+		return inst + 1;
+	}
+
+	if (target_addr <= (sljit_uw)S32_MAX) {
+		if (jump->flags & IS_COND)
+			inst[-1] |= (sljit_ins)IMM_I16(3);
+
+		jump->flags |= PATCH_ABS32;
+		inst[1] = inst[0];
+		return inst + 1;
+	}
+
+	if (target_addr <= S52_MAX) {
+		if (jump->flags & IS_COND)
+			inst[-1] |= (sljit_ins)IMM_I16(4);
+
+		jump->flags |= PATCH_ABS52;
+		inst[2] = inst[0];
+		return inst + 2;
+	}
+
+exit:
+	if (jump->flags & IS_COND)
+		inst[-1] |= (sljit_ins)IMM_I16(5);
+	inst[3] = inst[0];
+	return inst + 3;
+}
+
+static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+{
+	if (max_label <= (sljit_uw)S32_MAX) {
+		put_label->flags = PATCH_ABS32;
+		return 1;
+	}
+
+	if (max_label <= S52_MAX) {
+		put_label->flags = PATCH_ABS52;
+		return 2;
+	}
+
+	put_label->flags = 0;
+	return 3;
+}
+
+static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
+{
+	struct sljit_jump *jump = NULL;
+	struct sljit_put_label *put_label;
+	sljit_uw flags;
+	sljit_ins *inst;
+	sljit_uw addr;
+
+	if (reg != 0) {
+		jump = (struct sljit_jump*)dst;
+		flags = jump->flags;
+		inst = (sljit_ins*)jump->addr;
+		addr = (flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+	} else {
+		put_label = (struct sljit_put_label*)dst;
+		flags = put_label->flags;
+		inst = (sljit_ins*)put_label->addr;
+		addr = put_label->label->addr;
+		reg = *inst;
+	}
+
+	if (flags & PATCH_ABS32) {
+		SLJIT_ASSERT(addr <= S32_MAX);
+		inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+	} else if (flags & PATCH_ABS52) {
+		inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+		inst[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5);
+		inst += 1;
+	} else {
+		inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+		inst[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5);
+		inst[2] = LU52I_D | RD(reg) | RJ(reg) | IMM_I12(addr >> 52);
+		inst += 2;
+	}
+
+	if (jump != NULL) {
+		SLJIT_ASSERT((inst[1] & OPC_2RI16(0x3f)) == JIRL);
+		inst[1] = (inst[1] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I16((addr & 0xfff) >> 2);
+	} else
+		inst[1] = ORI | RD(reg) | RJ(reg) | IMM_I12(addr);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_ins *code;
+	sljit_ins *code_ptr;
+	sljit_ins *buf_ptr;
+	sljit_ins *buf_end;
+	sljit_uw word_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+	sljit_uw addr;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	word_count = 0;
+	next_addr = 0;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	do {
+		buf_ptr = (sljit_ins*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 2);
+		do {
+			*code_ptr = *buf_ptr++;
+			if (next_addr == word_count) {
+				SLJIT_ASSERT(!label || label->size >= word_count);
+				SLJIT_ASSERT(!jump || jump->addr >= word_count);
+				SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+				SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
+
+				/* These structures are ordered by their address. */
+				if (label && label->size == word_count) {
+					label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+					label->size = (sljit_uw)(code_ptr - code);
+					label = label->next;
+				}
+				if (jump && jump->addr == word_count) {
+					word_count += 3;
+					jump->addr = (sljit_uw)code_ptr;
+					code_ptr = detect_jump_type(jump, code, executable_offset);
+					jump = jump->next;
+				}
+				if (const_ && const_->addr == word_count) {
+					const_->addr = (sljit_uw)code_ptr;
+					const_ = const_->next;
+				}
+				if (put_label && put_label->addr == word_count) {
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)code_ptr;
+
+					code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
+					word_count += 3;
+
+					put_label = put_label->next;
+				}
+				next_addr = compute_next_addr(label, jump, const_, put_label);
+			}
+			code_ptr++;
+			word_count++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == word_count) {
+		label->addr = (sljit_uw)code_ptr;
+		label->size = (sljit_uw)(code_ptr - code);
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		do {
+			if (!(jump->flags & (PATCH_B | PATCH_J | PATCH_REL32))) {
+				load_addr_to_reg(jump, TMP_REG1);
+				break;
+			}
+
+			addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+			buf_ptr = (sljit_ins *)jump->addr;
+			addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
+
+			if (jump->flags & PATCH_B) {
+				SLJIT_ASSERT((sljit_sw)addr >= BRANCH16_MIN && (sljit_sw)addr <= BRANCH16_MAX);
+				buf_ptr[0] |= (sljit_ins)IMM_I16(addr >> 2);
+				break;
+			}
+
+			if (jump->flags & PATCH_REL32) {
+				SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX);
+
+				buf_ptr[0] = PCADDU12I | RD(TMP_REG1) | (sljit_ins)((sljit_sw)addr & ~0xfff);
+				SLJIT_ASSERT((buf_ptr[1] & OPC_2RI16(0x3f)) == JIRL);
+				buf_ptr[1] |= IMM_I16((addr & 0xfff) >> 2);
+				break;
+			}
+
+			SLJIT_ASSERT((sljit_sw)addr >= JUMP_MIN && (sljit_sw)addr <= JUMP_MAX);
+			if (jump->flags & IS_CALL)
+				buf_ptr[0] = BL | (sljit_ins)IMM_I26(addr >> 2);
+			else
+				buf_ptr[0] = B | (sljit_ins)IMM_I26(addr >> 2);
+		} while (0);
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+		load_addr_to_reg(put_label, 0);
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
+
+	code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+	code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+	return code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type)
+	{
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return (SLJIT_IS_FPU_AVAILABLE) != 0;
+#else
+		/* Available by default. */
+		return 1;
+#endif
+
+	case SLJIT_HAS_ATOMIC:
+		return (LOONGARCH_FEATURE_LAMCAS & get_cpu_features());
+
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_CTZ:
+	case SLJIT_HAS_REV:
+	case SLJIT_HAS_ROT:
+	case SLJIT_HAS_PREFETCH:
+	case SLJIT_HAS_COPY_F32:
+	case SLJIT_HAS_COPY_F64:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
+{
+	SLJIT_UNUSED_ARG(type);
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+/* Creates an index in data_transfer_insts array. */
+#define LOAD_DATA	0x01
+#define WORD_DATA	0x00
+#define BYTE_DATA	0x02
+#define HALF_DATA	0x04
+#define INT_DATA	0x06
+#define SIGNED_DATA	0x08
+/* Separates integer and floating point registers */
+#define GPR_REG		0x0f
+#define DOUBLE_DATA	0x10
+#define SINGLE_DATA	0x12
+
+#define MEM_MASK	0x1f
+
+#define ARG_TEST	0x00020
+#define ALT_KEEP_CACHE	0x00040
+#define CUMULATIVE_OP	0x00080
+#define IMM_OP		0x00100
+#define MOVE_OP		0x00200
+#define SRC2_IMM	0x00400
+
+#define UNUSED_DEST	0x00800
+#define REG_DEST	0x01000
+#define REG1_SOURCE	0x02000
+#define REG2_SOURCE	0x04000
+#define SLOW_SRC1	0x08000
+#define SLOW_SRC2	0x10000
+#define SLOW_DEST	0x20000
+
+#define STACK_STORE	ST_D
+#define STACK_LOAD	LD_D
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm)
+{
+	if (imm <= I12_MAX && imm >= I12_MIN)
+		return push_inst(compiler, ADDI_D | RD(dst_r) | RJ(TMP_ZERO) | IMM_I12(imm));
+
+	if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
+		FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
+		return push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm));
+	} else if (imm <= 0x7ffffffffffffl && imm >= -0x8000000000000l) {
+		FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
+		FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
+		return push_inst(compiler, LU32I_D | RD(dst_r) | (sljit_ins)(((imm >> 32) & 0xfffff) << 5));
+	}
+	FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
+	FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
+	FAIL_IF(push_inst(compiler, LU32I_D | RD(dst_r) | (sljit_ins)(((imm >> 32) & 0xfffff) << 5)));
+	return push_inst(compiler, LU52I_D | RD(dst_r) | RJ(dst_r) | IMM_I12(imm >> 52));
+}
+
+#define STACK_MAX_DISTANCE (-I12_MIN)
+
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw);
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 i, tmp, offset;
+	sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1);
+	local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
+
+	local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
+	compiler->local_size = local_size;
+
+	if (local_size <= STACK_MAX_DISTANCE) {
+		/* Frequent case. */
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(-local_size)));
+		offset = local_size - SSIZE_OF(sw);
+		local_size = 0;
+	} else {
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(STACK_MAX_DISTANCE)));
+		local_size -= STACK_MAX_DISTANCE;
+
+		if (local_size > STACK_MAX_DISTANCE)
+			FAIL_IF(load_immediate(compiler, TMP_REG1, local_size));
+		offset = STACK_MAX_DISTANCE - SSIZE_OF(sw);
+	}
+
+	FAIL_IF(push_inst(compiler, STACK_STORE | RD(RETURN_ADDR_REG) | RJ(SLJIT_SP) | IMM_I12(offset)));
+
+	tmp = SLJIT_S0 - saveds;
+	for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) {
+		offset -= SSIZE_OF(sw);
+		FAIL_IF(push_inst(compiler, STACK_STORE | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		offset -= SSIZE_OF(sw);
+		FAIL_IF(push_inst(compiler, STACK_STORE | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	tmp = SLJIT_FS0 - fsaveds;
+	for (i = SLJIT_FS0; i > tmp; i--) {
+		offset -= SSIZE_OF(f64);
+		FAIL_IF(push_inst(compiler, FST_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
+		offset -= SSIZE_OF(f64);
+		FAIL_IF(push_inst(compiler, FST_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	if (local_size > STACK_MAX_DISTANCE)
+		FAIL_IF(push_inst(compiler, SUB_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | RK(TMP_REG1)));
+	else if (local_size > 0)
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(-local_size)));
+
+	if (options & SLJIT_ENTER_REG_ARG)
+		return SLJIT_SUCCESS;
+
+	arg_types >>= SLJIT_ARG_SHIFT;
+	saved_arg_count = 0;
+	tmp = SLJIT_R0;
+
+	while (arg_types > 0) {
+		if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) {
+			if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {
+				FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_S0 - saved_arg_count) | RJ(tmp) | IMM_I12(0)));
+				saved_arg_count++;
+			}
+			tmp++;
+		}
+
+		arg_types >>= SLJIT_ARG_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#undef STACK_MAX_DISTANCE
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1);
+	local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
+
+	compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
+
+	return SLJIT_SUCCESS;
+}
+
+#define STACK_MAX_DISTANCE (-I12_MIN - 16)
+
+static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to)
+{
+	sljit_s32 i, tmp, offset;
+	sljit_s32 local_size = compiler->local_size;
+
+	if (local_size > STACK_MAX_DISTANCE) {
+		local_size -= STACK_MAX_DISTANCE;
+
+		if (local_size > STACK_MAX_DISTANCE) {
+			FAIL_IF(load_immediate(compiler, TMP_REG2, local_size));
+			FAIL_IF(push_inst(compiler, ADD_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | RK(TMP_REG2)));
+		} else
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(local_size)));
+
+		local_size = STACK_MAX_DISTANCE;
+	}
+
+	SLJIT_ASSERT(local_size > 0);
+
+	offset = local_size - SSIZE_OF(sw);
+	if (!is_return_to)
+		FAIL_IF(push_inst(compiler, STACK_LOAD | RD(RETURN_ADDR_REG) | RJ(SLJIT_SP) | IMM_I12(offset)));
+
+	tmp = SLJIT_S0 - compiler->saveds;
+	for (i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); i > tmp; i--) {
+		offset -= SSIZE_OF(sw);
+		FAIL_IF(push_inst(compiler, STACK_LOAD | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		offset -= SSIZE_OF(sw);
+		FAIL_IF(push_inst(compiler, STACK_LOAD | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	tmp = SLJIT_FS0 - compiler->fsaveds;
+	for (i = SLJIT_FS0; i > tmp; i--) {
+		offset -= SSIZE_OF(f64);
+		FAIL_IF(push_inst(compiler, FLD_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
+		offset -= SSIZE_OF(f64);
+		FAIL_IF(push_inst(compiler, FLD_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+	}
+
+	return push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(local_size));
+}
+
+#undef STACK_MAX_DISTANCE
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return_void(compiler));
+
+	FAIL_IF(emit_stack_frame_release(compiler, 0));
+	return push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return_to(compiler, src, srcw));
+
+	if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+		src = TMP_REG1;
+		srcw = 0;
+	} else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(src) | IMM_I12(0)));
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	FAIL_IF(emit_stack_frame_release(compiler, 1));
+
+	SLJIT_SKIP_CHECKS(compiler);
+	return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+static const sljit_ins data_transfer_insts[16 + 4] = {
+/* u w s */ ST_D /* st.d */,
+/* u w l */ LD_D /* ld.d */,
+/* u b s */ ST_B /* st.b */,
+/* u b l */ LD_BU /* ld.bu */,
+/* u h s */ ST_H /* st.h */,
+/* u h l */ LD_HU /* ld.hu */,
+/* u i s */ ST_W /* st.w */,
+/* u i l */ LD_WU /* ld.wu */,
+
+/* s w s */ ST_D /* st.d */,
+/* s w l */ LD_D /* ld.d */,
+/* s b s */ ST_B /* st.b */,
+/* s b l */ LD_B /* ld.b */,
+/* s h s */ ST_H /* st.h */,
+/* s h l */ LD_H /* ld.h */,
+/* s i s */ ST_W /* st.w */,
+/* s i l */ LD_W /* ld.w */,
+
+/* d   s */ FST_D /* fst.d */,
+/* d   l */ FLD_D /* fld.d */,
+/* s   s */ FST_S /* fst.s */,
+/* s   l */ FLD_S /* fld.s */,
+};
+
+static const sljit_ins data_transfer_insts_x[16 + 4] = {
+/* u w s */ STX_D /* stx.d */,
+/* u w l */ LDX_D /* ldx.d */,
+/* u b s */ STX_B /* stx.b */,
+/* u b l */ LDX_BU /* ldx.bu */,
+/* u h s */ STX_H /* stx.h */,
+/* u h l */ LDX_HU /* ldx.hu */,
+/* u i s */ STX_W /* stx.w */,
+/* u i l */ LDX_WU /* ldx.wu */,
+
+/* s w s */ STX_D /* stx.d */,
+/* s w l */ LDX_D /* ldx.d */,
+/* s b s */ STX_B /* stx.b */,
+/* s b l */ LDX_B /* ldx.b */,
+/* s h s */ STX_H /* stx.h */,
+/* s h l */ LDX_H /* ldx.h */,
+/* s i s */ STX_W /* stx.w */,
+/* s i l */ LDX_W /* ldx.w */,
+
+/* d   s */ FSTX_D /* fstx.d */,
+/* d   l */ FLDX_D /* fldx.d */,
+/* s   s */ FSTX_S /* fstx.s */,
+/* s   l */ FLDX_S /* fldx.s */,
+};
+
+static sljit_s32 push_mem_inst(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	sljit_ins ins;
+	sljit_s32 base = arg & REG_MASK;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if (arg & OFFS_REG_MASK) {
+		sljit_s32 offs = OFFS_REG(arg);
+
+		SLJIT_ASSERT(!argw);
+		ins = data_transfer_insts_x[flags & MEM_MASK] |
+			  ((flags & MEM_MASK) <= GPR_REG ? RD(reg) : FRD(reg)) |
+			  RJ(base) | RK(offs);
+	} else {
+		SLJIT_ASSERT(argw <= 0xfff && argw >= I12_MIN);
+
+		ins = data_transfer_insts[flags & MEM_MASK] |
+			  ((flags & MEM_MASK) <= GPR_REG ? RD(reg) : FRD(reg)) |
+			  RJ(base) | IMM_I12(argw);
+	}
+	return push_inst(compiler, ins);
+}
+
+/* Can perform an operation using at most 1 instruction. */
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	/* argw == 0 (ldx/stx rd, rj, rk) can be used.
+	 * argw in [-2048, 2047] (ld/st rd, rj, imm) can be used. */
+	if (!argw || (!(arg & OFFS_REG_MASK) && (argw <= I12_MAX && argw >= I12_MIN))) {
+		/* Works for both absolute and relative addresses. */
+		if (SLJIT_UNLIKELY(flags & ARG_TEST))
+			return 1;
+
+		FAIL_IF(push_mem_inst(compiler, flags, reg, arg, argw));
+		return -1;
+	}
+	return 0;
+}
+
+#define TO_ARGW_HI(argw) (((argw) & ~0xfff) + (((argw) & 0x800) ? 0x1000 : 0))
+
+/* See getput_arg below.
+   Note: can_cache is called only for binary operators. */
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
+
+	if (arg & OFFS_REG_MASK)
+		return 0;
+
+	if (arg == next_arg) {
+		if (((next_argw - argw) <= I12_MAX && (next_argw - argw) >= I12_MIN)
+				|| TO_ARGW_HI(argw) == TO_ARGW_HI(next_argw))
+			return 1;
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Emit the necessary instructions. See can_cache above. */
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	sljit_s32 base = arg & REG_MASK;
+	sljit_s32 tmp_r = TMP_REG1;
+	sljit_sw offset;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+	if (!(next_arg & SLJIT_MEM)) {
+		next_arg = 0;
+		next_argw = 0;
+	}
+
+	/* Since tmp can be the same as base or offset registers,
+	 * these might be unavailable after modifying tmp. */
+	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA))
+		tmp_r = reg;
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		if (SLJIT_UNLIKELY(argw))
+			FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG3) | RJ(OFFS_REG(arg)) | IMM_I12(argw)));
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, TMP_REG3), 0);
+	}
+
+	if (compiler->cache_arg == arg && argw - compiler->cache_argw <= I12_MAX && argw - compiler->cache_argw >= I12_MIN)
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(TMP_REG3), argw - compiler->cache_argw);
+
+	if (compiler->cache_arg == SLJIT_MEM && (argw - compiler->cache_argw <= I12_MAX) && (argw - compiler->cache_argw >= I12_MIN)) {
+		offset = argw - compiler->cache_argw;
+	} else {
+		sljit_sw argw_hi=TO_ARGW_HI(argw);
+		compiler->cache_arg = SLJIT_MEM;
+
+		if (next_arg && next_argw - argw <= I12_MAX && next_argw - argw >= I12_MIN && argw_hi != TO_ARGW_HI(next_argw)) {
+			FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
+			compiler->cache_argw = argw;
+			offset = 0;
+		} else {
+			FAIL_IF(load_immediate(compiler, TMP_REG3, argw_hi));
+			compiler->cache_argw = argw_hi;
+			offset = argw & 0xfff;
+			argw = argw_hi;
+		}
+	}
+
+	if (!base)
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(TMP_REG3), offset);
+
+	if (arg == next_arg && next_argw - argw <= I12_MAX && next_argw - argw >= I12_MIN) {
+		compiler->cache_arg = arg;
+		FAIL_IF(push_inst(compiler, ADD_D | RD(TMP_REG3) | RJ(TMP_REG3) | RK(base)));
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(TMP_REG3), offset);
+	}
+
+	if (!offset)
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, TMP_REG3), 0);
+
+	FAIL_IF(push_inst(compiler, ADD_D | RD(tmp_r) | RJ(TMP_REG3) | RK(base)));
+	return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(tmp_r), offset);
+}
+
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	sljit_s32 base = arg & REG_MASK;
+	sljit_s32 tmp_r = TMP_REG1;
+
+	if (getput_arg_fast(compiler, flags, reg, arg, argw))
+		return compiler->error;
+
+	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA))
+		tmp_r = reg;
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		if (SLJIT_UNLIKELY(argw))
+			FAIL_IF(push_inst(compiler, SLLI_D | RD(tmp_r) | RJ(OFFS_REG(arg)) | IMM_I12(argw)));
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, tmp_r), 0);
+	} else {
+		FAIL_IF(load_immediate(compiler, tmp_r, argw));
+
+		if (base != 0)
+			return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, tmp_r), 0);
+		return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(tmp_r), 0);
+	}
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
+{
+	if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
+		return compiler->error;
+	return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
+}
+
+#define IMM_EXTEND(v) (IMM_I12((op & SLJIT_32) ? (v) : (32 + (v))))
+
+/* andi/ori/xori are zero-extended */
+#define EMIT_LOGICAL(op_imm, op_reg) \
+	if (flags & SRC2_IMM) { \
+		if (op & SLJIT_SET_Z) {\
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(EQUAL_FLAG) | RJ(TMP_ZERO) | IMM_I12(src2))); \
+			FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG))); \
+		} \
+		if (!(flags & UNUSED_DEST)) { \
+			if (dst == src1) { \
+				FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(TMP_ZERO) | IMM_I12(src2))); \
+				FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(TMP_REG1))); \
+			} else { \
+				FAIL_IF(push_inst(compiler, ADDI_D | RD(dst) | RJ(TMP_ZERO) | IMM_I12(src2))); \
+				FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(dst))); \
+			} \
+		} \
+	} \
+	else { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(src2))); \
+	} \
+	while (0)
+
+#define EMIT_SHIFT(imm, reg) \
+	op_imm = (imm); \
+	op_reg = (reg)
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
+{
+	sljit_s32 is_overflow, is_carry, carry_src_r, is_handled;
+	sljit_ins op_imm, op_reg;
+	sljit_ins word_size = ((op & SLJIT_32) ? 32 : 64);
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (dst != src2)
+			return push_inst(compiler, INST(ADD, op) | RD(dst) | RJ(src2) | IMM_I12(0));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
+			return push_inst(compiler, ANDI | RD(dst) | RJ(src2) | IMM_I12(0xff));
+		SLJIT_ASSERT(dst == src2);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
+			return push_inst(compiler, EXT_W_B | RD(dst) | RJ(src2));
+		SLJIT_ASSERT(dst == src2);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
+			return push_inst(compiler, INST(BSTRPICK, op) | RD(dst) | RJ(src2) | (15 << 16));
+		SLJIT_ASSERT(dst == src2);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
+			return push_inst(compiler, EXT_W_H | RD(dst) | RJ(src2));
+		SLJIT_ASSERT(dst == src2);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
+			return push_inst(compiler, BSTRPICK_D | RD(dst) | RJ(src2) | (31 << 16));
+		SLJIT_ASSERT(dst == src2);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_S32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
+			return push_inst(compiler, SLLI_W | RD(dst) | RJ(src2) | IMM_I12(0));
+		SLJIT_ASSERT(dst == src2);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return push_inst(compiler, INST(CLZ, op) | RD(dst) | RJ(src2));
+
+	case SLJIT_CTZ:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return push_inst(compiler, INST(CTZ, op) | RD(dst) | RJ(src2));
+
+	case SLJIT_REV:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return push_inst(compiler, ((op & SLJIT_32) ? REVB_2W : REVB_D) | RD(dst) | RJ(src2));
+
+	case SLJIT_REV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		FAIL_IF(push_inst(compiler, REVB_2H | RD(dst) | RJ(src2)));
+		return push_inst(compiler, EXT_W_H | RD(dst) | RJ(dst));
+
+	case SLJIT_REV_U16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		FAIL_IF(push_inst(compiler, REVB_2H | RD(dst) | RJ(src2)));
+		return push_inst(compiler, INST(BSTRPICK, op) | RD(dst) | RJ(dst) | (15 << 16));
+
+	case SLJIT_REV_S32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1);
+		FAIL_IF(push_inst(compiler, REVB_2W | RD(dst) | RJ(src2)));
+		return push_inst(compiler, SLLI_W | RD(dst) | RJ(dst) | IMM_I12(0));
+
+	case SLJIT_REV_U32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1);
+		FAIL_IF(push_inst(compiler, REVB_2W | RD(dst) | RJ(src2)));
+		return push_inst(compiler, BSTRPICK_D | RD(dst) | RJ(dst) | (31 << 16));
+
+	case SLJIT_ADD:
+		/* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */
+		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+		carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+		if (flags & SRC2_IMM) {
+			if (is_overflow) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
+				else {
+					FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(TMP_ZERO) | IMM_I12(-1)));
+					FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG)));
+				}
+			}
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+			/* Only the zero flag is needed. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(src2)));
+		}
+		else {
+			if (is_overflow)
+				FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, INST(ADD, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+			if (is_overflow || carry_src_r != 0) {
+				if (src1 != dst)
+					carry_src_r = (sljit_s32)src1;
+				else if (src2 != dst)
+					carry_src_r = (sljit_s32)src2;
+				else {
+					FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(0)));
+					carry_src_r = OTHER_FLAG;
+				}
+			}
+
+			/* Only the zero flag is needed. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, INST(ADD, op) | RD(dst) | RJ(src1) | RK(src2)));
+		}
+
+		/* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */
+		if (is_overflow || carry_src_r != 0) {
+			if (flags & SRC2_IMM)
+				FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(dst) | IMM_I12(src2)));
+			else
+				FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(dst) | RK(carry_src_r)));
+		}
+
+		if (!is_overflow)
+			return SLJIT_SUCCESS;
+
+		FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RJ(dst) | RK(EQUAL_FLAG)));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, INST(ADD, op) | RD(EQUAL_FLAG) | RJ(dst) | IMM_I12(0)));
+		FAIL_IF(push_inst(compiler, INST(SRLI, op) | RD(TMP_REG1) | RJ(TMP_REG1) | IMM_EXTEND(31)));
+		return push_inst(compiler, XOR | RD(OTHER_FLAG) | RJ(TMP_REG1) | RK(OTHER_FLAG));
+
+	case SLJIT_ADDC:
+		carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+		if (flags & SRC2_IMM) {
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(dst) | RJ(src1) | IMM_I12(src2)));
+		} else {
+			if (carry_src_r != 0) {
+				if (src1 != dst)
+					carry_src_r = (sljit_s32)src1;
+				else if (src2 != dst)
+					carry_src_r = (sljit_s32)src2;
+				else {
+					FAIL_IF(push_inst(compiler, ADDI_D | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
+					carry_src_r = EQUAL_FLAG;
+				}
+			}
+
+			FAIL_IF(push_inst(compiler, ADD_D | RD(dst) | RJ(src1) | RK(src2)));
+		}
+
+		/* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */
+		if (carry_src_r != 0) {
+			if (flags & SRC2_IMM)
+				FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(dst) | IMM_I12(src2)));
+			else
+				FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RJ(dst) | RK(carry_src_r)));
+		}
+
+		FAIL_IF(push_inst(compiler, ADD_D | RD(dst) | RJ(dst) | RK(OTHER_FLAG)));
+
+		if (carry_src_r == 0)
+			return SLJIT_SUCCESS;
+
+		/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
+		FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(dst) | RK(OTHER_FLAG)));
+		/* Set carry flag. */
+		return push_inst(compiler, OR | RD(OTHER_FLAG) | RJ(OTHER_FLAG) | RK(EQUAL_FLAG));
+
+	case SLJIT_SUB:
+		if ((flags & SRC2_IMM) && src2 == I12_MIN) {
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(src2)));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		is_handled = 0;
+
+		if (flags & SRC2_IMM) {
+			if (GET_FLAG_TYPE(op) == SLJIT_LESS) {
+				FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2)));
+				is_handled = 1;
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) {
+				FAIL_IF(push_inst(compiler, SLTI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2)));
+				is_handled = 1;
+			}
+		}
+
+		if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+			is_handled = 1;
+
+			if (flags & SRC2_IMM) {
+				FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(src2)));
+				src2 = TMP_REG2;
+				flags &= ~SRC2_IMM;
+			}
+
+			switch (GET_FLAG_TYPE(op)) {
+			case SLJIT_LESS:
+				FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+				break;
+			case SLJIT_GREATER:
+				FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(src2) | RK(src1)));
+				break;
+			case SLJIT_SIG_LESS:
+				FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+				break;
+			case SLJIT_SIG_GREATER:
+				FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RJ(src2) | RK(src1)));
+				break;
+			}
+		}
+
+		if (is_handled) {
+			if (flags & SRC2_IMM) {
+				if (op & SLJIT_SET_Z)
+					FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-src2)));
+				if (!(flags & UNUSED_DEST))
+					return push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2));
+			}
+			else {
+				if (op & SLJIT_SET_Z)
+					FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+				if (!(flags & UNUSED_DEST))
+					return push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(src1) | RK(src2));
+			}
+			return SLJIT_SUCCESS;
+		}
+
+		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+		is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+		if (flags & SRC2_IMM) {
+			if (is_overflow) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
+				else {
+					FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-1)));
+					FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG)));
+				}
+			}
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-src2)));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+			/* Only the zero flag is needed. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2)));
+		}
+		else {
+			if (is_overflow)
+				FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+
+			/* Only the zero flag is needed. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(src1) | RK(src2)));
+		}
+
+		if (!is_overflow)
+			return SLJIT_SUCCESS;
+
+		FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RJ(dst) | RK(EQUAL_FLAG)));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(dst) | IMM_I12(0)));
+		FAIL_IF(push_inst(compiler, INST(SRLI, op) | RD(TMP_REG1) | RJ(TMP_REG1) | IMM_EXTEND(31)));
+		return push_inst(compiler, XOR | RD(OTHER_FLAG) | RJ(TMP_REG1) | RK(OTHER_FLAG));
+
+	case SLJIT_SUBC:
+		if ((flags & SRC2_IMM) && src2 == I12_MIN) {
+			FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(src2)));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+		if (flags & SRC2_IMM) {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+			FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2)));
+		}
+		else {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+			FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(src1) | RK(src2)));
+		}
+
+		if (is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | RD(TMP_REG1) | RJ(dst) | RK(OTHER_FLAG)));
+
+		FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(dst) | RK(OTHER_FLAG)));
+
+		if (!is_carry)
+			return SLJIT_SUCCESS;
+
+		return push_inst(compiler, OR | RD(OTHER_FLAG) | RJ(EQUAL_FLAG) | RK(TMP_REG1));
+
+	case SLJIT_MUL:
+		SLJIT_ASSERT(!(flags & SRC2_IMM));
+
+		if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW)
+			return push_inst(compiler, INST(MUL, op) | RD(dst) | RJ(src1) | RK(src2));
+
+		if (op & SLJIT_32) {
+			FAIL_IF(push_inst(compiler, MUL_D | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+			FAIL_IF(push_inst(compiler, MUL_W | RD(dst) | RJ(src1) | RK(src2)));
+			return push_inst(compiler, SUB_D | RD(OTHER_FLAG) | RJ(dst) | RK(OTHER_FLAG));
+		}
+
+		FAIL_IF(push_inst(compiler, MULH_D | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+		FAIL_IF(push_inst(compiler, MUL_D | RD(dst) | RJ(src1) | RK(src2)));
+		FAIL_IF(push_inst(compiler, SRAI_D | RD(OTHER_FLAG) | RJ(dst) | IMM_I12((63))));
+		return push_inst(compiler, SUB_D | RD(OTHER_FLAG) | RJ(EQUAL_FLAG) | RK(OTHER_FLAG));
+
+	case SLJIT_AND:
+		EMIT_LOGICAL(ANDI, AND);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_OR:
+		EMIT_LOGICAL(ORI, OR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_XOR:
+		EMIT_LOGICAL(XORI, XOR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_SHL:
+	case SLJIT_MSHL:
+		if (op & SLJIT_32) {
+			EMIT_SHIFT(SLLI_W, SLL_W);
+		} else {
+			EMIT_SHIFT(SLLI_D, SLL_D);
+		}
+		break;
+
+	case SLJIT_LSHR:
+	case SLJIT_MLSHR:
+		if (op & SLJIT_32) {
+			EMIT_SHIFT(SRLI_W, SRL_W);
+		} else {
+			EMIT_SHIFT(SRLI_D, SRL_D);
+		}
+		break;
+
+	case SLJIT_ASHR:
+	case SLJIT_MASHR:
+		if (op & SLJIT_32) {
+			EMIT_SHIFT(SRAI_W, SRA_W);
+		} else {
+			EMIT_SHIFT(SRAI_D, SRA_D);
+		}
+		break;
+
+	case SLJIT_ROTL:
+	case SLJIT_ROTR:
+		if (flags & SRC2_IMM) {
+			SLJIT_ASSERT(src2 != 0);
+
+			if (GET_OPCODE(op) == SLJIT_ROTL)
+				src2 = word_size - src2;
+			return push_inst(compiler, INST(ROTRI, op) | RD(dst) | RJ(src1) | IMM_I12(src2));
+
+		}
+
+		if (src2 == TMP_ZERO) {
+			if (dst != src1)
+				return push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(0));
+			return SLJIT_SUCCESS;
+		}
+
+		if (GET_OPCODE(op) == SLJIT_ROTL) {
+			FAIL_IF(push_inst(compiler, INST(SUB, op)| RD(OTHER_FLAG) | RJ(TMP_ZERO) | RK(src2)));
+			src2 = OTHER_FLAG;
+		}
+		return push_inst(compiler, INST(ROTR, op) | RD(dst) | RJ(src1) | RK(src2));
+
+	default:
+		SLJIT_UNREACHABLE();
+		return SLJIT_SUCCESS;
+	}
+
+	if (flags & SRC2_IMM) {
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, op_imm | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+		if (flags & UNUSED_DEST)
+			return SLJIT_SUCCESS;
+		return push_inst(compiler, op_imm | RD(dst) | RJ(src1) | IMM_I12(src2));
+	}
+
+	if (op & SLJIT_SET_Z)
+		FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+	if (flags & UNUSED_DEST)
+		return SLJIT_SUCCESS;
+	return push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(src2));
+}
+
+#undef IMM_EXTEND
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* arg1 goes to TMP_REG1 or src reg
+	   arg2 goes to TMP_REG2, imm or src reg
+	   TMP_REG3 can be used for caching
+	   result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
+	sljit_s32 dst_r = TMP_REG2;
+	sljit_s32 src1_r;
+	sljit_sw src2_r = 0;
+	sljit_s32 sugg_src2_r = TMP_REG2;
+
+	if (!(flags & ALT_KEEP_CACHE)) {
+		compiler->cache_arg = 0;
+		compiler->cache_argw = 0;
+	}
+
+	if (dst == 0) {
+		SLJIT_ASSERT(HAS_FLAGS(op));
+		flags |= UNUSED_DEST;
+		dst = TMP_REG2;
+	}
+	else if (FAST_IS_REG(dst)) {
+		dst_r = dst;
+		flags |= REG_DEST;
+		if (flags & MOVE_OP)
+			sugg_src2_r = dst_r;
+	}
+	else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
+		flags |= SLOW_DEST;
+
+	if (flags & IMM_OP) {
+		if (src2 == SLJIT_IMM && src2w != 0 && src2w <= I12_MAX && src2w >= I12_MIN) {
+			flags |= SRC2_IMM;
+			src2_r = src2w;
+		}
+		else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && src1w <= I12_MAX && src1w >= I12_MIN) {
+			flags |= SRC2_IMM;
+			src2_r = src1w;
+
+			/* And swap arguments. */
+			src1 = src2;
+			src1w = src2w;
+			src2 = SLJIT_IMM;
+			/* src2w = src2_r unneeded. */
+		}
+	}
+
+	/* Source 1. */
+	if (FAST_IS_REG(src1)) {
+		src1_r = src1;
+		flags |= REG1_SOURCE;
+	}
+	else if (src1 == SLJIT_IMM) {
+		if (src1w) {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+			src1_r = TMP_REG1;
+		}
+		else
+			src1_r = TMP_ZERO;
+	}
+	else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC1;
+		src1_r = TMP_REG1;
+	}
+
+	/* Source 2. */
+	if (FAST_IS_REG(src2)) {
+		src2_r = src2;
+		flags |= REG2_SOURCE;
+		if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP)
+			dst_r = (sljit_s32)src2_r;
+	}
+	else if (src2 == SLJIT_IMM) {
+		if (!(flags & SRC2_IMM)) {
+			if (src2w) {
+				FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
+				src2_r = sugg_src2_r;
+			}
+			else {
+				src2_r = TMP_ZERO;
+				if (flags & MOVE_OP) {
+					if (dst & SLJIT_MEM)
+						dst_r = 0;
+					else
+						op = SLJIT_MOV;
+				}
+			}
+		}
+	}
+	else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC2;
+
+		src2_r = sugg_src2_r;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		SLJIT_ASSERT(src2_r == TMP_REG2);
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
+		}
+		else {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
+		}
+	}
+	else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
+
+	FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
+
+	if (dst & SLJIT_MEM) {
+		if (!(flags & SLOW_DEST)) {
+			getput_arg_fast(compiler, flags, dst_r, dst, dstw);
+			return compiler->error;
+		}
+		return getput_arg(compiler, flags, dst_r, dst, dstw, 0, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_BREAKPOINT:
+		return push_inst(compiler, BREAK);
+	case SLJIT_NOP:
+		return push_inst(compiler, ANDI | RD(TMP_ZERO) | RJ(TMP_ZERO) | IMM_I12(0));
+	case SLJIT_LMUL_UW:
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(SLJIT_R1) | IMM_I12(0)));
+		FAIL_IF(push_inst(compiler, MULH_DU | RD(SLJIT_R1) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+		return push_inst(compiler, MUL_D | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(TMP_REG1));
+	case SLJIT_LMUL_SW:
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(SLJIT_R1) | IMM_I12(0)));
+		FAIL_IF(push_inst(compiler, MULH_D | RD(SLJIT_R1) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+		return push_inst(compiler, MUL_D | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(TMP_REG1));
+	case SLJIT_DIVMOD_UW:
+		FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(TMP_REG1) | RJ(SLJIT_R0) | IMM_I12(0)));
+		FAIL_IF(push_inst(compiler, ((op & SLJIT_32)? DIV_WU: DIV_DU) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+		return push_inst(compiler, ((op & SLJIT_32)? MOD_WU: MOD_DU) | RD(SLJIT_R1) | RJ(TMP_REG1) | RK(SLJIT_R1));
+	case SLJIT_DIVMOD_SW:
+		FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(TMP_REG1) | RJ(SLJIT_R0) | IMM_I12(0)));
+		FAIL_IF(push_inst(compiler, INST(DIV, op) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+		return push_inst(compiler, INST(MOD, op) | RD(SLJIT_R1) | RJ(TMP_REG1) | RK(SLJIT_R1));
+	case SLJIT_DIV_UW:
+		return push_inst(compiler, ((op & SLJIT_32)? DIV_WU: DIV_DU) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1));
+	case SLJIT_DIV_SW:
+		return push_inst(compiler, INST(DIV, op) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1));
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 flags = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	if (op & SLJIT_32)
+		flags = INT_DATA | SIGNED_DATA;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U32:
+		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw);
+
+	case SLJIT_MOV_S32:
+	/* Logical operators have no W variant, so sign extended input is necessary for them. */
+	case SLJIT_MOV32:
+		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw);
+
+	case SLJIT_MOV_U8:
+		return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+
+	case SLJIT_MOV_S8:
+		return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+
+	case SLJIT_MOV_U16:
+		return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+
+	case SLJIT_MOV_S16:
+		return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw);
+
+	case SLJIT_CLZ:
+	case SLJIT_CTZ:
+	case SLJIT_REV:
+		return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_REV_U16:
+	case SLJIT_REV_S16:
+		return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_REV_U32:
+	case SLJIT_REV_S32:
+		return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 flags = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (op & SLJIT_32) {
+		flags |= INT_DATA | SIGNED_DATA;
+		if (src1 == SLJIT_IMM)
+			src1w = (sljit_s32)src1w;
+		if (src2 == SLJIT_IMM)
+			src2w = (sljit_s32)src2w;
+	}
+
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD:
+	case SLJIT_ADDC:
+		compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
+		return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SUB:
+	case SLJIT_SUBC:
+		compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
+		return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_MUL:
+		compiler->status_flags_state = 0;
+		return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_AND:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+		return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SHL:
+	case SLJIT_MSHL:
+	case SLJIT_LSHR:
+	case SLJIT_MLSHR:
+	case SLJIT_ASHR:
+	case SLJIT_MASHR:
+	case SLJIT_ROTL:
+	case SLJIT_ROTR:
+		if (src2 == SLJIT_IMM) {
+			if (op & SLJIT_32)
+				src2w &= 0x1f;
+			else
+				src2w &= 0x3f;
+		}
+
+		return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
+
+	SLJIT_SKIP_CHECKS(compiler);
+	return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst_reg,
+	sljit_s32 src1_reg,
+	sljit_s32 src2_reg,
+	sljit_s32 src3, sljit_sw src3w)
+{
+	sljit_s32 is_left;
+	sljit_ins ins1, ins2, ins3;
+	sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+	sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64;
+
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
+
+	is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
+
+	if (src1_reg == src2_reg) {
+		SLJIT_SKIP_CHECKS(compiler);
+		return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
+	}
+
+	ADJUST_LOCAL_OFFSET(src3, src3w);
+
+	if (src3 == SLJIT_IMM) {
+		src3w &= bit_length - 1;
+
+		if (src3w == 0)
+			return SLJIT_SUCCESS;
+
+		if (is_left) {
+			ins1 = INST(SLLI, op) | IMM_I12(src3w);
+			src3w = bit_length - src3w;
+			ins2 = INST(SRLI, op) | IMM_I12(src3w);
+		} else {
+			ins1 = INST(SRLI, op) | IMM_I12(src3w);
+			src3w = bit_length - src3w;
+			ins2 = INST(SLLI, op) | IMM_I12(src3w);
+		}
+
+		FAIL_IF(push_inst(compiler, ins1 | RD(dst_reg) | RJ(src1_reg)));
+		FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RJ(src2_reg)));
+		return push_inst(compiler, OR | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG1));
+	}
+
+	if (src3 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src3, src3w));
+		src3 = TMP_REG2;
+	} else if (dst_reg == src3) {
+		push_inst(compiler, INST(ADDI, op) | RD(TMP_REG2) | RJ(src3) | IMM_I12(0));
+		src3 = TMP_REG2;
+	}
+
+	if (is_left) {
+		ins1 = INST(SLL, op);
+		ins2 = INST(SRLI, op);
+		ins3 = INST(SRL, op);
+	} else {
+		ins1 = INST(SRL, op);
+		ins2 = INST(SLLI, op);
+		ins3 = INST(SLL, op);
+	}
+
+	FAIL_IF(push_inst(compiler, ins1 | RD(dst_reg) | RJ(src1_reg) | RK(src3)));
+
+	if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
+		FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RJ(src2_reg) | IMM_I12(1)));
+		FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RJ(src3) | IMM_I12((sljit_ins)bit_length - 1)));
+		src2_reg = TMP_REG1;
+	} else
+		FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(TMP_REG2) | RJ(TMP_ZERO) | RK(src3)));
+
+	FAIL_IF(push_inst(compiler, ins3 | RD(TMP_REG1) | RJ(src2_reg) | RK(TMP_REG2)));
+	return push_inst(compiler, OR | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG1));
+}
+
+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 base = src & REG_MASK;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(RETURN_ADDR_REG) | RJ(src) | IMM_I12(0)));
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw));
+
+		return push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+		if (SLJIT_UNLIKELY(src & OFFS_REG_MASK)) {
+			srcw &= 0x3;
+			if (SLJIT_UNLIKELY(srcw))
+				FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG1) | RJ(OFFS_REG(src)) | IMM_I12(srcw)));
+			FAIL_IF(push_inst(compiler, ADD_D | RD(TMP_REG1) | RJ(base) | RK(TMP_REG1)));
+		} else {
+			if (base && srcw <= I12_MAX && srcw >= I12_MIN)
+				return push_inst(compiler,PRELD | RJ(base) | IMM_I12(srcw));
+
+			FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+			if (base != 0)
+				FAIL_IF(push_inst(compiler, ADD_D | RD(TMP_REG1) | RJ(base) | RK(TMP_REG1)));
+		}
+		return push_inst(compiler, PRELD | RD(0) | RJ(TMP_REG1));
+	}
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	switch (op) {
+	case SLJIT_FAST_ENTER:
+		if (FAST_IS_REG(dst))
+			return push_inst(compiler, ADDI_D | RD(dst) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
+
+		SLJIT_ASSERT(RETURN_ADDR_REG == TMP_REG2);
+		break;
+	case SLJIT_GET_RETURN_ADDRESS:
+		dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size - SSIZE_OF(sw)));
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+	if (type == SLJIT_GP_REGISTER)
+		return reg_map[reg];
+
+	if (type != SLJIT_FLOAT_REGISTER)
+		return -1;
+
+	return freg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_u32 size)
+{
+	SLJIT_UNUSED_ARG(size);
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	return push_inst(compiler, *(sljit_ins*)instruction);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+#define SET_COND(cond) (sljit_ins)(cond << 15)
+
+#define COND_CUN SET_COND(0x8)	 /* UN */
+#define COND_CEQ SET_COND(0x4)	 /* EQ */
+#define COND_CUEQ SET_COND(0xc)	 /* UN EQ */
+#define COND_CLT SET_COND(0x2)	 /* LT */
+#define COND_CULT SET_COND(0xa)	 /* UN LT */
+#define COND_CLE SET_COND(0x6)	 /* LT EQ */
+#define COND_CULE SET_COND(0xe)	 /* UN LT EQ */
+#define COND_CNE SET_COND(0x10)	 /* GT LT */
+#define COND_CUNE SET_COND(0x18) /* UN GT LT */
+#define COND_COR SET_COND(0x14)	 /* GT LT EQ */
+
+#define FINST(inst, type) (sljit_ins)((type & SLJIT_32) ? inst##_S : inst##_D)
+#define FCD(cd) (sljit_ins)(cd & 0x7)
+#define FCJ(cj) (sljit_ins)((cj & 0x7) << 5)
+#define FCA(ca) (sljit_ins)((ca & 0x7) << 15)
+#define F_OTHER_FLAG 1
+
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 7))
+
+/* convert to inter exact toward zero */
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins inst;
+	sljit_u32 word_data = 0;
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+
+	switch (GET_OPCODE(op))
+	{
+	case SLJIT_CONV_SW_FROM_F64:
+		word_data = 1;
+		inst = FINST(FTINTRZ_L, op);
+		break;
+	case SLJIT_CONV_S32_FROM_F64:
+		inst = FINST(FTINTRZ_W, op);
+		break;
+	default:
+		inst = BREAK;
+		SLJIT_UNREACHABLE();
+	}
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
+		src = TMP_FREG1;
+	}
+
+	FAIL_IF(push_inst(compiler, inst | FRD(TMP_FREG1) | FRJ(src)));
+	FAIL_IF(push_inst(compiler, FINST(MOVFR2GR, word_data) | RD(dst_r) | FRJ(TMP_FREG1)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, word_data ? WORD_DATA : INT_DATA, TMP_REG2, dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins inst;
+	sljit_u32 word_data = 0;
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	switch (GET_OPCODE(op))
+	{
+	case SLJIT_CONV_F64_FROM_SW:
+		word_data = 1;
+		inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_L : FFINT_D_L);
+		break;
+	case SLJIT_CONV_F64_FROM_S32:
+		inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_W : FFINT_D_W);
+		break;
+	default:
+		inst = BREAK;
+		SLJIT_UNREACHABLE();
+	}
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, (word_data ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
+		src = TMP_REG1;
+	} else if (src == SLJIT_IMM) {
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	}
+	FAIL_IF(push_inst(compiler, (word_data ? MOVGR2FR_D : MOVGR2FR_W) | FRD(dst_r) | RJ(src)));
+	FAIL_IF(push_inst(compiler, inst | FRD(dst_r) | FRJ(dst_r)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	return sljit_emit_fop1_conv_f64_from_w(compiler, op, dst, dstw, src, srcw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins inst;
+	sljit_u32 word_data = 0;
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	switch (GET_OPCODE(op))
+	{
+	case SLJIT_CONV_F64_FROM_UW:
+		word_data = 1;
+		inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_L : FFINT_D_L);
+		break;
+	case SLJIT_CONV_F64_FROM_U32:
+		inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_W : FFINT_D_W);
+		break;
+	default:
+		inst = BREAK;
+		SLJIT_UNREACHABLE();
+	}
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, (word_data ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
+		src = TMP_REG1;
+	} else if (src == SLJIT_IMM) {
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32)
+			srcw = (sljit_u32)srcw;
+
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	}
+
+	if (!word_data)
+		FAIL_IF(push_inst(compiler, SRLI_W | RD(src) | RJ(src) | IMM_I12(0)));
+
+	FAIL_IF(push_inst(compiler, BLT | RJ(src) | RD(TMP_ZERO) | IMM_I16(4)));
+
+	FAIL_IF(push_inst(compiler, (word_data ? MOVGR2FR_D : MOVGR2FR_W) | FRD(dst_r) | RJ(src)));
+	FAIL_IF(push_inst(compiler, inst | FRD(dst_r) | FRJ(dst_r)));
+	FAIL_IF(push_inst(compiler, B | IMM_I26(7)));
+
+	FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG2) | RJ(src) | IMM_I12(1)));
+	FAIL_IF(push_inst(compiler, (word_data ? SRLI_D : SRLI_W) | RD(TMP_REG1) | RJ(src) | IMM_I12(1)));
+	FAIL_IF(push_inst(compiler, OR | RD(TMP_REG1) | RJ(TMP_REG1) | RK(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, INST(MOVGR2FR, (!word_data)) | FRD(dst_r) | RJ(TMP_REG1)));
+	FAIL_IF(push_inst(compiler, inst | FRD(dst_r) | FRJ(dst_r)));
+	FAIL_IF(push_inst(compiler, FINST(FADD, op) | FRD(dst_r) | FRJ(dst_r) | FRK(dst_r)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0));
+		src2 = TMP_FREG2;
+	}
+
+	FAIL_IF(push_inst(compiler, XOR | RD(OTHER_FLAG) | RJ(OTHER_FLAG) | RK(OTHER_FLAG)));
+
+	switch (GET_FLAG_TYPE(op)) {
+	case SLJIT_F_EQUAL:
+	case SLJIT_ORDERED_EQUAL:
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CEQ | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+		break;
+	case SLJIT_F_LESS:
+	case SLJIT_ORDERED_LESS:
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CLT | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+		break;
+	case SLJIT_F_GREATER:
+	case SLJIT_ORDERED_GREATER:
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CLT | FCD(F_OTHER_FLAG) | FRJ(src2) | FRK(src1)));
+		break;
+	case SLJIT_UNORDERED_OR_GREATER:
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CULT | FCD(F_OTHER_FLAG) | FRJ(src2) | FRK(src1)));
+		break;
+	case SLJIT_UNORDERED_OR_LESS:
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CULT | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+		break;
+	case SLJIT_UNORDERED_OR_EQUAL:
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CUEQ | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+		break;
+	default: /* SLJIT_UNORDERED */
+		FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CUN | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+	}
+	return push_inst(compiler, MOVCF2GR | RD(OTHER_FLAG) | FCJ(F_OTHER_FLAG));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+		op ^= SLJIT_32;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, dst, dstw));
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1)
+				FAIL_IF(push_inst(compiler, FINST(FMOV, op) | FRD(dst_r) | FRJ(src)));
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst(compiler, FINST(FNEG, op) | FRD(dst_r) | FRJ(src)));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst(compiler, FINST(FABS, op) | FRD(dst_r) | FRJ(src)));
+		break;
+	case SLJIT_CONV_F64_FROM_F32:
+		/* The SLJIT_32 bit is inverted because sljit_f32 needs to be loaded from the memory. */
+		FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? FCVT_D_S : FCVT_S_D) | FRD(dst_r) | FRJ(src)));
+		op ^= SLJIT_32;
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, FLOAT_DATA(op), dst_r, dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r, flags = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
+
+	if (src1 & SLJIT_MEM) {
+		if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) {
+			FAIL_IF(compiler->error);
+			src1 = TMP_FREG1;
+		} else
+			flags |= SLOW_SRC1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) {
+			FAIL_IF(compiler->error);
+			src2 = TMP_FREG2;
+		} else
+			flags |= SLOW_SRC2;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
+		}
+		else {
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
+		}
+	}
+	else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
+
+	if (flags & SLOW_SRC1)
+		src1 = TMP_FREG1;
+	if (flags & SLOW_SRC2)
+		src2 = TMP_FREG2;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst(compiler, FINST(FADD, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+		break;
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst(compiler, FINST(FSUB, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+		break;
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst(compiler, FINST(FMUL, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+		break;
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst(compiler, FINST(FDIV, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+		break;
+	}
+
+	if (dst_r == TMP_FREG2)
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst_freg,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 reg;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2r(compiler, op, dst_freg, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src2, src2w, 0, 0));
+		src2 = TMP_FREG1;
+	}
+
+	if (src1 & SLJIT_MEM) {
+		reg = (dst_freg == src2) ? TMP_FREG1 : dst_freg;
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, reg, src1, src1w, 0, 0));
+		src1 = reg;
+	}
+
+	return push_inst(compiler, FINST(FCOPYSIGN, op) | FRD(dst_freg) | FRJ(src1) | FRK(src2));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f32 value)
+{
+	union {
+		sljit_s32 imm;
+		sljit_f32 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm == 0)
+		return push_inst(compiler, MOVGR2FR_W | RJ(TMP_ZERO) | FRD(freg));
+
+	FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+	return push_inst(compiler, MOVGR2FR_W | RJ(TMP_REG1) | FRD(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_sw imm;
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm == 0)
+		return push_inst(compiler, MOVGR2FR_D | RJ(TMP_ZERO) | FRD(freg));
+
+	FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+	return push_inst(compiler, MOVGR2FR_D | RJ(TMP_REG1) | FRD(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_ins inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+		inst = ((op & SLJIT_32) ? MOVGR2FR_W : MOVGR2FR_D) | FRD(freg) | RJ(reg);
+	else
+		inst = ((op & SLJIT_32) ? MOVFR2GR_S : MOVFR2GR_D) | RD(reg) | FRJ(freg);
+	return push_inst(compiler, inst);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	return label;
+}
+
+static sljit_ins get_jump_instruction(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+	case SLJIT_ATOMIC_NOT_STORED:
+		return BNE | RJ(EQUAL_FLAG) | RD(TMP_ZERO);
+	case SLJIT_NOT_EQUAL:
+	case SLJIT_ATOMIC_STORED:
+		return BEQ | RJ(EQUAL_FLAG) | RD(TMP_ZERO);
+	case SLJIT_LESS:
+	case SLJIT_GREATER:
+	case SLJIT_SIG_LESS:
+	case SLJIT_SIG_GREATER:
+	case SLJIT_OVERFLOW:
+	case SLJIT_CARRY:
+		return BEQ | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_SIG_GREATER_EQUAL:
+	case SLJIT_SIG_LESS_EQUAL:
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_NOT_CARRY:
+		return BNE | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+	case SLJIT_F_EQUAL:
+	case SLJIT_ORDERED_EQUAL:
+	case SLJIT_F_LESS:
+	case SLJIT_ORDERED_LESS:
+	case SLJIT_ORDERED_GREATER:
+	case SLJIT_UNORDERED_OR_GREATER:
+	case SLJIT_F_GREATER:
+	case SLJIT_UNORDERED_OR_LESS:
+	case SLJIT_UNORDERED_OR_EQUAL:
+	case SLJIT_UNORDERED:
+		return BEQ | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+	case SLJIT_ORDERED_NOT_EQUAL:
+	case SLJIT_ORDERED_LESS_EQUAL:
+	case SLJIT_ORDERED_GREATER_EQUAL:
+	case SLJIT_F_NOT_EQUAL:
+	case SLJIT_UNORDERED_OR_NOT_EQUAL:
+	case SLJIT_UNORDERED_OR_GREATER_EQUAL:
+	case SLJIT_UNORDERED_OR_LESS_EQUAL:
+	case SLJIT_F_LESS_EQUAL:
+	case SLJIT_F_GREATER_EQUAL:
+	case SLJIT_ORDERED:
+		return BNE | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+	default:
+		/* Not conditional branch. */
+		return 0;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+	sljit_ins inst;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	inst = get_jump_instruction(type);
+
+	if (inst != 0) {
+		PTR_FAIL_IF(push_inst(compiler, inst));
+		jump->flags |= IS_COND;
+	}
+
+	jump->addr = compiler->size;
+	inst = JIRL | RJ(TMP_REG1) | IMM_I16(0);
+
+	if (type >= SLJIT_FAST_CALL) {
+		jump->flags |= IS_CALL;
+		inst |= RD(RETURN_ADDR_REG);
+	}
+
+	PTR_FAIL_IF(push_inst(compiler, inst));
+
+	/* Maximum number of instructions required for generating a constant. */
+	compiler->size += 3;
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	SLJIT_UNUSED_ARG(arg_types);
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+	if (type & SLJIT_CALL_RETURN) {
+		PTR_FAIL_IF(emit_stack_frame_release(compiler, 0));
+		type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP);
+	}
+
+	SLJIT_SKIP_CHECKS(compiler);
+	return sljit_emit_jump(compiler, type);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	struct sljit_jump *jump;
+	sljit_s32 flags;
+	sljit_ins inst;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+
+	if (src1 & SLJIT_MEM) {
+		PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG1, src1, src1w, src2, src2w));
+		src1 = TMP_REG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG2, src2, src2w, 0, 0));
+		src2 = TMP_REG2;
+	}
+
+	if (src1 == SLJIT_IMM) {
+		if (src1w != 0) {
+			PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+			src1 = TMP_REG1;
+		}
+		else
+			src1 = TMP_ZERO;
+	}
+
+	if (src2 == SLJIT_IMM) {
+		if (src2w != 0) {
+			PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w));
+			src2 = TMP_REG2;
+		}
+		else
+			src2 = TMP_ZERO;
+	}
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, (sljit_u32)((type & SLJIT_REWRITABLE_JUMP) | IS_COND));
+	type &= 0xff;
+
+	switch (type) {
+	case SLJIT_EQUAL:
+		inst = BNE | RJ(src1) | RD(src2);
+		break;
+	case SLJIT_NOT_EQUAL:
+		inst = BEQ | RJ(src1) | RD(src2);
+		break;
+	case SLJIT_LESS:
+		inst = BGEU | RJ(src1) | RD(src2);
+		break;
+	case SLJIT_GREATER_EQUAL:
+		inst = BLTU | RJ(src1) | RD(src2);
+		break;
+	case SLJIT_GREATER:
+		inst = BGEU | RJ(src2) | RD(src1);
+		break;
+	case SLJIT_LESS_EQUAL:
+		inst = BLTU | RJ(src2) | RD(src1);
+		break;
+	case SLJIT_SIG_LESS:
+		inst = BGE | RJ(src1) | RD(src2);
+		break;
+	case SLJIT_SIG_GREATER_EQUAL:
+		inst = BLT | RJ(src1) | RD(src2);
+		break;
+	case SLJIT_SIG_GREATER:
+		inst = BGE | RJ(src2) | RD(src1);
+		break;
+	case SLJIT_SIG_LESS_EQUAL:
+		inst = BLT | RJ(src2) | RD(src1);
+		break;
+	default:
+		inst = BREAK;
+		SLJIT_UNREACHABLE();
+	}
+
+	PTR_FAIL_IF(push_inst(compiler, inst));
+
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(TMP_REG1) | IMM_I12(0)));
+
+	/* Maximum number of instructions required for generating a constant. */
+	compiler->size += 3;
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+
+	if (src != SLJIT_IMM) {
+		if (src & SLJIT_MEM) {
+			ADJUST_LOCAL_OFFSET(src, srcw);
+			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+			src = TMP_REG1;
+		}
+		return push_inst(compiler, JIRL | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RJ(src) | IMM_I12(0));
+	}
+
+	/* These jumps are converted to jump/call instructions when possible. */
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	FAIL_IF(!jump);
+	set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_CALL : 0));
+	jump->u.target = (sljit_uw)srcw;
+
+	jump->addr = compiler->size;
+	FAIL_IF(push_inst(compiler, JIRL | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RJ(TMP_REG1) | IMM_I12(0)));
+
+	/* Maximum number of instructions required for generating a constant. */
+	compiler->size += 3;
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(arg_types);
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+	if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+		src = TMP_REG1;
+	}
+
+	if (type & SLJIT_CALL_RETURN) {
+		if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(src) | IMM_I12(0)));
+			src = TMP_REG1;
+		}
+
+		FAIL_IF(emit_stack_frame_release(compiler, 0));
+		type = SLJIT_JUMP;
+	}
+
+	SLJIT_SKIP_CHECKS(compiler);
+	return sljit_emit_ijump(compiler, type, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 src_r, dst_r, invert;
+	sljit_s32 saved_op = op;
+	sljit_s32 mem_type = ((op & SLJIT_32) || op == SLJIT_MOV32) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	op = GET_OPCODE(op);
+	dst_r = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
+		FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
+
+	if (type < SLJIT_F_EQUAL) {
+		src_r = OTHER_FLAG;
+		invert = type & 0x1;
+
+		switch (type) {
+		case SLJIT_EQUAL:
+		case SLJIT_NOT_EQUAL:
+			FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(EQUAL_FLAG) | IMM_I12(1)));
+			src_r = dst_r;
+			break;
+		case SLJIT_ATOMIC_STORED:
+		case SLJIT_ATOMIC_NOT_STORED:
+			FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(EQUAL_FLAG) | IMM_I12(1)));
+			src_r = dst_r;
+			invert ^= 0x1;
+			break;
+		case SLJIT_OVERFLOW:
+		case SLJIT_NOT_OVERFLOW:
+			if (compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)) {
+				src_r = OTHER_FLAG;
+				break;
+			}
+			FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(OTHER_FLAG) | IMM_I12(1)));
+			src_r = dst_r;
+			invert ^= 0x1;
+			break;
+		}
+	} else {
+		invert = 0;
+		src_r = OTHER_FLAG;
+
+		switch (type) {
+		case SLJIT_ORDERED_NOT_EQUAL:
+		case SLJIT_ORDERED_LESS_EQUAL:
+		case SLJIT_ORDERED_GREATER_EQUAL:
+		case SLJIT_F_NOT_EQUAL:
+		case SLJIT_UNORDERED_OR_NOT_EQUAL:
+		case SLJIT_UNORDERED_OR_GREATER_EQUAL:
+		case SLJIT_UNORDERED_OR_LESS_EQUAL:
+		case SLJIT_F_LESS_EQUAL:
+		case SLJIT_F_GREATER_EQUAL:
+		case SLJIT_ORDERED:
+			invert = 1;
+			break;
+		}
+	}
+
+	if (invert) {
+		FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RJ(src_r) | IMM_I12(1)));
+		src_r = dst_r;
+	}
+
+	if (op < SLJIT_ADD) {
+		if (dst & SLJIT_MEM)
+			return emit_op_mem(compiler, mem_type, src_r, dst, dstw);
+
+		if (src_r != dst_r)
+			return push_inst(compiler, ADDI_D | RD(dst_r) | RJ(src_r) | IMM_I12(0));
+		return SLJIT_SUCCESS;
+	}
+
+	mem_type |= CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE;
+
+	if (dst & SLJIT_MEM)
+		return emit_op(compiler, saved_op, mem_type, dst, dstw, TMP_REG1, 0, src_r, 0);
+	return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, src_r, 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2_reg)
+{
+	sljit_ins *ptr;
+	sljit_uw size;
+	sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+
+	if (dst_reg != src2_reg) {
+		if (dst_reg == src1) {
+			src1 = src2_reg;
+			src1w = 0;
+			type ^= 0x1;
+		} else {
+			if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+				FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG2) | RJ(dst_reg) | IMM_I12(0)));
+
+				if ((src1 & REG_MASK) == dst_reg)
+					src1 = (src1 & ~REG_MASK) | TMP_REG2;
+
+				if (OFFS_REG(src1) == dst_reg)
+					src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+			}
+
+			FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_reg) | RJ(src2_reg) | IMM_I12(0)));
+		}
+	}
+
+	size = compiler->size;
+
+	ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	compiler->size++;
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w));
+	} else if (src1 == SLJIT_IMM) {
+		if (type & SLJIT_32)
+			src1w = (sljit_s32)src1w;
+		FAIL_IF(load_immediate(compiler, dst_reg, src1w));
+	} else
+		FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_reg) | RJ(src1) | IMM_I12(0)));
+
+	*ptr = get_jump_instruction(type & ~SLJIT_32) | IMM_I16(compiler->size - size);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_freg,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2_freg)
+{
+	sljit_s32 invert = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+
+	if ((type & ~SLJIT_32) == SLJIT_EQUAL || (type & ~SLJIT_32) == SLJIT_NOT_EQUAL) {
+		if ((type & ~SLJIT_32) == SLJIT_EQUAL)
+			invert = 1;
+		FAIL_IF(push_inst(compiler, MOVGR2CF | FCD(F_OTHER_FLAG) | RJ(EQUAL_FLAG)));
+	}
+	else
+		FAIL_IF(push_inst(compiler, MOVGR2CF | FCD(F_OTHER_FLAG) | RJ(OTHER_FLAG)));
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, dst_freg, src1, src1w));
+		if (invert)
+			return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(dst_freg) | FRK(src2_freg) | FCA(F_OTHER_FLAG));
+		return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src2_freg) | FRK(dst_freg) | FCA(F_OTHER_FLAG));
+	} else {
+		if (invert)
+			return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src1) | FRK(src2_freg) | FCA(F_OTHER_FLAG));
+		return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src2_freg) | FRK(src1) | FCA(F_OTHER_FLAG));
+	}
+}
+
+#undef FLOAT_DATA
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_s32 flags;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+	if (!(reg & REG_PAIR_MASK))
+		return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw);
+
+	if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+		memw &= 0x3;
+
+		if (SLJIT_UNLIKELY(memw != 0)) {
+			FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG1) | RJ(OFFS_REG(mem)) | IMM_I12(memw)));
+			FAIL_IF(push_inst(compiler, ADD_D| RD(TMP_REG1) | RJ(TMP_REG1) | RK(mem & REG_MASK)));
+		} else
+			FAIL_IF(push_inst(compiler, ADD_D| RD(TMP_REG1) | RJ(mem & REG_MASK) | RK(OFFS_REG(mem))));
+
+		mem = TMP_REG1;
+		memw = 0;
+	} else if (memw > I12_MAX - SSIZE_OF(sw) || memw < I12_MIN) {
+		if (((memw + 0x800) & 0xfff) <= 0xfff - SSIZE_OF(sw)) {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, TO_ARGW_HI(memw)));
+			memw &= 0xfff;
+		} else {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, memw));
+			memw = 0;
+		}
+
+		if (mem & REG_MASK)
+			FAIL_IF(push_inst(compiler, ADD_D| RD(TMP_REG1) | RJ(TMP_REG1) | RK(mem & REG_MASK)));
+
+		mem = TMP_REG1;
+	} else {
+		mem &= REG_MASK;
+		memw &= 0xfff;
+	}
+
+	SLJIT_ASSERT((memw >= 0 && memw <= I12_MAX - SSIZE_OF(sw)) || (memw > I12_MAX && memw <= 0xfff));
+
+	if (!(type & SLJIT_MEM_STORE) && mem == REG_PAIR_FIRST(reg)) {
+		FAIL_IF(push_mem_inst(compiler, WORD_DATA | LOAD_DATA, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), (memw + SSIZE_OF(sw)) & 0xfff));
+		return push_mem_inst(compiler, WORD_DATA | LOAD_DATA, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw);
+	}
+
+	flags = WORD_DATA | (!(type & SLJIT_MEM_STORE) ? LOAD_DATA : 0);
+
+	FAIL_IF(push_mem_inst(compiler, flags, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw));
+	return push_mem_inst(compiler, flags, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), (memw + SSIZE_OF(sw)) & 0xfff);
+}
+
+#undef TO_ARGW_HI
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler,
+	sljit_s32 op,
+	sljit_s32 dst_reg,
+	sljit_s32 mem_reg)
+{
+	sljit_ins ins;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+	if (!(LOONGARCH_FEATURE_LAMCAS & get_cpu_features()))
+		return SLJIT_ERR_UNSUPPORTED;
+
+	switch(GET_OPCODE(op)) {
+	case SLJIT_MOV_U8:
+		ins = LD_BU;
+		break;
+	case SLJIT_MOV_U16:
+		ins = LD_HU;
+		break;
+	case SLJIT_MOV32:
+		ins = LD_W;
+		break;
+	case SLJIT_MOV_U32:
+		ins = LD_WU;
+		break;
+	default:
+		ins = LD_D;
+		break;
+	}
+
+	return push_inst(compiler, ins | RD(dst_reg) | RJ(mem_reg) | IMM_I12(0));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler,
+	sljit_s32 op,
+	sljit_s32 src_reg,
+	sljit_s32 mem_reg,
+	sljit_s32 temp_reg)
+{
+	sljit_ins ins = 0;
+	sljit_ins unsign = 0;
+	sljit_s32 tmp = temp_reg;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+
+	if (!(LOONGARCH_FEATURE_LAMCAS & get_cpu_features()))
+		return SLJIT_ERR_UNSUPPORTED;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_U8:
+		ins = AMCAS_B;
+		unsign = BSTRPICK_D | (7 << 16);
+		break;
+	case SLJIT_MOV_U16:
+		ins = AMCAS_H;
+		unsign = BSTRPICK_D | (15 << 16);
+		break;
+	case SLJIT_MOV32:
+		ins = AMCAS_W;
+		break;
+	case SLJIT_MOV_U32:
+		ins = AMCAS_W;
+		unsign = BSTRPICK_D | (31 << 16);
+		break;
+	default:
+		ins = AMCAS_D;
+		break;
+	}
+
+	if (op & SLJIT_SET_ATOMIC_STORED) {
+		FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RJ(temp_reg) | RK(TMP_ZERO)));
+		tmp = TMP_REG1;
+	}
+	FAIL_IF(push_inst(compiler, ins | RD(tmp) | RJ(mem_reg) | RK(src_reg)));
+	if (!(op & SLJIT_SET_ATOMIC_STORED))
+		return SLJIT_SUCCESS;
+
+	if (unsign)
+		FAIL_IF(push_inst(compiler, unsign | RD(tmp) | RJ(tmp)));
+
+	FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(tmp) | RK(temp_reg)));
+	return push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(EQUAL_FLAG) | IMM_I12(1));
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
+{
+	SLJIT_UNUSED_ARG(last_ins);
+
+	FAIL_IF(push_inst(compiler, LU12I_W | RD(dst) | (sljit_ins)(((init_value & 0xffffffff) >> 12) << 5)));
+	FAIL_IF(push_inst(compiler, LU32I_D | RD(dst) | (sljit_ins)(((init_value >> 32) & 0xfffff) << 5)));
+	FAIL_IF(push_inst(compiler, LU52I_D | RD(dst) | RJ(dst) | (sljit_ins)(IMM_I12(init_value >> 52))));
+	return push_inst(compiler, ORI | RD(dst) | RJ(dst) | IMM_I12(init_value));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins *inst = (sljit_ins*)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0);
+
+	SLJIT_ASSERT((inst[0] & OPC_1RI20(0x7f)) == LU12I_W);
+	inst[0] = (inst[0] & (OPC_1RI20(0x7f) | 0x1f)) | (sljit_ins)(((new_target & 0xffffffff) >> 12) << 5);
+
+	SLJIT_ASSERT((inst[1] & OPC_1RI20(0x7f)) == LU32I_D);
+	inst[1] = (inst[1] & (OPC_1RI20(0x7f) | 0x1f)) | (sljit_ins)(sljit_ins)(((new_target >> 32) & 0xfffff) << 5);
+
+	SLJIT_ASSERT((inst[2] & OPC_2RI12(0x3ff)) == LU52I_D);
+	inst[2] = (inst[2] & (OPC_2RI12(0x3ff) | 0x3ff)) | IMM_I12(new_target >> 52);
+
+	SLJIT_ASSERT((inst[3] & OPC_2RI12(0x3ff)) == ORI || (inst[3] & OPC_2RI16(0x3f)) == JIRL);
+	if ((inst[3] & OPC_2RI12(0x3ff)) == ORI)
+		inst[3] = (inst[3] & (OPC_2RI12(0x3ff) | 0x3ff)) | IMM_I12(new_target);
+	else
+		inst[3] = (inst[3] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I12((new_target & 0xfff) >> 2);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1);
+
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 4);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+	PTR_FAIL_IF(emit_const(compiler, dst_r, init_value, 0));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+	PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
+
+	compiler->size += 3;
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+
+	return put_label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
+}

+ 165 - 7
thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c

@@ -26,6 +26,49 @@
 
 /* mips 32-bit arch dependent functions. */
 
+static sljit_s32 emit_copysign(struct sljit_compiler *compiler, sljit_s32 op,
+		sljit_sw src1, sljit_sw src2, sljit_sw dst)
+{
+	int is_32 = (op & SLJIT_32);
+	sljit_ins mfhc = MFC1, mthc = MTC1;
+	sljit_ins src1_r = FS(src1), src2_r = FS(src2), dst_r = FS(dst);
+
+	if (!is_32) {
+		switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+		case CPU_FEATURE_FR:
+			mfhc = MFHC1;
+			mthc = MTHC1;
+			break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+		default:
+			src1_r |= (1 << 11);
+			src2_r |= (1 << 11);
+			dst_r |= (1 << 11);
+			break;
+		}
+	}
+
+	FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG1) | src1_r, DR(TMP_REG1)));
+	FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG2) | src2_r, DR(TMP_REG2)));
+	if (!is_32 && src1 != dst)
+		FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(src1) | FD(dst), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	else
+		FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+	FAIL_IF(push_inst(compiler, XOR | T(TMP_REG1) | D(TMP_REG2) | S(TMP_REG2), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, SRL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, SLL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, XOR | T(TMP_REG2) | D(TMP_REG1) | S(TMP_REG1), DR(TMP_REG1)));
+	FAIL_IF(push_inst(compiler, mthc | T(TMP_REG1) | dst_r, MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	if (mthc == MTC1)
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+	return SLJIT_SUCCESS;
+}
+
 static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
 {
 	if (!(imm & ~0xffff))
@@ -44,6 +87,108 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
 	return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
 }
 
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		struct {
+#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
+			sljit_s32 lo;
+			sljit_s32 hi;
+#else /* !SLJIT_LITTLE_ENDIAN */
+			sljit_s32 hi;
+			sljit_s32 lo;
+#endif /* SLJIT_LITTLE_ENDIAN */
+		} bin;
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.bin.lo != 0)
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.bin.lo));
+	if (u.bin.hi != 0)
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG2), u.bin.hi));
+
+	FAIL_IF(push_inst(compiler, MTC1 | (u.bin.lo != 0 ? T(TMP_REG1) : TA(0)) | FS(freg), MOVABLE_INS));
+	switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+	case CPU_FEATURE_FR:
+		return push_inst(compiler, MTHC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg), MOVABLE_INS);
+#endif /* SLJIT_MIPS_REV >= 2 */
+	default:
+		FAIL_IF(push_inst(compiler, MTC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg) | (1 << 11), MOVABLE_INS));
+		break;
+	}
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_s32 reg2 = 0;
+	sljit_ins inst = FS(freg);
+	sljit_ins mthc = MTC1, mfhc = MFC1;
+	int is_32 = (op & SLJIT_32);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	op = GET_OPCODE(op);
+	if (reg & REG_PAIR_MASK) {
+		reg2 = REG_PAIR_SECOND(reg);
+		reg = REG_PAIR_FIRST(reg);
+
+		inst |= T(reg2);
+
+		if (op == SLJIT_COPY_TO_F64)
+			FAIL_IF(push_inst(compiler, MTC1 | inst, MOVABLE_INS));
+		else
+			FAIL_IF(push_inst(compiler, MFC1 | inst, DR(reg2)));
+
+		inst = FS(freg) | (1 << 11);
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+		if (cpu_feature_list & CPU_FEATURE_FR) {
+			mthc = MTHC1;
+			mfhc = MFHC1;
+			inst = FS(freg);
+		}
+#endif /* SLJIT_MIPS_REV >= 2 */
+	}
+
+	inst |= T(reg);
+	if (!is_32 && !reg2) {
+		switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+		case CPU_FEATURE_FR:
+			mthc = MTHC1;
+			mfhc = MFHC1;
+			break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+		default:
+			inst |= (1 << 11);
+			break;
+		}
+	}
+
+	if (op == SLJIT_COPY_TO_F64)
+		FAIL_IF(push_inst(compiler, mthc | inst, MOVABLE_INS));
+	else
+		FAIL_IF(push_inst(compiler, mfhc | inst, DR(reg)));
+
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	if (mthc == MTC1 || mfhc == MFC1)
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+	return SLJIT_SUCCESS;
+}
+
 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
 {
 	sljit_ins *inst = (sljit_ins *)addr;
@@ -74,6 +219,11 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
 	sljit_ins ins = NOP;
 	sljit_u8 offsets[4];
 	sljit_u8 *offsets_ptr = offsets;
+#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
+	sljit_ins f64_hi = TA(7), f64_lo = TA(6);
+#else
+	sljit_ins f64_hi = TA(6), f64_lo = TA(7);
+#endif /* SLJIT_LITTLE_ENDIAN */
 
 	SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
 
@@ -138,20 +288,28 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
 
 		switch (types & SLJIT_ARG_MASK) {
 		case SLJIT_ARG_TYPE_F64:
-			if (*offsets_ptr < 4 * sizeof (sljit_sw)) {
+			if (*offsets_ptr < 4 * sizeof(sljit_sw)) {
 				if (prev_ins != NOP)
 					FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
 
 				/* Must be preceded by at least one other argument,
 				 * and its starting offset must be 8 because of alignment. */
 				SLJIT_ASSERT((*offsets_ptr >> 2) == 2);
-
-				prev_ins = MFC1 | TA(6) | FS(float_arg_count) | (1 << 11);
-				ins = MFC1 | TA(7) | FS(float_arg_count);
+				switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+				case CPU_FEATURE_FR:
+					prev_ins = MFHC1 | f64_hi | FS(float_arg_count);
+					break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+				default:
+					prev_ins = MFC1 | f64_hi | FS(float_arg_count) | (1 << 11);
+					break;
+				}
+				ins = MFC1 | f64_lo | FS(float_arg_count);
 			} else if (*offsets_ptr < 254)
 				ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);
 			else if (*offsets_ptr == 254)
-				ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
+				ins = MOV_fmt(FMT_D) | FS(SLJIT_FR0) | FD(TMP_FREG1);
 
 			float_arg_count--;
 			break;
@@ -161,7 +319,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
 			else if (*offsets_ptr < 254)
 				ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);
 			else if (*offsets_ptr == 254)
-				ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
+				ins = MOV_fmt(FMT_S) | FS(SLJIT_FR0) | FD(TMP_FREG1);
 
 			float_arg_count--;
 			break;
@@ -285,7 +443,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
 
 	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
 
-	if (src & SLJIT_IMM)
+	if (src == SLJIT_IMM)
 		FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
 	else if (src != PIC_ADDR_REG)
 		FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));

+ 73 - 5
thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c

@@ -26,6 +26,23 @@
 
 /* mips 64-bit arch dependent functions. */
 
+static sljit_s32 emit_copysign(struct sljit_compiler *compiler, sljit_s32 op,
+		sljit_s32 src1, sljit_s32 src2, sljit_s32 dst)
+{
+	FAIL_IF(push_inst(compiler, SELECT_OP(DMFC1, MFC1) | T(TMP_REG1) | FS(src1), DR(TMP_REG1)));
+	FAIL_IF(push_inst(compiler, SELECT_OP(DMFC1, MFC1) | T(TMP_REG2) | FS(src2), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, XOR | S(TMP_REG2) | T(TMP_REG1) | D(TMP_REG2), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+	FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | T(TMP_REG2) | D(TMP_REG1), DR(TMP_REG1)));
+	FAIL_IF(push_inst(compiler, SELECT_OP(DMTC1, MTC1) | T(TMP_REG1) | FS(dst), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	if (!(op & SLJIT_32))
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+	return SLJIT_SUCCESS;
+}
+
 static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
 {
 	sljit_s32 shift = 32;
@@ -128,6 +145,57 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
 	return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
 }
 
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_sw imm;
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm == 0) {
+		FAIL_IF(push_inst(compiler, DMTC1 | TA(0) | FS(freg), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+		FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+		return SLJIT_SUCCESS;
+	}
+
+	FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.imm));
+	FAIL_IF(push_inst(compiler, DMTC1 | T(TMP_REG1) | FS(freg), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_ins inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	inst = T(reg) | FS(freg);
+
+	if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+		FAIL_IF(push_inst(compiler, SELECT_OP(DMTC1, MTC1) | inst, MOVABLE_INS));
+	else
+		FAIL_IF(push_inst(compiler, SELECT_OP(DMFC1, MFC1) | inst, DR(reg)));
+
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+	if (!(op & SLJIT_32))
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+	return SLJIT_SUCCESS;
+}
+
 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
 {
 	sljit_ins *inst = (sljit_ins *)addr;
@@ -183,17 +251,17 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
 		switch (types & SLJIT_ARG_MASK) {
 		case SLJIT_ARG_TYPE_F64:
 			if (arg_count != float_arg_count)
-				ins = MOV_S | FMT_D | FS(float_arg_count) | FD(arg_count);
+				ins = MOV_fmt(FMT_D) | FS(float_arg_count) | FD(arg_count);
 			else if (arg_count == 1)
-				ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
+				ins = MOV_fmt(FMT_D) | FS(SLJIT_FR0) | FD(TMP_FREG1);
 			arg_count--;
 			float_arg_count--;
 			break;
 		case SLJIT_ARG_TYPE_F32:
 			if (arg_count != float_arg_count)
-				ins = MOV_S | FMT_S | FS(float_arg_count) | FD(arg_count);
+				ins = MOV_fmt(FMT_S) | FS(float_arg_count) | FD(arg_count);
 			else if (arg_count == 1)
-				ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
+				ins = MOV_fmt(FMT_S) | FS(SLJIT_FR0) | FD(TMP_FREG1);
 			arg_count--;
 			float_arg_count--;
 			break;
@@ -300,7 +368,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
 
 	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
 
-	if (src & SLJIT_IMM)
+	if (src == SLJIT_IMM)
 		FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
 	else if (src != PIC_ADDR_REG)
 		FAIL_IF(push_inst(compiler, DADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 399 - 137
thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c


+ 149 - 4
thirdparty/pcre2/src/sljit/sljitNativePPC_32.c

@@ -85,10 +85,6 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 		}
 		return SLJIT_SUCCESS;
 
-	case SLJIT_NOT:
-		SLJIT_ASSERT(src1 == TMP_REG1);
-		return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
-
 	case SLJIT_CLZ:
 		SLJIT_ASSERT(src1 == TMP_REG1);
 		return push_inst(compiler, CNTLZW | S(src2) | A(dst));
@@ -246,6 +242,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 			FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm)));
 			return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16));
 		}
+		if (flags & ALT_FORM4) {
+			SLJIT_ASSERT(src1 == TMP_REG1);
+			return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
+		}
 		return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
 
 	case SLJIT_SHL:
@@ -325,6 +325,151 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
 	return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
 }
 
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+	sljit_s32 invert_sign = 1;
+
+	if (src == SLJIT_IMM) {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ (sljit_sw)0x80000000));
+		src = TMP_REG1;
+		invert_sign = 0;
+	} else if (!FAST_IS_REG(src)) {
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	/* First, a special double precision floating point value is constructed:
+	      (2^53 + (src xor (2^31)))
+	   The upper 32 bits of this number is a constant, and the lower 32 bits
+	   is simply the value of the source argument. The xor 2^31 operation adds
+	   0x80000000 to the source argument, which moves it into the 0 - 0xffffffff
+	   range. Finally we substract 2^53 + 2^31 to get the converted value. */
+	FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
+	if (invert_sign)
+		FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
+	FAIL_IF(push_inst(compiler, STW | S(TMP_REG2) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
+	FAIL_IF(push_inst(compiler, STW | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+	FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
+	FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+	FAIL_IF(push_inst(compiler, STW | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+	FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+	FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
+
+	if (op & SLJIT_32)
+		FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src == SLJIT_IMM) {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	} else if (!FAST_IS_REG(src)) {
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	/* First, a special double precision floating point value is constructed:
+	      (2^53 + src)
+	   The upper 32 bits of this number is a constant, and the lower 32 bits
+	   is simply the value of the source argument. Finally we substract 2^53
+	   to get the converted value. */
+	FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
+	FAIL_IF(push_inst(compiler, STW | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+	FAIL_IF(push_inst(compiler, STW | S(TMP_REG2) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
+
+	FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+	FAIL_IF(push_inst(compiler, STW | S(TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+	FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+	FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
+
+	if (op & SLJIT_32)
+		FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_s32 imm[2];
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm[0] != 0)
+		FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0]));
+	if (u.imm[1] != 0)
+		FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1]));
+
+	/* Saved in the same endianness. */
+	FAIL_IF(push_inst(compiler, STW | S(u.imm[0] != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+	FAIL_IF(push_inst(compiler, STW | S(u.imm[1] != 0 ? TMP_REG2 : TMP_ZERO) | A(SLJIT_SP) | (TMP_MEM_OFFSET + sizeof(sljit_s32))));
+	return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_s32 reg2 = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	if (op & SLJIT_32) {
+		if (op == SLJIT_COPY32_TO_F32) {
+			FAIL_IF(push_inst(compiler, STW | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+			return push_inst(compiler, LFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+		}
+
+		FAIL_IF(push_inst(compiler, STFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		return push_inst(compiler, LWZ | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+	}
+
+	if (reg & REG_PAIR_MASK) {
+		reg2 = REG_PAIR_SECOND(reg);
+		reg = REG_PAIR_FIRST(reg);
+	}
+
+	if (op == SLJIT_COPY_TO_F64) {
+		FAIL_IF(push_inst(compiler, STW | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
+
+		if (reg2 != 0)
+			FAIL_IF(push_inst(compiler, STW | S(reg2) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+		else
+			FAIL_IF(push_inst(compiler, STFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+
+		return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+	}
+
+	FAIL_IF(push_inst(compiler, STFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+	if (reg2 != 0)
+		FAIL_IF(push_inst(compiler, LWZ | S(reg2) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+
+	return push_inst(compiler, LWZ | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI);
+}
+
 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
 {
 	sljit_ins *inst = (sljit_ins *)addr;

+ 146 - 6
thirdparty/pcre2/src/sljit/sljitNativePPC_64.c

@@ -49,7 +49,7 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg,
 	if (imm <= SIMM_MAX && imm >= SIMM_MIN)
 		return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
 
-	if (!(imm & ~0xffff))
+	if (((sljit_uw)imm >> 16) == 0)
 		return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
 
 	if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
@@ -57,6 +57,11 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg,
 		return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
 	}
 
+	if (((sljit_uw)imm >> 32) == 0) {
+		FAIL_IF(push_inst(compiler, ORIS | S(TMP_ZERO) | A(reg) | IMM(imm >> 16)));
+		return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
+	}
+
 	/* Count leading zeroes. */
 	tmp = (sljit_uw)((imm >= 0) ? imm : ~imm);
 	ASM_SLJIT_CLZ(tmp, shift);
@@ -198,11 +203,6 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 		}
 		return SLJIT_SUCCESS;
 
-	case SLJIT_NOT:
-		SLJIT_ASSERT(src1 == TMP_REG1);
-		UN_EXTS();
-		return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
-
 	case SLJIT_CLZ:
 		SLJIT_ASSERT(src1 == TMP_REG1);
 		return push_inst(compiler, ((flags & ALT_FORM1) ? CNTLZW : CNTLZD) | S(src2) | A(dst));
@@ -399,6 +399,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 			FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm)));
 			return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16));
 		}
+		if (flags & ALT_FORM4) {
+			SLJIT_ASSERT(src1 == TMP_REG1);
+			UN_EXTS();
+			return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
+		}
 		return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
 
 	case SLJIT_SHL:
@@ -563,6 +568,141 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
 	return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
 }
 
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src == SLJIT_IMM) {
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	} else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
+		else
+			FAIL_IF(emit_op_mem(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	if (FAST_IS_REG(src)) {
+		FAIL_IF(push_inst(compiler, STD | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+	} else
+		FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
+
+	FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+
+	if (op & SLJIT_32)
+		FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32) {
+		if (src == SLJIT_IMM) {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_u32)srcw));
+			src = TMP_REG1;
+		} else {
+			if (FAST_IS_REG(src))
+				FAIL_IF(push_inst(compiler, CLRLDI(TMP_REG1, src, 32)));
+			else
+				FAIL_IF(emit_op_mem(compiler, INT_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+			src = TMP_REG1;
+		}
+
+		FAIL_IF(push_inst(compiler, STD | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+	} else {
+		if (src == SLJIT_IMM) {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+			src = TMP_REG1;
+		} else if (src & SLJIT_MEM) {
+			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+			src = TMP_REG1;
+		}
+
+		FAIL_IF(push_inst(compiler, CMPI | CRD(0 | 1) | A(src) | 0));
+		FAIL_IF(push_inst(compiler, BCx | (12 << 21) | (0 << 16) | 20));
+		FAIL_IF(push_inst(compiler, STD | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+		FAIL_IF(push_inst(compiler, Bx | ((op & SLJIT_32) ? 36 : 32)));
+
+		if (op & SLJIT_32)
+			FAIL_IF(push_inst(compiler, RLWINM | S(src) | A(TMP_REG2) | RLWI_SH(10) | RLWI_MBE(10, 21)));
+		else
+			FAIL_IF(push_inst(compiler, ANDI | S(src) | A(TMP_REG2) | 0x1));
+
+		/* Shift right. */
+		FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(63) | RLDI_MB(1)));
+
+		if (op & SLJIT_32)
+			FAIL_IF(push_inst(compiler, RLDICR | S(TMP_REG1) | A(TMP_REG1) | RLDI_SH(0) | RLDI_ME(53)));
+
+		FAIL_IF(push_inst(compiler, OR | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2)));
+
+		FAIL_IF(push_inst(compiler, STD | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+		FAIL_IF(push_inst(compiler, FADD | FD(dst_r) | FA(dst_r) | FB(dst_r)));
+	}
+
+	if (op & SLJIT_32)
+		FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_sw imm;
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm != 0)
+		FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+
+	FAIL_IF(push_inst(compiler, STD | S(u.imm != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+	return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	if (GET_OPCODE(op) == SLJIT_COPY_TO_F64) {
+		FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? STW : STD) | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+		return push_inst(compiler, ((op & SLJIT_32) ? LFS : LFD) | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+	}
+
+	FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? STFS : STFD) | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+	return push_inst(compiler, ((op & SLJIT_32) ? LWZ : LD) | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+}
+
 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
 {
 	sljit_ins *inst = (sljit_ins*)addr;

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 381 - 236
thirdparty/pcre2/src/sljit/sljitNativePPC_common.c


+ 70 - 1
thirdparty/pcre2/src/sljit/sljitNativeRISCV_32.c

@@ -27,7 +27,6 @@
 static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r)
 {
 	SLJIT_UNUSED_ARG(tmp_r);
-	SLJIT_ASSERT(dst_r != tmp_r);
 
 	if (imm <= SIMM_MAX && imm >= SIMM_MIN)
 		return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));
@@ -43,6 +42,76 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
 	return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
 }
 
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_s32 imm[2];
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm[0] != 0)
+		FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0], TMP_REG3));
+	if (u.imm[1] != 0)
+		FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1], TMP_REG3));
+
+	FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-16)));
+	FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(u.imm[0] != 0 ? TMP_REG1 : TMP_ZERO) | (8 << 7)));
+	FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(u.imm[1] != 0 ? TMP_REG2 : TMP_ZERO) | (12 << 7)));
+	FAIL_IF(push_inst(compiler, FLD | FRD(freg) | RS1(SLJIT_SP) | IMM_I(8)));
+	return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(16));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_ins inst;
+	sljit_s32 reg2 = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	if (op & SLJIT_32) {
+		if (op == SLJIT_COPY32_TO_F32)
+			inst = FMV_W_X | RS1(reg) | FRD(freg);
+		else
+			inst = FMV_X_W | FRS1(freg) | RD(reg);
+
+		return push_inst(compiler, inst);
+	}
+
+	FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-16)));
+
+	if (reg & REG_PAIR_MASK) {
+		reg2 = REG_PAIR_SECOND(reg);
+		reg = REG_PAIR_FIRST(reg);
+	}
+
+	if (op == SLJIT_COPY_TO_F64) {
+		if (reg2 != 0)
+			FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(reg2) | (8 << 7)));
+		else
+			FAIL_IF(push_inst(compiler, FSW | RS1(SLJIT_SP) | FRS2(freg) | (8 << 7)));
+
+		FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(reg) | (12 << 7)));
+		FAIL_IF(push_inst(compiler, FLD | FRD(freg) | RS1(SLJIT_SP) | IMM_I(8)));
+	} else {
+		FAIL_IF(push_inst(compiler, FSD | RS1(SLJIT_SP) | FRS2(freg) | (8 << 7)));
+
+		if (reg2 != 0)
+			FAIL_IF(push_inst(compiler, FMV_X_W | FRS1(freg) | RD(reg2)));
+
+		FAIL_IF(push_inst(compiler, LW | RD(reg) | RS1(SLJIT_SP) | IMM_I(12)));
+	}
+
+	return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(16));
+}
+
 static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
 {
 	if ((init_value & 0x800) != 0)

+ 41 - 2
thirdparty/pcre2/src/sljit/sljitNativeRISCV_64.c

@@ -28,8 +28,6 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
 {
 	sljit_sw high;
 
-	SLJIT_ASSERT(dst_r != tmp_r);
-
 	if (imm <= SIMM_MAX && imm >= SIMM_MIN)
 		return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));
 
@@ -81,6 +79,8 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
 		return SLJIT_SUCCESS;
 	}
 
+	SLJIT_ASSERT(dst_r != tmp_r);
+
 	high = imm >> 32;
 	imm = (sljit_s32)imm;
 
@@ -126,6 +126,45 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
 	return push_inst(compiler, XOR | RD(dst_r) | RS1(dst_r) | RS2(tmp_r));
 }
 
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_sw imm;
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm == 0)
+		return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_ZERO) | FRD(freg));
+
+	FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3));
+	return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_REG1) | FRD(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_ins inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+		inst = FMV_W_X | RS1(reg) | FRD(freg);
+	else
+		inst = FMV_X_W | FRS1(freg) | RD(reg);
+
+	if (!(op & SLJIT_32))
+		inst |= (sljit_ins)1 << 25;
+
+	return push_inst(compiler, inst);
+}
+
 static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
 {
 	sljit_sw high;

+ 427 - 176
thirdparty/pcre2/src/sljit/sljitNativeRISCV_common.c

@@ -97,16 +97,20 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
 #define FLD		(F3(0x3) | OPC(0x7))
 #define FLE_S		(F7(0x50) | F3(0x0) | OPC(0x53))
 #define FLT_S		(F7(0x50) | F3(0x1) | OPC(0x53))
-#define FSD		(F3(0x3) | OPC(0x27))
 /* These conversion opcodes are partly defined. */
 #define FCVT_S_D	(F7(0x20) | OPC(0x53))
 #define FCVT_S_W	(F7(0x68) | OPC(0x53))
+#define FCVT_S_WU	(F7(0x68) | F12(0x1) | OPC(0x53))
 #define FCVT_W_S	(F7(0x60) | F3(0x1) | OPC(0x53))
 #define FMUL_S		(F7(0x8) | F3(0x7) | OPC(0x53))
+#define FMV_X_W		(F7(0x70) | F3(0x0) | OPC(0x53))
+#define FMV_W_X		(F7(0x78) | F3(0x0) | OPC(0x53))
+#define FSD		(F3(0x3) | OPC(0x27))
 #define FSGNJ_S		(F7(0x10) | F3(0x0) | OPC(0x53))
 #define FSGNJN_S	(F7(0x10) | F3(0x1) | OPC(0x53))
 #define FSGNJX_S	(F7(0x10) | F3(0x2) | OPC(0x53))
 #define FSUB_S		(F7(0x4) | F3(0x7) | OPC(0x53))
+#define FSW		(F3(0x2) | OPC(0x27))
 #define JAL		(OPC(0x6f))
 #define JALR		(F3(0x0) | OPC(0x67))
 #define LD		(F3(0x3) | OPC(0x3))
@@ -344,13 +348,12 @@ static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
 		if ((addr & 0x80000000l) != 0)
 			high = ~high;
 
-		if ((high & 0x800) != 0)
-			high += 0x1000;
-
 		if (flags & PATCH_ABS52) {
 			SLJIT_ASSERT(addr <= S52_MAX);
 			inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high << 12);
 		} else {
+			if ((high & 0x800) != 0)
+				high += 0x1000;
 			inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff);
 			inst[1] = ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high);
 			inst++;
@@ -531,7 +534,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
 {
 	switch (feature_type) {
 	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return (SLJIT_IS_FPU_AVAILABLE) != 0;
+#elif defined(__riscv_float_abi_soft)
+		return 0;
+#else
+		return 1;
+#endif /* SLJIT_IS_FPU_AVAILABLE */
 	case SLJIT_HAS_ZERO_REGISTER:
+	case SLJIT_HAS_COPY_F32:
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+	case SLJIT_HAS_COPY_F64:
+#endif /* !SLJIT_CONFIG_RISCV_64 */
 		return 1;
 	default:
 		return 0;
@@ -540,7 +554,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
 {
-	return (type >= SLJIT_ORDERED_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL);
+	switch (type) {
+	case SLJIT_UNORDERED_OR_EQUAL:
+	case SLJIT_ORDERED_NOT_EQUAL:
+		return 2;
+
+	case SLJIT_UNORDERED:
+	case SLJIT_ORDERED:
+		return 1;
+	}
+
+	return 0;
 }
 
 /* --------------------------------------------------------------------- */
@@ -610,10 +634,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
 	if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
 		if ((local_size & SSIZE_OF(sw)) != 0)
 			local_size += SSIZE_OF(sw);
-		local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+		local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
 	}
 #else
-	local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+	local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
 #endif
 	local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
 	compiler->local_size = local_size;
@@ -704,10 +728,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
 	if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
 		if ((local_size & SSIZE_OF(sw)) != 0)
 			local_size += SSIZE_OF(sw);
-		local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+		local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
 	}
 #else
-	local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+	local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
 #endif
 	compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
 
@@ -915,7 +939,7 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
 
 	/* Since tmp can be the same as base or offset registers,
 	 * these might be unavailable after modifying tmp. */
-	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA))
+	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA) && reg == TMP_REG2)
 		tmp_r = reg;
 
 	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
@@ -1031,9 +1055,11 @@ static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, slji
 
 #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
 #define WORD 0
+#define WORD_32 0
 #define IMM_EXTEND(v) (IMM_I(v))
 #else /* !SLJIT_CONFIG_RISCV_32 */
 #define WORD word
+#define WORD_32 0x08
 #define IMM_EXTEND(v) (IMM_I((op & SLJIT_32) ? (v) : (32 + (v))))
 #endif /* SLJIT_CONFIG_RISCV_32 */
 
@@ -1041,16 +1067,16 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
 {
 	sljit_s32 is_clz = (GET_OPCODE(op) == SLJIT_CLZ);
 #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-	sljit_ins word = (op & SLJIT_32) >> 5;
-	sljit_ins max = (op & SLJIT_32) ? 32 : 64;
+	sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
+	sljit_ins word_size = (op & SLJIT_32) ? 32 : 64;
 #else /* !SLJIT_CONFIG_RISCV_64 */
-	sljit_ins max = 32;
+	sljit_ins word_size = 32;
 #endif /* SLJIT_CONFIG_RISCV_64 */
 
 	SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
 
 	/* The OTHER_FLAG is the counter. */
-	FAIL_IF(push_inst(compiler, ADDI | WORD | RD(OTHER_FLAG) | RS1(TMP_ZERO) | IMM_I(max)));
+	FAIL_IF(push_inst(compiler, ADDI | WORD | RD(OTHER_FLAG) | RS1(TMP_ZERO) | IMM_I(word_size)));
 
 	/* The TMP_REG2 is the next value. */
 	if (src != TMP_REG2)
@@ -1066,7 +1092,7 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
 		FAIL_IF(push_inst(compiler, BLT | RS1(TMP_REG2) | RS2(TMP_ZERO) | ((sljit_ins)(2 * SSIZE_OF(ins)) << 7) | ((sljit_ins)(8 * SSIZE_OF(ins)) << 20)));
 
 	/* The TMP_REG1 is the next shift. */
-	FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG1) | RS1(TMP_ZERO) | IMM_I(max)));
+	FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG1) | RS1(TMP_ZERO) | IMM_I(word_size)));
 
 	FAIL_IF(push_inst(compiler, ADDI | WORD | RD(EQUAL_FLAG) | RS1(TMP_REG2) | IMM_I(0)));
 	FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_I(1)));
@@ -1081,6 +1107,65 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
 	return push_inst(compiler, ADDI | WORD | RD(dst) | RS1(OTHER_FLAG) | IMM_I(0));
 }
 
+static sljit_s32 emit_rev(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src)
+{
+	SLJIT_UNUSED_ARG(op);
+
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+	if (!(op & SLJIT_32)) {
+		FAIL_IF(push_inst(compiler, LUI | RD(OTHER_FLAG) | 0x10000));
+		FAIL_IF(push_inst(compiler, SRLI | RD(TMP_REG1) | RS1(src) | IMM_I(32)));
+		FAIL_IF(push_inst(compiler, ADDI | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | IMM_I(0xfff)));
+		FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(src) | IMM_I(32)));
+		FAIL_IF(push_inst(compiler, SLLI | RD(EQUAL_FLAG) | RS1(OTHER_FLAG) | IMM_I(32)));
+		FAIL_IF(push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(EQUAL_FLAG)));
+
+		FAIL_IF(push_inst(compiler, SRLI | RD(TMP_REG1) | RS1(dst) | IMM_I(16)));
+		FAIL_IF(push_inst(compiler, AND | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)));
+		FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(OTHER_FLAG)));
+		FAIL_IF(push_inst(compiler, SLLI | RD(EQUAL_FLAG) | RS1(OTHER_FLAG) | IMM_I(8)));
+		FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(dst) | IMM_I(16)));
+		FAIL_IF(push_inst(compiler, XOR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(EQUAL_FLAG)));
+		FAIL_IF(push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1)));
+
+		FAIL_IF(push_inst(compiler, SRLI | RD(TMP_REG1) | RS1(dst) | IMM_I(8)));
+		FAIL_IF(push_inst(compiler, AND | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)));
+		FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(OTHER_FLAG)));
+		FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(dst) | IMM_I(8)));
+		return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1));
+	}
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+	FAIL_IF(push_inst(compiler, SRLI | WORD_32 | RD(TMP_REG1) | RS1(src) | IMM_I(16)));
+	FAIL_IF(push_inst(compiler, LUI | RD(OTHER_FLAG) | 0xff0000));
+	FAIL_IF(push_inst(compiler, SLLI | WORD_32 | RD(dst) | RS1(src) | IMM_I(16)));
+	FAIL_IF(push_inst(compiler, ORI | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | IMM_I(0xff)));
+	FAIL_IF(push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1)));
+
+	FAIL_IF(push_inst(compiler, SRLI | WORD_32 | RD(TMP_REG1) | RS1(dst) | IMM_I(8)));
+	FAIL_IF(push_inst(compiler, AND | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)));
+	FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(OTHER_FLAG)));
+	FAIL_IF(push_inst(compiler, SLLI | WORD_32 | RD(dst) | RS1(dst) | IMM_I(8)));
+	return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1));
+}
+
+static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src)
+{
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+	sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
+	sljit_ins word_size = (op & SLJIT_32) ? 32 : 64;
+#else /* !SLJIT_CONFIG_RISCV_64 */
+	sljit_ins word_size = 32;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+	FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(src) | IMM_I(8)));
+	FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src) | IMM_I(word_size - 8)));
+	FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_I(0xff)));
+	FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_REV_U16 ? SRLI : SRAI) | WORD | RD(dst) | RS1(dst) | IMM_I(word_size - 16)));
+	return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1));
+}
+
 #define EMIT_LOGICAL(op_imm, op_reg) \
 	if (flags & SRC2_IMM) { \
 		if (op & SLJIT_SET_Z) \
@@ -1105,7 +1190,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 	sljit_s32 is_overflow, is_carry, carry_src_r, is_handled;
 	sljit_ins op_imm, op_reg;
 #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-	sljit_ins word = (op & SLJIT_32) >> 5;
+	sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
 #endif /* SLJIT_CONFIG_RISCV_64 */
 
 	SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
@@ -1174,10 +1259,33 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
 		return emit_clz_ctz(compiler, op, dst, src2);
 
+	case SLJIT_REV:
+	case SLJIT_REV_S32:
+#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
+	case SLJIT_REV_U32:
+#endif /* SLJIT_CONFIG_RISCV_32 */
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return emit_rev(compiler, op, dst, src2);
+
+	case SLJIT_REV_U16:
+	case SLJIT_REV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return emit_rev16(compiler, op, dst, src2);
+
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+	case SLJIT_REV_U32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1);
+		FAIL_IF(emit_rev(compiler, op, dst, src2));
+		if (dst == TMP_REG2)
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(dst) | IMM_I(32)));
+		return push_inst(compiler, SRLI | RD(dst) | RS1(dst) | IMM_I(32));
+#endif /* SLJIT_CONFIG_RISCV_32 */
+
 	case SLJIT_ADD:
 		/* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */
 		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
-		carry_src_r = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+		carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
 
 		if (flags & SRC2_IMM) {
 			if (is_overflow) {
@@ -1233,7 +1341,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 		return push_inst(compiler, XOR | RD(OTHER_FLAG) | RS1(TMP_REG1) | RS2(OTHER_FLAG));
 
 	case SLJIT_ADDC:
-		carry_src_r = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+		carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
 
 		if (flags & SRC2_IMM) {
 			FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(src2)));
@@ -1280,11 +1388,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 		is_handled = 0;
 
 		if (flags & SRC2_IMM) {
-			if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+			if (GET_FLAG_TYPE(op) == SLJIT_LESS) {
 				FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2)));
 				is_handled = 1;
 			}
-			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) {
 				FAIL_IF(push_inst(compiler, SLTI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2)));
 				is_handled = 1;
 			}
@@ -1301,19 +1409,15 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 
 			switch (GET_FLAG_TYPE(op)) {
 			case SLJIT_LESS:
-			case SLJIT_GREATER_EQUAL:
 				FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src1) | RS2(src2)));
 				break;
 			case SLJIT_GREATER:
-			case SLJIT_LESS_EQUAL:
 				FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src2) | RS2(src1)));
 				break;
 			case SLJIT_SIG_LESS:
-			case SLJIT_SIG_GREATER_EQUAL:
 				FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RS1(src1) | RS2(src2)));
 				break;
 			case SLJIT_SIG_GREATER:
-			case SLJIT_SIG_LESS_EQUAL:
 				FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RS1(src2) | RS2(src1)));
 				break;
 			}
@@ -1336,7 +1440,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 		}
 
 		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
-		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+		is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
 
 		if (flags & SRC2_IMM) {
 			if (is_overflow) {
@@ -1385,7 +1489,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
 			flags &= ~SRC2_IMM;
 		}
 
-		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+		is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
 
 		if (flags & SRC2_IMM) {
 			if (is_carry)
@@ -1534,9 +1638,10 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
 		compiler->cache_argw = 0;
 	}
 
-	if (dst == TMP_REG2) {
+	if (dst == 0) {
 		SLJIT_ASSERT(HAS_FLAGS(op));
 		flags |= UNUSED_DEST;
+		dst = TMP_REG2;
 	}
 	else if (FAST_IS_REG(dst)) {
 		dst_r = dst;
@@ -1548,11 +1653,11 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
 		flags |= SLOW_DEST;
 
 	if (flags & IMM_OP) {
-		if ((src2 & SLJIT_IMM) && src2w != 0 && src2w <= SIMM_MAX && src2w >= SIMM_MIN) {
+		if (src2 == SLJIT_IMM && src2w != 0 && src2w <= SIMM_MAX && src2w >= SIMM_MIN) {
 			flags |= SRC2_IMM;
 			src2_r = src2w;
 		}
-		else if ((flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w != 0 && src1w <= SIMM_MAX && src1w >= SIMM_MIN) {
+		else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && src1w <= SIMM_MAX && src1w >= SIMM_MIN) {
 			flags |= SRC2_IMM;
 			src2_r = src1w;
 
@@ -1569,7 +1674,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
 		src1_r = src1;
 		flags |= REG1_SOURCE;
 	}
-	else if (src1 & SLJIT_IMM) {
+	else if (src1 == SLJIT_IMM) {
 		if (src1w) {
 			FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3));
 			src1_r = TMP_REG1;
@@ -1592,7 +1697,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
 		if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP)
 			dst_r = (sljit_s32)src2_r;
 	}
-	else if (src2 & SLJIT_IMM) {
+	else if (src2 == SLJIT_IMM) {
 		if (!(flags & SRC2_IMM)) {
 			if (src2w) {
 				FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w, TMP_REG3));
@@ -1649,7 +1754,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
 {
 #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-	sljit_ins word = (op & SLJIT_32) >> 5;
+	sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
 
 	SLJIT_ASSERT(word == 0 || word == 0x8);
 #endif /* SLJIT_CONFIG_RISCV_64 */
@@ -1718,32 +1823,38 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
 
 #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
 	case SLJIT_MOV_U32:
-		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u32)srcw : srcw);
+		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw);
 
 	case SLJIT_MOV_S32:
 	/* Logical operators have no W variant, so sign extended input is necessary for them. */
 	case SLJIT_MOV32:
-		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s32)srcw : srcw);
+		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw);
 #endif
 
 	case SLJIT_MOV_U8:
-		return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+		return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw);
 
 	case SLJIT_MOV_S8:
-		return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+		return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw);
 
 	case SLJIT_MOV_U16:
-		return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+		return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw);
 
 	case SLJIT_MOV_S16:
-		return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
-
-	case SLJIT_NOT:
-		return emit_op(compiler, SLJIT_XOR | (op & (SLJIT_32 | SLJIT_SET_Z)), flags, dst, dstw, src, srcw, SLJIT_IMM, -1);
+		return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw);
 
 	case SLJIT_CLZ:
 	case SLJIT_CTZ:
+	case SLJIT_REV:
 		return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_REV_U16:
+	case SLJIT_REV_S16:
+		return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_REV_U32:
+	case SLJIT_REV_S32:
+		return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
 	}
 
 	SLJIT_UNREACHABLE();
@@ -1766,9 +1877,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
 #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
 	if (op & SLJIT_32) {
 		flags |= INT_DATA | SIGNED_DATA;
-		if (src1 & SLJIT_IMM)
+		if (src1 == SLJIT_IMM)
 			src1w = (sljit_s32)src1w;
-		if (src2 & SLJIT_IMM)
+		if (src2 == SLJIT_IMM)
 			src2w = (sljit_s32)src2w;
 	}
 #endif
@@ -1801,7 +1912,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
 	case SLJIT_MASHR:
 	case SLJIT_ROTL:
 	case SLJIT_ROTR:
-		if (src2 & SLJIT_IMM) {
+		if (src2 == SLJIT_IMM) {
 #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
 			src2w &= 0x1f;
 #else /* !SLJIT_CONFIG_RISCV_32 */
@@ -1827,18 +1938,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
 	CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
 
 	SLJIT_SKIP_CHECKS(compiler);
-	return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
+	return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
 }
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
-	sljit_s32 src_dst,
-	sljit_s32 src1, sljit_sw src1w,
-	sljit_s32 src2, sljit_sw src2w)
+	sljit_s32 dst_reg,
+	sljit_s32 src1_reg,
+	sljit_s32 src2_reg,
+	sljit_s32 src3, sljit_sw src3w)
 {
 	sljit_s32 is_left;
 	sljit_ins ins1, ins2, ins3;
 #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-	sljit_ins word = (op & SLJIT_32) >> 5;
+	sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
 	sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
 	sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64;
 #else /* !SLJIT_CONFIG_RISCV_64 */
@@ -1849,50 +1961,44 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
 	SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
 
 	CHECK_ERROR();
-	CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+	CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
 
 	is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
 
-	if (src_dst == src1) {
+	if (src1_reg == src2_reg) {
 		SLJIT_SKIP_CHECKS(compiler);
-		return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w);
+		return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
 	}
 
-	ADJUST_LOCAL_OFFSET(src1, src1w);
-	ADJUST_LOCAL_OFFSET(src2, src2w);
+	ADJUST_LOCAL_OFFSET(src3, src3w);
 
-	if (src2 & SLJIT_IMM) {
-		src2w &= bit_length - 1;
+	if (src3 == SLJIT_IMM) {
+		src3w &= bit_length - 1;
 
-		if (src2w == 0)
+		if (src3w == 0)
 			return SLJIT_SUCCESS;
-	} else if (src2 & SLJIT_MEM) {
-		FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src2, src2w));
-		src2 = TMP_REG2;
-	}
 
-	if (src1 & SLJIT_MEM) {
-		FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w));
-		src1 = TMP_REG1;
-	} else if (src1 & SLJIT_IMM) {
-		FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3));
-		src1 = TMP_REG1;
-	}
-
-	if (src2 & SLJIT_IMM) {
 		if (is_left) {
-			ins1 = SLLI | WORD | IMM_I(src2w);
-			src2w = bit_length - src2w;
-			ins2 = SRLI | WORD | IMM_I(src2w);
+			ins1 = SLLI | WORD | IMM_I(src3w);
+			src3w = bit_length - src3w;
+			ins2 = SRLI | WORD | IMM_I(src3w);
 		} else {
-			ins1 = SRLI | WORD | IMM_I(src2w);
-			src2w = bit_length - src2w;
-			ins2 = SLLI | WORD | IMM_I(src2w);
+			ins1 = SRLI | WORD | IMM_I(src3w);
+			src3w = bit_length - src3w;
+			ins2 = SLLI | WORD | IMM_I(src3w);
 		}
 
-		FAIL_IF(push_inst(compiler, ins1 | RD(src_dst) | RS1(src_dst)));
-		FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RS1(src1)));
-		return push_inst(compiler, OR | RD(src_dst) | RS1(src_dst) | RS2(TMP_REG1));
+		FAIL_IF(push_inst(compiler, ins1 | RD(dst_reg) | RS1(src1_reg)));
+		FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RS1(src2_reg)));
+		return push_inst(compiler, OR | RD(dst_reg) | RS1(dst_reg) | RS2(TMP_REG1));
+	}
+
+	if (src3 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src3, src3w));
+		src3 = TMP_REG2;
+	} else if (dst_reg == src3) {
+		push_inst(compiler, ADDI | WORD | RD(TMP_REG2) | RS1(src3) | IMM_I(0));
+		src3 = TMP_REG2;
 	}
 
 	if (is_left) {
@@ -1905,21 +2011,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
 		ins3 = SLL;
 	}
 
-	FAIL_IF(push_inst(compiler, ins1 | WORD | RD(src_dst) | RS1(src_dst) | RS2(src2)));
+	FAIL_IF(push_inst(compiler, ins1 | WORD | RD(dst_reg) | RS1(src1_reg) | RS2(src3)));
 
 	if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
-		FAIL_IF(push_inst(compiler, ins2 | WORD | RD(TMP_REG1) | RS1(src1) | IMM_I(1)));
-		FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RS1(src2) | IMM_I((sljit_ins)bit_length - 1)));
-		src1 = TMP_REG1;
+		FAIL_IF(push_inst(compiler, ins2 | WORD | RD(TMP_REG1) | RS1(src2_reg) | IMM_I(1)));
+		FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RS1(src3) | IMM_I((sljit_ins)bit_length - 1)));
+		src2_reg = TMP_REG1;
 	} else
-		FAIL_IF(push_inst(compiler, SUB | WORD | RD(TMP_REG2) | RS1(TMP_ZERO) | RS2(src2)));
+		FAIL_IF(push_inst(compiler, SUB | WORD | RD(TMP_REG2) | RS1(TMP_ZERO) | RS2(src3)));
 
-	FAIL_IF(push_inst(compiler, ins3 | WORD | RD(TMP_REG1) | RS1(src1) | RS2(TMP_REG2)));
-	return push_inst(compiler, OR | RD(src_dst) | RS1(src_dst) | RS2(TMP_REG1));
+	FAIL_IF(push_inst(compiler, ins3 | WORD | RD(TMP_REG1) | RS1(src2_reg) | RS2(TMP_REG2)));
+	return push_inst(compiler, OR | RD(dst_reg) | RS1(dst_reg) | RS2(TMP_REG1));
 }
 
-#undef WORD
-
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
 	sljit_s32 src, sljit_sw srcw)
 {
@@ -1947,21 +2051,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
 	return SLJIT_SUCCESS;
 }
 
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw)
 {
-	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
-	return reg_map[reg];
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	switch (op) {
+	case SLJIT_FAST_ENTER:
+		if (FAST_IS_REG(dst))
+			return push_inst(compiler, ADDI | RD(dst) | RS1(RETURN_ADDR_REG) | IMM_I(0));
+
+		SLJIT_ASSERT(RETURN_ADDR_REG == TMP_REG2);
+		break;
+	case SLJIT_GET_RETURN_ADDRESS:
+		dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size - SSIZE_OF(sw)));
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
+
+	return SLJIT_SUCCESS;
 }
 
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
 {
-	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+	if (type == SLJIT_GP_REGISTER)
+		return reg_map[reg];
+
+	if (type != SLJIT_FLOAT_REGISTER)
+		return -1;
+
 	return freg_map[reg];
 }
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
 	void *instruction, sljit_u32 size)
 {
+	SLJIT_UNUSED_ARG(size);
+
 	CHECK_ERROR();
 	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
 
@@ -2008,51 +2143,73 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
 #endif
 }
 
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,
 	sljit_s32 dst, sljit_sw dstw,
 	sljit_s32 src, sljit_sw srcw)
 {
-	sljit_ins inst;
-#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-	sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)) << 21;
-#endif
-
 	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
 
 	if (src & SLJIT_MEM) {
 #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
 		FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
-#else
-		FAIL_IF(emit_op_mem2(compiler, (flags ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
-#endif
+#else /* SLJIT_CONFIG_RISCV_32 */
+		FAIL_IF(emit_op_mem2(compiler, ((ins & (1 << 21)) ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
+#endif /* !SLJIT_CONFIG_RISCV_32 */
 		src = TMP_REG1;
-	} else if (src & SLJIT_IMM) {
-#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
-			srcw = (sljit_s32)srcw;
-#endif
-
+	} else if (src == SLJIT_IMM) {
 		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw, TMP_REG3));
 		src = TMP_REG1;
 	}
 
-	inst = FCVT_S_W | FMT(op) | FRD(dst_r) | RS1(src);
+	FAIL_IF(push_inst(compiler, ins | FRD(dst_r) | RS1(src)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, DOUBLE_DATA | ((sljit_s32)(~ins >> 24) & 0x2), TMP_FREG1, dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins ins = FCVT_S_W | FMT(op);
 
 #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
 	if (op & SLJIT_32)
-		inst |= F3(0x7);
-#else
-	inst |= flags;
+		ins |= F3(0x7);
+#else /* !SLJIT_CONFIG_RISCV_32 */
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)
+		ins |= (1 << 21);
+	else if (src == SLJIT_IMM)
+		srcw = (sljit_s32)srcw;
 
 	if (op != SLJIT_CONV_F64_FROM_S32)
-		inst |= F3(0x7);
-#endif
+		ins |= F3(0x7);
+#endif /* SLJIT_CONFIG_RISCV_32 */
 
-	FAIL_IF(push_inst(compiler, inst));
+	return sljit_emit_fop1_conv_f64_from_w(compiler, ins, dst, dstw, src, srcw);
+}
 
-	if (dst & SLJIT_MEM)
-		return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
-	return SLJIT_SUCCESS;
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins ins = FCVT_S_WU | FMT(op);
+
+#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
+	if (op & SLJIT_32)
+		ins |= F3(0x7);
+#else /* !SLJIT_CONFIG_RISCV_32 */
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_UW)
+		ins |= (1 << 21);
+	else if (src == SLJIT_IMM)
+		srcw = (sljit_u32)srcw;
+
+	if (op != SLJIT_CONV_F64_FROM_S32)
+		ins |= F3(0x7);
+#endif /* SLJIT_CONFIG_RISCV_32 */
+
+	return sljit_emit_fop1_conv_f64_from_w(compiler, ins, dst, dstw, src, srcw);
 }
 
 static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2073,40 +2230,36 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
 
 	switch (GET_FLAG_TYPE(op)) {
 	case SLJIT_F_EQUAL:
-	case SLJIT_F_NOT_EQUAL:
 	case SLJIT_ORDERED_EQUAL:
-	case SLJIT_UNORDERED_OR_NOT_EQUAL:
 		inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2);
 		break;
 	case SLJIT_F_LESS:
-	case SLJIT_F_GREATER_EQUAL:
 	case SLJIT_ORDERED_LESS:
-	case SLJIT_UNORDERED_OR_GREATER_EQUAL:
 		inst = FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2);
 		break;
 	case SLJIT_ORDERED_GREATER:
-	case SLJIT_UNORDERED_OR_LESS_EQUAL:
 		inst = FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src2) | FRS2(src1);
 		break;
 	case SLJIT_F_GREATER:
-	case SLJIT_F_LESS_EQUAL:
 	case SLJIT_UNORDERED_OR_GREATER:
-	case SLJIT_ORDERED_LESS_EQUAL:
 		inst = FLE_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2);
 		break;
 	case SLJIT_UNORDERED_OR_LESS:
-	case SLJIT_ORDERED_GREATER_EQUAL:
 		inst = FLE_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src2) | FRS2(src1);
 		break;
-	case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
-	case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+	case SLJIT_UNORDERED_OR_EQUAL:
 		FAIL_IF(push_inst(compiler, FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2)));
 		FAIL_IF(push_inst(compiler, FLT_S | FMT(op) | RD(TMP_REG1) | FRS1(src2) | FRS2(src1)));
 		inst = OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(TMP_REG1);
 		break;
-	default: /* SLJIT_UNORDERED, SLJIT_ORDERED */
-		FAIL_IF(push_inst(compiler, FADD_S | FMT(op) | FRD(TMP_FREG1) | FRS1(src1) | FRS2(src2)));
-		inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(TMP_FREG1) | FRS2(TMP_FREG1);
+	default: /* SLJIT_UNORDERED */
+		if (src1 == src2) {
+			inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src1);
+			break;
+		}
+		FAIL_IF(push_inst(compiler, FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src1)));
+		FAIL_IF(push_inst(compiler, FEQ_S | FMT(op) | RD(TMP_REG1) | FRS1(src2) | FRS2(src2)));
+		inst = AND | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(TMP_REG1);
 		break;
 	}
 
@@ -2233,6 +2386,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
 	case SLJIT_DIV_F64:
 		FAIL_IF(push_inst(compiler, FDIV_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2)));
 		break;
+
+	case SLJIT_COPYSIGN_F64:
+		return push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2));
 	}
 
 	if (dst_r == TMP_FREG2)
@@ -2241,24 +2397,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
 	return SLJIT_SUCCESS;
 }
 
-#undef FLOAT_DATA
-#undef FMT
-
-/* --------------------------------------------------------------------- */
-/*  Other instructions                                                   */
-/* --------------------------------------------------------------------- */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f32 value)
 {
+	union {
+		sljit_s32 imm;
+		sljit_f32 value;
+	} u;
+
 	CHECK_ERROR();
-	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
-	ADJUST_LOCAL_OFFSET(dst, dstw);
+	CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+	u.value = value;
 
-	if (FAST_IS_REG(dst))
-		return push_inst(compiler, ADDI | RD(dst) | RS1(RETURN_ADDR_REG) | IMM_I(0));
+	if (u.imm == 0)
+		return push_inst(compiler, FMV_W_X | RS1(TMP_ZERO) | FRD(freg));
 
-	/* Memory. */
-	return emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw);
+	FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3));
+	return push_inst(compiler, FMV_W_X | RS1(TMP_REG1) | FRD(freg));
 }
 
 /* --------------------------------------------------------------------- */
@@ -2287,26 +2443,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
 #define BRANCH_LENGTH	((sljit_ins)(7 * sizeof(sljit_ins)) << 7)
 #endif
 
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+static sljit_ins get_jump_instruction(sljit_s32 type)
 {
-	struct sljit_jump *jump;
-	sljit_ins inst;
-
-	CHECK_ERROR_PTR();
-	CHECK_PTR(check_sljit_emit_jump(compiler, type));
-
-	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
-	PTR_FAIL_IF(!jump);
-	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
-	type &= 0xff;
-
 	switch (type) {
 	case SLJIT_EQUAL:
-		inst = BNE | RS1(EQUAL_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
-		break;
+		return BNE | RS1(EQUAL_FLAG) | RS2(TMP_ZERO);
 	case SLJIT_NOT_EQUAL:
-		inst = BEQ | RS1(EQUAL_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
-		break;
+		return BEQ | RS1(EQUAL_FLAG) | RS2(TMP_ZERO);
 	case SLJIT_LESS:
 	case SLJIT_GREATER:
 	case SLJIT_SIG_LESS:
@@ -2315,7 +2458,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
 	case SLJIT_CARRY:
 	case SLJIT_F_EQUAL:
 	case SLJIT_ORDERED_EQUAL:
-	case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+	case SLJIT_ORDERED_NOT_EQUAL:
 	case SLJIT_F_LESS:
 	case SLJIT_ORDERED_LESS:
 	case SLJIT_ORDERED_GREATER:
@@ -2323,7 +2466,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
 	case SLJIT_ORDERED_LESS_EQUAL:
 	case SLJIT_ORDERED_GREATER_EQUAL:
 	case SLJIT_ORDERED:
-		inst = BEQ | RS1(OTHER_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
+		return BEQ | RS1(OTHER_FLAG) | RS2(TMP_ZERO);
 		break;
 	case SLJIT_GREATER_EQUAL:
 	case SLJIT_LESS_EQUAL:
@@ -2333,7 +2476,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
 	case SLJIT_NOT_CARRY:
 	case SLJIT_F_NOT_EQUAL:
 	case SLJIT_UNORDERED_OR_NOT_EQUAL:
-	case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
+	case SLJIT_UNORDERED_OR_EQUAL:
 	case SLJIT_F_GREATER_EQUAL:
 	case SLJIT_UNORDERED_OR_GREATER_EQUAL:
 	case SLJIT_UNORDERED_OR_LESS_EQUAL:
@@ -2341,16 +2484,30 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
 	case SLJIT_UNORDERED_OR_GREATER:
 	case SLJIT_UNORDERED_OR_LESS:
 	case SLJIT_UNORDERED:
-		inst = BNE | RS1(OTHER_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
-		break;
+		return BNE | RS1(OTHER_FLAG) | RS2(TMP_ZERO);
 	default:
 		/* Not conditional branch. */
-		inst = 0;
-		break;
+		return 0;
 	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+	sljit_ins inst;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	inst = get_jump_instruction(type);
 
 	if (inst != 0) {
-		PTR_FAIL_IF(push_inst(compiler, inst));
+		PTR_FAIL_IF(push_inst(compiler, inst | BRANCH_LENGTH));
 		jump->flags |= IS_COND;
 	}
 
@@ -2420,7 +2577,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
 		src2 = TMP_REG2;
 	}
 
-	if (src1 & SLJIT_IMM) {
+	if (src1 == SLJIT_IMM) {
 		if (src1w != 0) {
 			PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3));
 			src1 = TMP_REG1;
@@ -2429,7 +2586,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
 			src1 = TMP_ZERO;
 	}
 
-	if (src2 & SLJIT_IMM) {
+	if (src2 == SLJIT_IMM) {
 		if (src2w != 0) {
 			PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w, TMP_REG3));
 			src2 = TMP_REG2;
@@ -2499,7 +2656,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
 	CHECK_ERROR();
 	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
 
-	if (!(src & SLJIT_IMM)) {
+	if (src != SLJIT_IMM) {
 		if (src & SLJIT_MEM) {
 			ADJUST_LOCAL_OFFSET(src, srcw);
 			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
@@ -2641,16 +2798,110 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
 	return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, src_r, 0);
 }
 
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
 	sljit_s32 dst_reg,
-	sljit_s32 src, sljit_sw srcw)
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2_reg)
+{
+	sljit_ins *ptr;
+	sljit_uw size;
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+	sljit_ins word = (sljit_ins)(type & SLJIT_32) >> 5;
+	sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+#else /* !SLJIT_CONFIG_RISCV_64 */
+        sljit_s32 inp_flags = WORD_DATA | LOAD_DATA;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+	SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+
+	if (dst_reg != src2_reg) {
+		if (dst_reg == src1) {
+			src1 = src2_reg;
+			src1w = 0;
+			type ^= 0x1;
+		} else {
+			if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+				FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(dst_reg) | IMM_I(0)));
+
+				if ((src1 & REG_MASK) == dst_reg)
+					src1 = (src1 & ~REG_MASK) | TMP_REG2;
+
+				if (OFFS_REG(src1) == dst_reg)
+					src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+			}
+
+			FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src2_reg) | IMM_I(0)));
+		}
+	}
+
+	size = compiler->size;
+
+	ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	compiler->size++;
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w));
+	} else if (src1 == SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+		if (word)
+			src1w = (sljit_s32)src1w;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+		FAIL_IF(load_immediate(compiler, dst_reg, src1w, TMP_REG1));
+	} else
+		FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src1) | IMM_I(0)));
+
+	*ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9);
+	return SLJIT_SUCCESS;
+}
+
+#undef WORD
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_freg,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2_freg)
 {
+	sljit_ins *ptr;
+	sljit_uw size;
+
 	CHECK_ERROR();
-	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+	CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+
+	if (dst_freg != src2_freg) {
+		if (dst_freg == src1) {
+			src1 = src2_freg;
+			src1w = 0;
+			type ^= 0x1;
+		} else
+			FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(type) | FRD(dst_freg) | FRS1(src2_freg) | FRS2(src2_freg)));
+	}
+
+	size = compiler->size;
+
+	ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	compiler->size++;
+
+	if (src1 & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, dst_freg, src1, src1w));
+	else
+		FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(type) | FRD(dst_freg) | FRS1(src1) | FRS2(src1)));
 
-	return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
+	*ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9);
+	return SLJIT_SUCCESS;
 }
 
+#undef FLOAT_DATA
+#undef FMT
+
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
 	sljit_s32 reg,
 	sljit_s32 mem, sljit_sw memw)

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 414 - 204
thirdparty/pcre2/src/sljit/sljitNativeS390X.c


+ 395 - 70
thirdparty/pcre2/src/sljit/sljitNativeX86_32.c

@@ -62,21 +62,19 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	/* Both size flags cannot be switched on. */
 	SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
 	/* SSE2 and immediate is not possible. */
-	SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
-	SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
-		&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
-		&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
+	SLJIT_ASSERT(a != SLJIT_IMM || !(flags & EX86_SSE2));
+	SLJIT_ASSERT(((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+			& ((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+	SLJIT_ASSERT((flags & (EX86_VEX_EXT | EX86_REX)) != EX86_VEX_EXT);
 
 	size &= 0xf;
-	inst_size = size;
+	/* The mod r/m byte is always present. */
+	inst_size = size + 1;
 
-	if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
-		inst_size++;
-	if (flags & EX86_PREF_66)
+	if (flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
 		inst_size++;
 
 	/* Calculate size of b. */
-	inst_size += 1; /* mod r/m byte. */
 	if (b & SLJIT_MEM) {
 		if (!(b & REG_MASK))
 			inst_size += sizeof(sljit_sw);
@@ -87,8 +85,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 					inst_size += sizeof(sljit_s8);
 				else
 					inst_size += sizeof(sljit_sw);
-			}
-			else if (reg_map[b & REG_MASK] == 5) {
+			} else if (reg_map[b & REG_MASK] == 5) {
 				/* Swap registers if possible. */
 				if ((b & OFFS_REG_MASK) && (immb & 0x3) == 0 && reg_map[OFFS_REG(b)] != 5)
 					b = SLJIT_MEM | OFFS_REG(b) | TO_OFFS_REG(b & REG_MASK);
@@ -105,15 +102,14 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	}
 
 	/* Calculate size of a. */
-	if (a & SLJIT_IMM) {
+	if (a == SLJIT_IMM) {
 		if (flags & EX86_BIN_INS) {
 			if (imma <= 127 && imma >= -128) {
 				inst_size += 1;
 				flags |= EX86_BYTE_ARG;
 			} else
 				inst_size += 4;
-		}
-		else if (flags & EX86_SHIFT_INS) {
+		} else if (flags & EX86_SHIFT_INS) {
 			SLJIT_ASSERT(imma <= 0x1f);
 			if (imma != 1) {
 				inst_size++;
@@ -125,8 +121,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 			inst_size += sizeof(short);
 		else
 			inst_size += sizeof(sljit_sw);
-	}
-	else
+	} else
 		SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
 
 	inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
@@ -136,27 +131,26 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	INC_SIZE(inst_size);
 	if (flags & EX86_PREF_F2)
 		*inst++ = 0xf2;
-	if (flags & EX86_PREF_F3)
+	else if (flags & EX86_PREF_F3)
 		*inst++ = 0xf3;
-	if (flags & EX86_PREF_66)
+	else if (flags & EX86_PREF_66)
 		*inst++ = 0x66;
 
 	buf_ptr = inst + size;
 
 	/* Encode mod/rm byte. */
 	if (!(flags & EX86_SHIFT_INS)) {
-		if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
+		if ((flags & EX86_BIN_INS) && a == SLJIT_IMM)
 			*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
 
-		if (a & SLJIT_IMM)
+		if (a == SLJIT_IMM)
 			*buf_ptr = 0;
 		else if (!(flags & EX86_SSE2_OP1))
 			*buf_ptr = U8(reg_map[a] << 3);
 		else
-			*buf_ptr = U8(a << 3);
-	}
-	else {
-		if (a & SLJIT_IMM) {
+			*buf_ptr = U8(freg_map[a] << 3);
+	} else {
+		if (a == SLJIT_IMM) {
 			if (imma == 1)
 				*inst = GROUP_SHIFT_1;
 			else
@@ -167,7 +161,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	}
 
 	if (!(b & SLJIT_MEM)) {
-		*buf_ptr = U8(*buf_ptr | MOD_REG | (!(flags & EX86_SSE2_OP2) ? reg_map[b] : b));
+		*buf_ptr = U8(*buf_ptr | MOD_REG | (!(flags & EX86_SSE2_OP2) ? reg_map[b] : freg_map[b]));
 		buf_ptr++;
 	} else if (b & REG_MASK) {
 		reg_map_b = reg_map[b & REG_MASK];
@@ -183,8 +177,9 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 			if (!(b & OFFS_REG_MASK))
 				*buf_ptr++ |= reg_map_b;
 			else {
-				*buf_ptr++ |= 0x04;
-				*buf_ptr++ = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3));
+				buf_ptr[0] |= 0x04;
+				buf_ptr[1] = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3));
+				buf_ptr += 2;
 			}
 
 			if (immb != 0 || reg_map_b == 5) {
@@ -195,25 +190,24 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 					buf_ptr += sizeof(sljit_sw);
 				}
 			}
-		}
-		else {
+		} else {
 			if (reg_map_b == 5)
 				*buf_ptr |= 0x40;
 
-			*buf_ptr++ |= 0x04;
-			*buf_ptr++ = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3) | (immb << 6));
+			buf_ptr[0] |= 0x04;
+			buf_ptr[1] = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3) | (immb << 6));
+			buf_ptr += 2;
 
 			if (reg_map_b == 5)
 				*buf_ptr++ = 0;
 		}
-	}
-	else {
+	} else {
 		*buf_ptr++ |= 0x05;
 		sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
 		buf_ptr += sizeof(sljit_sw);
 	}
 
-	if (a & SLJIT_IMM) {
+	if (a == SLJIT_IMM) {
 		if (flags & EX86_BYTE_ARG)
 			*buf_ptr = U8(imma);
 		else if (flags & EX86_HALF_ARG)
@@ -222,7 +216,67 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 			sljit_unaligned_store_sw(buf_ptr, imma);
 	}
 
-	return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
+	return inst;
+}
+
+static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw op,
+	/* The first and second register operand. */
+	sljit_s32 a, sljit_s32 v,
+	/* The general operand (not immediate). */
+	sljit_s32 b, sljit_sw immb)
+{
+	sljit_u8 *inst;
+	sljit_u8 vex = 0;
+	sljit_u8 vex_m = 0;
+	sljit_uw size;
+
+	SLJIT_ASSERT(((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+			& ((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+
+	if (op & VEX_OP_0F38)
+		vex_m = 0x2;
+	else if (op & VEX_OP_0F3A)
+		vex_m = 0x3;
+
+	if (op & VEX_W) {
+		if (vex_m == 0)
+			vex_m = 0x1;
+
+		vex |= 0x80;
+	}
+
+	if (op & EX86_PREF_66)
+		vex |= 0x1;
+	else if (op & EX86_PREF_F2)
+		vex |= 0x3;
+	else if (op & EX86_PREF_F3)
+		vex |= 0x2;
+
+	op &= ~(EX86_PREF_66 | EX86_PREF_F2 | EX86_PREF_F3);
+
+	if (op & VEX_256)
+		vex |= 0x4;
+
+	vex = U8(vex | ((((op & VEX_SSE2_OPV) ? freg_map[v] : reg_map[v]) ^ 0xf) << 3));
+
+	size = op & ~(sljit_uw)0xff;
+	size |= (vex_m == 0) ? 3 : 4;
+
+	inst = emit_x86_instruction(compiler, size, a, 0, b, immb);
+	FAIL_IF(!inst);
+
+	if (vex_m == 0) {
+		inst[0] = 0xc5;
+		inst[1] = U8(vex | 0x80);
+		inst[2] = U8(op);
+		return SLJIT_SUCCESS;
+	}
+
+	inst[0] = 0xc4;
+	inst[1] = U8(vex_m | 0xe0);
+	inst[2] = vex;
+	inst[3] = U8(op);
+	return SLJIT_SUCCESS;
 }
 
 /* --------------------------------------------------------------------- */
@@ -578,8 +632,6 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
 {
-	sljit_u8 *inst;
-
 	CHECK_ERROR();
 	CHECK(check_sljit_emit_return_void(compiler));
 
@@ -588,11 +640,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler
 
 	FAIL_IF(emit_stack_frame_release(compiler, 0));
 
-	inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
-	FAIL_IF(!inst);
-	INC_SIZE(1);
-	RET();
-	return SLJIT_SUCCESS;
+	return emit_byte(compiler, RET_near);
 }
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
@@ -782,7 +830,7 @@ static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler,
 
 		offset = stack_size + compiler->local_size;
 
-		if (!(src & SLJIT_IMM) && src != SLJIT_R0) {
+		if (src != SLJIT_IMM && src != SLJIT_R0) {
 			if (word_arg_count >= 1) {
 				EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R0, 0);
 				r2_offset = sizeof(sljit_sw);
@@ -836,7 +884,7 @@ static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler,
 
 	stack_size = args_size + SSIZE_OF(sw);
 
-	if (word_arg_count >= 1 && !(src & SLJIT_IMM) && src != SLJIT_R0) {
+	if (word_arg_count >= 1 && src != SLJIT_IMM && src != SLJIT_R0) {
 		r2_offset = SSIZE_OF(sw);
 		stack_size += SSIZE_OF(sw);
 	}
@@ -865,7 +913,7 @@ static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler,
 			EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), word_arg4_offset);
 	}
 
-	if (!(src & SLJIT_IMM) && src != SLJIT_R0) {
+	if (src != SLJIT_IMM && src != SLJIT_R0) {
 		if (word_arg_count >= 1) {
 			SLJIT_ASSERT(r2_offset == sizeof(sljit_sw));
 			EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R0, 0);
@@ -952,13 +1000,7 @@ static sljit_s32 emit_tail_call_end(struct sljit_compiler *compiler, sljit_s32 e
 	sljit_u8 *inst;
 
 	BINARY_IMM32(ADD, extra_space, SLJIT_SP, 0);
-
-	inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
-	FAIL_IF(!inst);
-	INC_SIZE(1);
-	RET();
-
-	return SLJIT_SUCCESS;
+	return emit_byte(compiler, RET_near);
 }
 
 static sljit_s32 tail_call_reg_arg_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
@@ -1075,7 +1117,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
 		stack_size = type;
 		FAIL_IF(tail_call_with_args(compiler, &stack_size, arg_types, src, srcw));
 
-		if (!(src & SLJIT_IMM)) {
+		if (src != SLJIT_IMM) {
 			src = SLJIT_R0;
 			srcw = 0;
 		}
@@ -1142,30 +1184,20 @@ static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *com
 	return SLJIT_SUCCESS;
 }
 
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+static sljit_s32 emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
 {
 	sljit_u8 *inst;
 
-	CHECK_ERROR();
-	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
-	ADJUST_LOCAL_OFFSET(dst, dstw);
-
 	CHECK_EXTRA_REGS(dst, dstw, (void)0);
 
-	if (FAST_IS_REG(dst)) {
-		/* Unused dest is possible here. */
-		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
-		FAIL_IF(!inst);
-
-		INC_SIZE(1);
-		POP_REG(reg_map[dst]);
-		return SLJIT_SUCCESS;
-	}
+	/* Unused dest is possible here. */
+	if (FAST_IS_REG(dst))
+		return emit_byte(compiler, U8(POP_r + reg_map[dst]));
 
 	/* Memory. */
 	inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
 	FAIL_IF(!inst);
-	*inst++ = POP_rm;
+	*inst = POP_rm;
 	return SLJIT_SUCCESS;
 }
 
@@ -1185,8 +1217,8 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
 	else {
 		inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
 		FAIL_IF(!inst);
-		*inst++ = GROUP_FF;
-		*inst |= PUSH_rm;
+		inst[0] = GROUP_FF;
+		inst[1] |= PUSH_rm;
 
 		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
 		FAIL_IF(!inst);
@@ -1197,6 +1229,22 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
 	return SLJIT_SUCCESS;
 }
 
+static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw)
+{
+	sljit_s32 options = compiler->options;
+	sljit_s32 saveds = compiler->saveds;
+	sljit_s32 scratches = compiler->scratches;
+
+	saveds = ((scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3) - SLJIT_KEPT_SAVEDS_COUNT(options)) * SSIZE_OF(sw);
+
+	/* Saving ebp. */
+	if (!(options & SLJIT_ENTER_REG_ARG))
+		saveds += SSIZE_OF(sw);
+
+	return emit_mov(compiler, dst, dstw, SLJIT_MEM1(SLJIT_SP), compiler->local_size + saveds);
+}
+
 /* --------------------------------------------------------------------- */
 /*  Other operations                                                     */
 /* --------------------------------------------------------------------- */
@@ -1279,6 +1327,283 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
 	return SLJIT_SUCCESS;
 }
 
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+	sljit_u8 *inst, *jump_inst1, *jump_inst2;
+	sljit_uw size1, size2;
+
+	/* Binary representation of 0x80000000. */
+	static const sljit_f64 f64_high_bit = (sljit_f64)0x80000000ul;
+
+	CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+	if (!(op & SLJIT_32)) {
+		EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		inst[1] |= ROL;
+
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		inst[1] |= SHR;
+
+		FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_PREF_F2 | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+		FAIL_IF(!inst);
+		INC_SIZE(2);
+		inst[0] = U8(get_jump_code(SLJIT_NOT_CARRY) - 0x10);
+
+		size1 = compiler->size;
+		FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_PREF_F2 | EX86_SSE2, dst_r, SLJIT_MEM0(), (sljit_sw)&f64_high_bit));
+
+		inst[1] = U8(compiler->size - size1);
+
+		if (dst_r == TMP_FREG)
+			return emit_sse2_store(compiler, 0, dst, dstw, TMP_FREG);
+		return SLJIT_SUCCESS;
+	}
+
+	if (!FAST_IS_REG(src)) {
+		EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+		src = TMP_REG1;
+	}
+
+	BINARY_IMM32(CMP, 0, src, 0);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	inst[0] = JL_i8;
+	jump_inst1 = inst;
+
+	size1 = compiler->size;
+
+	FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, src, 0));
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	inst[0] = JMP_i8;
+	jump_inst2 = inst;
+
+	size2 = compiler->size;
+
+	jump_inst1[1] = U8(size2 - size1);
+
+	if (src != TMP_REG1)
+		EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
+
+	inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+	FAIL_IF(!inst);
+	inst[1] |= SHR;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	inst[0] = JNC_i8;
+	jump_inst1 = inst;
+
+	size1 = compiler->size;
+
+	BINARY_IMM32(OR, 1, TMP_REG1, 0);
+	jump_inst1[1] = U8(compiler->size - size1);
+
+	FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+	FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, dst_r, 0));
+
+	jump_inst2[1] = U8(compiler->size - size2);
+
+	if (dst_r == TMP_FREG)
+		return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f32 value)
+{
+	sljit_u8 *inst;
+	union {
+		sljit_s32 imm;
+		sljit_f32 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm != 0)
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+	FAIL_IF(!inst);
+	INC_SIZE(4);
+
+	inst[0] = GROUP_66;
+	inst[1] = GROUP_0F;
+
+	if (u.imm == 0) {
+		inst[2] = PXOR_x_xm;
+		inst[3] = U8(freg | (freg << 3) | MOD_REG);
+	} else {
+		inst[2] = MOVD_x_rm;
+		inst[3] = U8(reg_map[TMP_REG1] | (freg << 3) | MOD_REG);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	sljit_u8 *inst;
+	sljit_s32 tmp_freg = freg;
+	union {
+		sljit_s32 imm[2];
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm[0] == 0) {
+		if (u.imm[1] == 0)
+			return emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0);
+
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[1]);
+	} else
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[0]);
+
+	FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, TMP_REG1, 0));
+
+	if (u.imm[1] == 0)
+		return SLJIT_SUCCESS;
+
+	if (u.imm[0] == 0) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+		FAIL_IF(!inst);
+		INC_SIZE(4);
+
+		inst[0] = GROUP_0F;
+		inst[1] = SHUFPS_x_xm;
+		inst[2] = U8(MOD_REG | (freg << 3) | freg);
+		inst[3] = 0x51;
+		return SLJIT_SUCCESS;
+	}
+
+	if (u.imm[0] != u.imm[1]) {
+		SLJIT_ASSERT(u.imm[1] != 0 && cpu_feature_list != 0);
+
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[1]);
+
+		if (cpu_feature_list & CPU_FEATURE_SSE41) {
+			FAIL_IF(emit_groupf_ext(compiler, PINSRD_x_rm_i8 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2_OP1, freg, TMP_REG1, 0));
+			return emit_byte(compiler, 1);
+		}
+
+		FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, TMP_REG1, 0));
+		tmp_freg = TMP_FREG;
+	}
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+	FAIL_IF(!inst);
+	INC_SIZE(3);
+
+	inst[0] = GROUP_0F;
+	inst[1] = UNPCKLPS_x_xm;
+	inst[2] = U8(MOD_REG | (freg << 3) | tmp_freg);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_u8 *inst;
+	sljit_s32 reg2;
+	sljit_sw regw, reg2w;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	regw = 0;
+	reg2 = 0;
+	reg2w = 0;
+
+	SLJIT_ASSERT(cpu_feature_list != 0);
+
+	if (!(op & SLJIT_32) && (cpu_feature_list & CPU_FEATURE_SSE41)) {
+		if (reg & REG_PAIR_MASK) {
+			reg2 = REG_PAIR_FIRST(reg);
+			reg = REG_PAIR_SECOND(reg);
+
+			CHECK_EXTRA_REGS(reg, regw, (void)0);
+
+			FAIL_IF(emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x)
+				| EX86_PREF_66 | EX86_SSE2_OP1, freg, reg, regw));
+		} else
+			reg2 = reg;
+
+		CHECK_EXTRA_REGS(reg2, reg2w, (void)0);
+
+		FAIL_IF(emit_groupf_ext(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? PINSRD_x_rm_i8 : PEXTRD_rm_x_i8)
+			| EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2_OP1, freg, reg2, reg2w));
+		return emit_byte(compiler, 1);
+	}
+
+	if (reg & REG_PAIR_MASK) {
+		reg2 = REG_PAIR_SECOND(reg);
+		reg = REG_PAIR_FIRST(reg);
+
+		if (reg == reg2)
+			reg = 0;
+
+		CHECK_EXTRA_REGS(reg2, reg2w, (void)0);
+	}
+
+	CHECK_EXTRA_REGS(reg, regw, (void)0);
+
+	if (op & SLJIT_32)
+		return emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x)
+			| EX86_PREF_66 | EX86_SSE2_OP1, freg, reg, regw);
+
+	if (op == SLJIT_COPY_FROM_F64) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
+		FAIL_IF(!inst);
+		INC_SIZE(5);
+
+		inst[0] = GROUP_66;
+		inst[1] = GROUP_0F;
+		inst[2] = PSHUFD_x_xm;
+		inst[3] = U8(MOD_REG | (TMP_FREG << 3) | freg);
+		inst[4] = 1;
+	} else if (reg != 0)
+		FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw));
+
+	if (reg2 != 0)
+		FAIL_IF(emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x)
+			| EX86_PREF_66 | EX86_SSE2_OP1, freg, reg2, reg2w));
+
+	if (GET_OPCODE(op) == SLJIT_COPY_TO_F64) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+		FAIL_IF(!inst);
+		INC_SIZE(3);
+
+		inst[0] = GROUP_0F;
+		inst[1] = UNPCKLPS_x_xm;
+		inst[2] = U8(MOD_REG | (freg << 3) | (reg == 0 ? freg : TMP_FREG));
+	} else
+		FAIL_IF(emit_groupf(compiler, MOVD_rm_x | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw));
+
+	return SLJIT_SUCCESS;
+}
+
 static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler)
 {
 	sljit_sw size;

+ 354 - 92
thirdparty/pcre2/src/sljit/sljitNativeX86_64.c

@@ -37,9 +37,9 @@ static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg,
 	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
 	FAIL_IF(!inst);
 	INC_SIZE(2 + sizeof(sljit_sw));
-	*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
-	*inst++ = U8(MOV_r_i32 | (reg_map[reg] & 0x7));
-	sljit_unaligned_store_sw(inst, imm);
+	inst[0] = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
+	inst[1] = U8(MOV_r_i32 | reg_lmap[reg]);
+	sljit_unaligned_store_sw(inst + 2, imm);
 	return SLJIT_SUCCESS;
 }
 
@@ -72,7 +72,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	sljit_uw inst_size;
 
 	/* The immediate operand must be 32 bit. */
-	SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
+	SLJIT_ASSERT(a != SLJIT_IMM || compiler->mode32 || IS_HALFWORD(imma));
 	/* Both cannot be switched on. */
 	SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
 	/* Size flags not allowed for typed instructions. */
@@ -80,26 +80,24 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	/* Both size flags cannot be switched on. */
 	SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
 	/* SSE2 and immediate is not possible. */
-	SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
-	SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
-		&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
-		&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
+	SLJIT_ASSERT(a != SLJIT_IMM || !(flags & EX86_SSE2));
+	SLJIT_ASSERT(((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+			& ((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+	SLJIT_ASSERT((flags & (EX86_VEX_EXT | EX86_REX)) != EX86_VEX_EXT);
 
 	size &= 0xf;
-	inst_size = size;
+	/* The mod r/m byte is always present. */
+	inst_size = size + 1;
 
 	if (!compiler->mode32 && !(flags & EX86_NO_REXW))
 		rex |= REX_W;
 	else if (flags & EX86_REX)
 		rex |= REX;
 
-	if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
-		inst_size++;
-	if (flags & EX86_PREF_66)
+	if (flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
 		inst_size++;
 
 	/* Calculate size of b. */
-	inst_size += 1; /* mod r/m byte. */
 	if (b & SLJIT_MEM) {
 		if (!(b & OFFS_REG_MASK) && NOT_HALFWORD(immb)) {
 			PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immb));
@@ -119,8 +117,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 					inst_size += sizeof(sljit_s8);
 				else
 					inst_size += sizeof(sljit_s32);
-			}
-			else if (reg_lmap[b & REG_MASK] == 5) {
+			} else if (reg_lmap[b & REG_MASK] == 5) {
 				/* Swap registers if possible. */
 				if ((b & OFFS_REG_MASK) && (immb & 0x3) == 0 && reg_lmap[OFFS_REG(b)] != 5)
 					b = SLJIT_MEM | OFFS_REG(b) | TO_OFFS_REG(b & REG_MASK);
@@ -140,23 +137,26 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 					rex |= REX_X;
 			}
 		}
-	}
-	else if (!(flags & EX86_SSE2_OP2)) {
+	} else if (!(flags & EX86_SSE2_OP2)) {
 		if (reg_map[b] >= 8)
 			rex |= REX_B;
-	}
-	else if (freg_map[b] >= 8)
+	} else if (freg_map[b] >= 8)
 		rex |= REX_B;
 
-	if (a & SLJIT_IMM) {
+	if ((flags & EX86_VEX_EXT) && (rex & 0x3)) {
+		SLJIT_ASSERT(size == 2);
+		size++;
+		inst_size++;
+	}
+
+	if (a == SLJIT_IMM) {
 		if (flags & EX86_BIN_INS) {
 			if (imma <= 127 && imma >= -128) {
 				inst_size += 1;
 				flags |= EX86_BYTE_ARG;
 			} else
 				inst_size += 4;
-		}
-		else if (flags & EX86_SHIFT_INS) {
+		} else if (flags & EX86_SHIFT_INS) {
 			SLJIT_ASSERT(imma <= (compiler->mode32 ? 0x1f : 0x3f));
 			if (imma != 1) {
 				inst_size++;
@@ -168,8 +168,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 			inst_size += sizeof(short);
 		else
 			inst_size += sizeof(sljit_s32);
-	}
-	else {
+	} else {
 		SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
 		/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
 		if (!(flags & EX86_SSE2_OP1)) {
@@ -186,32 +185,34 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 	inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
 	PTR_FAIL_IF(!inst);
 
-	/* Encoding the byte. */
+	/* Encoding prefixes. */
 	INC_SIZE(inst_size);
 	if (flags & EX86_PREF_F2)
 		*inst++ = 0xf2;
-	if (flags & EX86_PREF_F3)
+	else if (flags & EX86_PREF_F3)
 		*inst++ = 0xf3;
-	if (flags & EX86_PREF_66)
+	else if (flags & EX86_PREF_66)
 		*inst++ = 0x66;
+
+	/* Rex is always the last prefix. */
 	if (rex)
 		*inst++ = rex;
+
 	buf_ptr = inst + size;
 
 	/* Encode mod/rm byte. */
 	if (!(flags & EX86_SHIFT_INS)) {
-		if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
+		if ((flags & EX86_BIN_INS) && a == SLJIT_IMM)
 			*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
 
-		if (a & SLJIT_IMM)
+		if (a == SLJIT_IMM)
 			*buf_ptr = 0;
 		else if (!(flags & EX86_SSE2_OP1))
 			*buf_ptr = U8(reg_lmap[a] << 3);
 		else
 			*buf_ptr = U8(freg_lmap[a] << 3);
-	}
-	else {
-		if (a & SLJIT_IMM) {
+	} else {
+		if (a == SLJIT_IMM) {
 			if (imma == 1)
 				*inst = GROUP_SHIFT_1;
 			else
@@ -238,8 +239,9 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 			if (!(b & OFFS_REG_MASK))
 				*buf_ptr++ |= reg_lmap_b;
 			else {
-				*buf_ptr++ |= 0x04;
-				*buf_ptr++ = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3));
+				buf_ptr[0] |= 0x04;
+				buf_ptr[1] = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3));
+				buf_ptr += 2;
 			}
 
 			if (immb != 0 || reg_lmap_b == 5) {
@@ -250,26 +252,26 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 					buf_ptr += sizeof(sljit_s32);
 				}
 			}
-		}
-		else {
+		} else {
 			if (reg_lmap_b == 5)
 				*buf_ptr |= 0x40;
 
-			*buf_ptr++ |= 0x04;
-			*buf_ptr++ = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6));
+			buf_ptr[0] |= 0x04;
+			buf_ptr[1] = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6));
+			buf_ptr += 2;
 
 			if (reg_lmap_b == 5)
 				*buf_ptr++ = 0;
 		}
-	}
-	else {
-		*buf_ptr++ |= 0x04;
-		*buf_ptr++ = 0x25;
+	} else {
+		buf_ptr[0] |= 0x04;
+		buf_ptr[1] = 0x25;
+		buf_ptr += 2;
 		sljit_unaligned_store_s32(buf_ptr, (sljit_s32)immb); /* 32 bit displacement. */
 		buf_ptr += sizeof(sljit_s32);
 	}
 
-	if (a & SLJIT_IMM) {
+	if (a == SLJIT_IMM) {
 		if (flags & EX86_BYTE_ARG)
 			*buf_ptr = U8(imma);
 		else if (flags & EX86_HALF_ARG)
@@ -278,7 +280,78 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
 			sljit_unaligned_store_s32(buf_ptr, (sljit_s32)imma);
 	}
 
-	return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
+	return inst;
+}
+
+static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw op,
+	/* The first and second register operand. */
+	sljit_s32 a, sljit_s32 v,
+	/* The general operand (not immediate). */
+	sljit_s32 b, sljit_sw immb)
+{
+	sljit_u8 *inst;
+	sljit_u8 vex = 0;
+	sljit_u8 vex_m = 0;
+	sljit_uw size;
+
+	SLJIT_ASSERT(((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+			& ((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+
+	op |= EX86_REX;
+
+	if (op & VEX_OP_0F38)
+		vex_m = 0x2;
+	else if (op & VEX_OP_0F3A)
+		vex_m = 0x3;
+
+	if ((op & VEX_W) || ((op & VEX_AUTO_W) && !compiler->mode32)) {
+		if (vex_m == 0)
+			vex_m = 0x1;
+
+		vex |= 0x80;
+	}
+
+	if (op & EX86_PREF_66)
+		vex |= 0x1;
+	else if (op & EX86_PREF_F2)
+		vex |= 0x3;
+	else if (op & EX86_PREF_F3)
+		vex |= 0x2;
+
+	op &= ~(EX86_PREF_66 | EX86_PREF_F2 | EX86_PREF_F3);
+
+	if (op & VEX_256)
+		vex |= 0x4;
+
+	vex = U8(vex | ((((op & VEX_SSE2_OPV) ? freg_map[v] : reg_map[v]) ^ 0xf) << 3));
+
+	size = op & ~(sljit_uw)0xff;
+	size |= (vex_m == 0) ? (EX86_VEX_EXT | 2) : 3;
+
+	inst = emit_x86_instruction(compiler, size, a, 0, b, immb);
+	FAIL_IF(!inst);
+
+	SLJIT_ASSERT((inst[-1] & 0xf0) == REX);
+
+	/* If X or B is present in REX prefix. */
+	if (vex_m == 0 && inst[-1] & 0x3)
+		vex_m = 0x1;
+
+	if (vex_m == 0) {
+		vex |= U8(((inst[-1] >> 2) ^ 0x1) << 7);
+
+		inst[-1] = 0xc5;
+		inst[0] = vex;
+		inst[1] = U8(op);
+		return SLJIT_SUCCESS;
+	}
+
+	vex_m |= U8((inst[-1] ^ 0x7) << 5);
+	inst[-1] = 0xc4;
+	inst[0] = vex_m;
+	inst[1] = vex;
+	inst[2] = U8(op);
+	return SLJIT_SUCCESS;
 }
 
 /* --------------------------------------------------------------------- */
@@ -370,6 +443,12 @@ static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, slji
 	return code_ptr;
 }
 
+#ifdef _WIN64
+typedef struct {
+	sljit_sw regs[2];
+} sljit_sse2_reg;
+#endif /* _WIN64 */
+
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
 	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
 	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
@@ -423,7 +502,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
 
 #ifdef _WIN64
 	local_size += SLJIT_LOCALS_OFFSET;
-	saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16);
+	saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sse2_reg);
 
 	if (saved_float_regs_size > 0) {
 		saved_float_regs_offset = ((local_size + 0xf) & ~0xf);
@@ -532,16 +611,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
 
 		tmp = SLJIT_FS0 - fsaveds;
 		for (i = SLJIT_FS0; i > tmp; i--) {
-			inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
-			*inst++ = GROUP_0F;
-			*inst = MOVAPS_xm_x;
+			FAIL_IF(emit_groupf(compiler, MOVAPS_xm_x | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
 			saved_float_regs_offset += 16;
 		}
 
 		for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
-			inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
-			*inst++ = GROUP_0F;
-			*inst = MOVAPS_xm_x;
+			FAIL_IF(emit_groupf(compiler, MOVAPS_xm_x | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
 			saved_float_regs_offset += 16;
 		}
 	}
@@ -565,7 +640,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
 
 #ifdef _WIN64
 	local_size += SLJIT_LOCALS_OFFSET;
-	saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16);
+	saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sse2_reg);
 
 	if (saved_float_regs_size > 0)
 		local_size = ((local_size + 0xf) & ~0xf) + saved_float_regs_size;
@@ -591,7 +666,7 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
 #endif /* _WIN64 */
 
 #ifdef _WIN64
-	saved_float_regs_offset = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16);
+	saved_float_regs_offset = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sse2_reg);
 
 	if (saved_float_regs_offset > 0) {
 		compiler->mode32 = 1;
@@ -599,16 +674,12 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
 
 		tmp = SLJIT_FS0 - fsaveds;
 		for (i = SLJIT_FS0; i > tmp; i--) {
-			inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
-			*inst++ = GROUP_0F;
-			*inst = MOVAPS_x_xm;
+			FAIL_IF(emit_groupf(compiler, MOVAPS_x_xm | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
 			saved_float_regs_offset += 16;
 		}
 
 		for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
-			inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
-			*inst++ = GROUP_0F;
-			*inst = MOVAPS_x_xm;
+			FAIL_IF(emit_groupf(compiler, MOVAPS_x_xm | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
 			saved_float_regs_offset += 16;
 		}
 
@@ -656,20 +727,13 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
 {
-	sljit_u8 *inst;
-
 	CHECK_ERROR();
 	CHECK(check_sljit_emit_return_void(compiler));
 
 	compiler->mode32 = 0;
 
 	FAIL_IF(emit_stack_frame_release(compiler, 0));
-
-	inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
-	FAIL_IF(!inst);
-	INC_SIZE(1);
-	RET();
-	return SLJIT_SUCCESS;
+	return emit_byte(compiler, RET_near);
 }
 
 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
@@ -863,22 +927,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
 	return sljit_emit_ijump(compiler, type, src, srcw);
 }
 
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+static sljit_s32 emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
 {
 	sljit_u8 *inst;
 
-	CHECK_ERROR();
-	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
-	ADJUST_LOCAL_OFFSET(dst, dstw);
-
 	if (FAST_IS_REG(dst)) {
-		if (reg_map[dst] < 8) {
-			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
-			FAIL_IF(!inst);
-			INC_SIZE(1);
-			POP_REG(reg_lmap[dst]);
-			return SLJIT_SUCCESS;
-		}
+		if (reg_map[dst] < 8)
+			return emit_byte(compiler, U8(POP_r + reg_lmap[dst]));
 
 		inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
 		FAIL_IF(!inst);
@@ -892,7 +947,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
 	compiler->mode32 = 1;
 	inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
 	FAIL_IF(!inst);
-	*inst++ = POP_rm;
+	*inst = POP_rm;
 	return SLJIT_SUCCESS;
 }
 
@@ -922,8 +977,8 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
 		compiler->mode32 = 1;
 		inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
 		FAIL_IF(!inst);
-		*inst++ = GROUP_FF;
-		*inst |= PUSH_rm;
+		inst[0] = GROUP_FF;
+		inst[1] |= PUSH_rm;
 
 		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
 		FAIL_IF(!inst);
@@ -934,6 +989,16 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
 	return SLJIT_SUCCESS;
 }
 
+static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw)
+{
+	sljit_s32 saved_regs_size;
+
+	compiler->mode32 = 0;
+	saved_regs_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);
+	return emit_mov(compiler, dst, dstw, SLJIT_MEM1(SLJIT_SP), compiler->local_size + saved_regs_size);
+}
+
 /* --------------------------------------------------------------------- */
 /*  Other operations                                                     */
 /* --------------------------------------------------------------------- */
@@ -1027,15 +1092,15 @@ static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
 
 	compiler->mode32 = 0;
 
-	if (src & SLJIT_IMM) {
+	if (src == SLJIT_IMM) {
 		if (FAST_IS_REG(dst)) {
-			if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
-				inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
-				FAIL_IF(!inst);
-				*inst = MOV_rm_i32;
-				return SLJIT_SUCCESS;
-			}
-			return emit_load_imm64(compiler, dst, srcw);
+			if (!sign || ((sljit_u32)srcw <= 0x7fffffff))
+				return emit_do_imm32(compiler, reg_map[dst] <= 7 ? 0 : REX_B, U8(MOV_r_i32 | reg_lmap[dst]), srcw);
+
+			inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = MOV_rm_i32;
+			return SLJIT_SUCCESS;
 		}
 		compiler->mode32 = 1;
 		inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
@@ -1053,10 +1118,10 @@ static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
 		if (sign) {
 			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
 			FAIL_IF(!inst);
-			*inst++ = MOVSXD_r_rm;
+			*inst = MOVSXD_r_rm;
 		} else {
 			compiler->mode32 = 1;
-			FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
+			EMIT_MOV(compiler, dst_r, 0, src, srcw);
 			compiler->mode32 = 0;
 		}
 	}
@@ -1072,6 +1137,203 @@ static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
 	return SLJIT_SUCCESS;
 }
 
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+	sljit_u8 *inst, *jump_inst1, *jump_inst2;
+	sljit_uw size1, size2;
+
+	compiler->mode32 = 0;
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32) {
+		if (src != SLJIT_IMM) {
+			compiler->mode32 = 1;
+			EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+			compiler->mode32 = 0;
+		} else
+			FAIL_IF(emit_do_imm32(compiler, reg_map[TMP_REG1] <= 7 ? 0 : REX_B, U8(MOV_r_i32 | reg_lmap[TMP_REG1]), srcw));
+
+		FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+
+		compiler->mode32 = 1;
+
+		if (dst_r == TMP_FREG)
+			return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
+		return SLJIT_SUCCESS;
+	}
+
+	if (!FAST_IS_REG(src)) {
+		EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+		src = TMP_REG1;
+	}
+
+	BINARY_IMM32(CMP, 0, src, 0);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	inst[0] = JL_i8;
+	jump_inst1 = inst;
+
+	size1 = compiler->size;
+
+	compiler->mode32 = 0;
+	FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, src, 0));
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	inst[0] = JMP_i8;
+	jump_inst2 = inst;
+
+	size2 = compiler->size;
+
+	jump_inst1[1] = U8(size2 - size1);
+
+	if (src != TMP_REG1)
+		EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
+
+	EMIT_MOV(compiler, TMP_REG2, 0, src, 0);
+
+	inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+	FAIL_IF(!inst);
+	inst[1] |= SHR;
+
+	compiler->mode32 = 1;
+	BINARY_IMM32(AND, 1, TMP_REG2, 0);
+
+	compiler->mode32 = 0;
+	inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG2, 0);
+	FAIL_IF(!inst);
+	inst[0] = OR_r_rm;
+
+	FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+	compiler->mode32 = 1;
+	FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, dst_r, 0));
+
+	jump_inst2[1] = U8(compiler->size - size2);
+
+	if (dst_r == TMP_FREG)
+		return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 sljit_emit_fset(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_u8 rex, sljit_s32 is_zero)
+{
+	sljit_u8 *inst;
+	sljit_u32 size;
+
+	if (is_zero) {
+		rex = freg_map[freg] >= 8 ? (REX_R | REX_B) : 0;
+	} else {
+		if (freg_map[freg] >= 8)
+			rex |= REX_R;
+		if (reg_map[TMP_REG1] >= 8)
+			rex |= REX_B;
+	}
+
+	size = (rex != 0) ? 5 : 4;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+	INC_SIZE(size);
+
+	*inst++ = GROUP_66;
+	if (rex != 0)
+		*inst++ = rex;
+	inst[0] = GROUP_0F;
+
+	if (is_zero) {
+		inst[1] = PXOR_x_xm;
+		inst[2] = U8(freg_lmap[freg] | (freg_lmap[freg] << 3) | MOD_REG);
+	} else {
+		inst[1] = MOVD_x_rm;
+		inst[2] = U8(reg_lmap[TMP_REG1] | (freg_lmap[freg] << 3) | MOD_REG);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f32 value)
+{
+	union {
+		sljit_s32 imm;
+		sljit_f32 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm != 0) {
+		compiler->mode32 = 1;
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm);
+	}
+
+	return sljit_emit_fset(compiler, freg, 0, u.imm == 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+	sljit_s32 freg, sljit_f64 value)
+{
+	union {
+		sljit_sw imm;
+		sljit_f64 value;
+	} u;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+	u.value = value;
+
+	if (u.imm != 0) {
+		compiler->mode32 = 0;
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm);
+	}
+
+	return sljit_emit_fset(compiler, freg, REX_W, u.imm == 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 freg, sljit_s32 reg)
+{
+	sljit_u8 *inst;
+	sljit_u32 size;
+	sljit_u8 rex = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+	if (!(op & SLJIT_32))
+		rex = REX_W;
+
+	if (freg_map[freg] >= 8)
+		rex |= REX_R;
+
+	if (reg_map[reg] >= 8)
+		rex |= REX_B;
+
+	size = (rex != 0) ? 5 : 4;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+	INC_SIZE(size);
+
+	*inst++ = GROUP_66;
+	if (rex != 0)
+		*inst++ = rex;
+	inst[0] = GROUP_0F;
+	inst[1] = GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x;
+	inst[2] = U8(reg_lmap[reg] | (freg_lmap[freg] << 3) | MOD_REG);
+
+	return SLJIT_SUCCESS;
+}
+
 static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler)
 {
 	sljit_s32 tmp, size;

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 439 - 319
thirdparty/pcre2/src/sljit/sljitNativeX86_common.c


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä