FILE(GLOB man1 ${PROJECT_SOURCE_DIR}/doc/*.1)
FILE(GLOB man3 ${PROJECT_SOURCE_DIR}/doc/*.3)
-INSTALL(FILES ${man1} DESTINATION man/man1)
-INSTALL(FILES ${man3} DESTINATION man/man3)
+INSTALL(FILES ${man1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+INSTALL(FILES ${man3} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
INSTALL(FILES ${html} DESTINATION share/doc/pcre2/html)
IF(MSVC AND INSTALL_MSVC_PDB)
--------------------
Before the move to GitHub, this was the only record of changes to PCRE2. Now
-there is often more detail in the pull requests.
+there is also the log of commit messages.
+
+Version 10.44 07-June-2024
+--------------------------
+
+1. If a pattern contained a variable-length lookbehind in which the first
+branch was not the one with the shortest minimum length, and the lookbehind
+contained a capturing group, and elsewhere in the pattern there was another
+lookbehind that referenced that group, the pattern was incorrectly compiled,
+leading to unpredictable results, including crashes in JIT compiling. An
+example pattern is: /(((?<=123?456456|ABC)))(?<=\2)/
+
+2. Further updates to the oss-fuzz support:
+
+ (a) Limit quantifiers for groups and classes to be no more than 10. This
+ avoids very long JIT compile times that happen in some cases when groups
+ are replicated for quantification, and very long match times when
+ classes contain a lot of non-ascii characters.
+
+ (b) Added PCRE2_EXTENDED_MORE to the list of allowed options.
+
+ (c) Arranged for text error messages to be shown in 16-bit and 32-bit modes.
+
+ (d) Made the output in standalone mode more readable.
+
+ (e) General code tidies.
+
+ (f) Limit the size of compiled patterns to 10MB (see 6 below).
+
+ (g) Do not run JIT on patterns whose compiled length is greater than 200K
+ bytes because this takes a long time, causing oss-fuzz to time out.
+
+ (h) Avoid compiling or matching twice with the same options (this could
+ happen if the input didn't set any options).
+
+3. Increase the maximum length of a name for a group from 32 to 128 because
+there is a user for whom 32 is too small.
+
+4. Cause pcre2test to output a message when pcre2_jit_compile() gives an error
+return if either jitverify or info is specified.
+
+5. Some auxiliary files for building under OpenVMS that were contributed by
+Alexey Chupahin have been installed.
+
+6. Added pcre2_set_max_pattern_compiled_length() to limit the size of compiled
+patterns.
+
+7. There was a bug in the implementation of \X caused by my (PH) misreading or
+misunderstanding one of the grapheme sequence breaking rules in Unicode Annex
+#29. A break should occur between two characters with the Extended Pictographic
+break property unless a zero-width joiner intervenes. PCRE2 was not insisting
+on the ZWJ, causing \X to match more than it should. See GitHub issue #410.
+
+8. Avoid compilation issues with proprietary compilers in UNIX since 10.43.
Version 10.43 16-February-2024
32. Changed the meaning of \w (and its synonyms) in UCP mode to match Perl. It
now matches characters whose general categories are L or N or whose particular
-categories are Mn (non-spacing mark) or Pc (combining puntuation). The latter
+categories are Mn (non-spacing mark) or Pc (combining punctuation). The latter
includes underscore.
33. Changed the meaning of [:xdigit:] in UCP mode to match Perl. It now also
coverage.
15. Fixed a bug in pcre2grep that could cause an extra newline to be written
-after output generaed by --output.
+after output generated by --output.
16. If a file has a .bz2 extension but is not in fact compressed, pcre2grep
should process it as a plain text file. A bug stopped this happening; now fixed
that an appropriate width is chosen if pointers are 64bit wide and
long is not (ex: Windows 64bit).
- IMHO removing the cast (and therefore the possibilty of truncation)
+ IMHO removing the cast (and therefore the possibility of truncation)
make the code cleaner and the fallback is likely portable enough
with all 64-bit POSIX systems doing LP64 except for Windows.
quantifier was nevertheless complaining that a quantifier number was too big.
5. A run of autoconf suggested that configure.ac was out-of-date with respect
-to the lastest autoconf. Running autoupdate made some valid changes, some valid
+to the latest autoconf. Running autoupdate made some valid changes, some valid
suggestions, and also some invalid changes, which were fixed by hand. Autoconf
now runs clean and the resulting "configure" seems to work, so I hope nothing
is broken. Later: the requirement for autoconf 2.70 broke some automatic test
Makefile.am and configure.ac by H.J. Lu. Equivalent patch for CMakeLists.txt
invented by PH.
-2. Fix inifinite loop when a single byte newline is searched in JIT when
+2. Fix infinite loop when a single byte newline is searched in JIT when
invalid utf8 mode is enabled.
3. Updated CMakeLists.txt with patch from Wolfgang Stöggl (Bugzilla #2584):
the final repetition, not from an earlier repetition that might be the
destination of a backtrack. This feature was documented, and was carried over
into PCRE2. However, it has now been realized that the major refactoring that
-was done for 10.30 has made this atomicizing unnecessary, and it is confusing
+was done for 10.30 has made this atomizing unnecessary, and it is confusing
when users are unaware of it, making some patterns appear not to be working as
expected. Capture values of recursive back references in repeated groups are
now correctly backtracked, so this unnecessary restriction has been removed.
7. Automatic callouts are no longer generated before and after callouts in the
pattern.
-8. When pcre2test was outputing information from a callout, the caret indicator
+8. When pcre2test was outputting information from a callout, the caret indicator
for the current position in the subject line was incorrect if it was after an
escape sequence for a character whose code point was greater than \x{ff}.
the stack size via pcre2test is possible). This avoids having to manually set a
large stack size when testing with clang.
-42. Fix register overwite in JIT when SSE2 acceleration is enabled.
+42. Fix register overwrite in JIT when SSE2 acceleration is enabled.
43. Detect integer overflow in pcre2test pattern and data repetition counts.
7. When an (*ACCEPT) is triggered inside capturing parentheses, it arranges for
those parentheses to be closed with whatever has been captured so far. However,
it was failing to mark any other groups between the highest capture so far and
-the currrent group as "unset". Thus, the ovector for those groups contained
+the current group as "unset". Thus, the ovector for those groups contained
whatever was previously there. An example is the pattern /(x)|((*ACCEPT))/ when
matched against "abcd".
doc/html/pcre2_set_glob_separator.html \
doc/html/pcre2_set_heap_limit.html \
doc/html/pcre2_set_match_limit.html \
+ doc/html/pcre2_set_max_pattern_compiled_length.html \
doc/html/pcre2_set_max_pattern_length.html \
doc/html/pcre2_set_max_varlookbehind.html \
doc/html/pcre2_set_offset_limit.html \
doc/pcre2_set_glob_separator.3 \
doc/pcre2_set_heap_limit.3 \
doc/pcre2_set_match_limit.3 \
+ doc/pcre2_set_max_pattern_compiled_length.3 \
doc/pcre2_set_max_pattern_length.3 \
doc/pcre2_set_max_varlookbehind.3 \
doc/pcre2_set_offset_limit.3 \
noinst_PROGRAMS =
# Additional files to delete on 'make clean', 'make distclean',
-# and 'make maintainer-clean'.
+# and 'make maintainer-clean'. It turns out that the default is to delete only
+# those binaries that *this* configuration has created. If the configuration
+# has been changed, some binaries may not get automatically deleted. Therefore
+# we list them here.
+
+CLEANFILES = \
+ pcre2_dftables \
+ pcre2_jit_test \
+ pcre2fuzzcheck-8 \
+ pcre2fuzzcheck-16 \
+ pcre2fuzzcheck-32 \
+ pcre2demo
-CLEANFILES =
DISTCLEANFILES = src/config.h.in~
MAINTAINERCLEANFILES =
NON-AUTOTOOLS-BUILD \
HACKING
+# These are support files for building under VMS
+
+EXTRA_DIST += \
+ vms/configure.com \
+ vms/openvms_readme.txt \
+ vms/pcre2.h_patch \
+ vms/stdint.h
+
# These files are used in the preparation of a release
EXTRA_DIST += \
src/sljit/sljitNativeX86_32.c \
src/sljit/sljitNativeX86_64.c \
src/sljit/sljitNativeX86_common.c \
+ src/sljit/sljitSerialize.c \
src/sljit/sljitUtils.c \
src/sljit/allocator_src/sljitExecAllocatorApple.c \
src/sljit/allocator_src/sljitExecAllocatorCore.c \
doc/html/pcre2_set_glob_separator.html \
doc/html/pcre2_set_heap_limit.html \
doc/html/pcre2_set_match_limit.html \
+ doc/html/pcre2_set_max_pattern_compiled_length.html \
doc/html/pcre2_set_max_pattern_length.html \
doc/html/pcre2_set_max_varlookbehind.html \
doc/html/pcre2_set_offset_limit.html \
doc/pcre2_set_glob_separator.3 \
doc/pcre2_set_heap_limit.3 \
doc/pcre2_set_match_limit.3 \
+ doc/pcre2_set_max_pattern_compiled_length.3 \
doc/pcre2_set_max_pattern_length.3 \
doc/pcre2_set_max_varlookbehind.3 \
doc/pcre2_set_offset_limit.3 \
dist_noinst_SCRIPTS = RunTest $(am__append_45)
# Additional files to delete on 'make clean', 'make distclean',
-# and 'make maintainer-clean'.
+# and 'make maintainer-clean'. It turns out that the default is to delete only
+# those binaries that *this* configuration has created. If the configuration
+# has been changed, some binaries may not get automatically deleted. Therefore
+# we list them here.
# RunTest and RunGrepTest should clean up after themselves, but just in case
# they don't, add their working files to CLEANFILES.
-CLEANFILES = src/pcre2_chartables.c testSinput test3input test3output \
+CLEANFILES = pcre2_dftables pcre2_jit_test pcre2fuzzcheck-8 \
+ pcre2fuzzcheck-16 pcre2fuzzcheck-32 pcre2demo \
+ src/pcre2_chartables.c testSinput test3input test3output \
test3outputA test3outputB testtry teststdout teststderr \
teststderrgrep testtemp1grep testtemp2grep testtrygrep \
testNinputgrep
# These files contain maintenance information
+# These are support files for building under VMS
+
# These files are used in the preparation of a release
# These files are usable versions of pcre2.h and config.h that are distributed
# PCRE2 demonstration program. Not built automatically. The point is that the
# users should build it themselves. So just distribute the source.
EXTRA_DIST = m4/ax_pthread.m4 m4/pcre2_visibility.m4 \
- NON-AUTOTOOLS-BUILD HACKING PrepareRelease CheckMan CleanTxt \
- Detrail 132html doc/index.html.src src/pcre2.h.generic \
- src/config.h.generic src/pcre2_ucptables.c \
- src/pcre2_chartables.c.dist src/sljit/sljitConfig.h \
- src/sljit/sljitConfigCPU.h src/sljit/sljitConfigInternal.h \
- src/sljit/sljitLir.c src/sljit/sljitLir.h \
- src/sljit/sljitNativeARM_32.c src/sljit/sljitNativeARM_64.c \
- src/sljit/sljitNativeARM_T2_32.c \
+ NON-AUTOTOOLS-BUILD HACKING vms/configure.com \
+ vms/openvms_readme.txt vms/pcre2.h_patch vms/stdint.h \
+ PrepareRelease CheckMan CleanTxt Detrail 132html \
+ doc/index.html.src src/pcre2.h.generic src/config.h.generic \
+ src/pcre2_ucptables.c src/pcre2_chartables.c.dist \
+ src/sljit/sljitConfig.h src/sljit/sljitConfigCPU.h \
+ src/sljit/sljitConfigInternal.h src/sljit/sljitLir.c \
+ src/sljit/sljitLir.h src/sljit/sljitNativeARM_32.c \
+ src/sljit/sljitNativeARM_64.c src/sljit/sljitNativeARM_T2_32.c \
src/sljit/sljitNativeLOONGARCH_64.c \
src/sljit/sljitNativeMIPS_32.c src/sljit/sljitNativeMIPS_64.c \
src/sljit/sljitNativeMIPS_common.c \
src/sljit/sljitNativeRISCV_common.c \
src/sljit/sljitNativeS390X.c src/sljit/sljitNativeX86_32.c \
src/sljit/sljitNativeX86_64.c \
- src/sljit/sljitNativeX86_common.c src/sljit/sljitUtils.c \
+ src/sljit/sljitNativeX86_common.c src/sljit/sljitSerialize.c \
+ src/sljit/sljitUtils.c \
src/sljit/allocator_src/sljitExecAllocatorApple.c \
src/sljit/allocator_src/sljitExecAllocatorCore.c \
src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c \
-------------------------
+Version 10.44 07-June-2024
+--------------------------
+
+This is mostly a bug-fix and tidying release. There is one new function, to set
+a maximum size for a compiled pattern. The maximum name length for groups is
+increased to 128. Some auxiliary files for building under VMS are added.
+
+
Version 10.43 16-February-2024
------------------------------
Building PCRE2 on Windows with Visual Studio
Testing with RunTest.bat
Building PCRE2 on native z/OS and z/VM
+ Building PCRE2 under VMS
GENERAL
z/OS file formats. The port provides an API for LE languages such as COBOL and
for the z/OS and z/VM versions of the Rexx languages.
+
+BUILDING PCRE2 UNDER VMS
+
+Alexey Chuphin has contributed some auxiliary files for building PCRE2 under
+OpenVMS. They are in the "vms" directory in the distribution tarball. Please
+read the file called vms/openvms_readme.txt. The pcre2test and pcre2grep
+programs contain some VMS-specific code.
+
===========================
-Last Updated: 15 April 2023
+Last Updated: 16 April 2024
===========================
The PCRE2 APIs
Documentation for PCRE2
- Contributions by users of PCRE2
Building PCRE2 on non-Unix-like systems
Building PCRE2 without using autotools
Building PCRE2 using autotools
src/config.h.generic ) a version of config.h for use in non-"configure"
) environments
+(F) Auxiliary files for building PCRE2 under OpenVMS
+
+ vms/configure.com )
+ vms/openvms_readme.txt ) These files were contributed by a PCRE2 user.
+ vms/pcre2.h_patch )
+ vms/stdint.h )
+
Philip Hazel
Email local part: Philip.Hazel
Email domain: gmail.com
-Last updated: 24 November 2023
+Last updated: 15 April 2024
set(PCRE2_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
if (MINGW AND PCRE2_NON_STANDARD_LIB_SUFFIX)
set(PCRE2_SUFFIX "-0.dll")
+ elseif(MSVC)
+ set(PCRE2_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX})
endif ()
endif ()
find_library(PCRE2_8BIT_LIBRARY NAMES ${PCRE2_PREFIX}${PCRE2_8BIT_NAME}${PCRE2_SUFFIX} ${PCRE2_PREFIX}${PCRE2_8BIT_NAME}d${PCRE2_SUFFIX} DOC "8 bit PCRE2 library")
#define PCRE2GREP_BUFSIZE @PCRE2GREP_BUFSIZE@
#define PCRE2GREP_MAX_BUFSIZE @PCRE2GREP_MAX_BUFSIZE@
-#define MAX_NAME_SIZE 32
+#define MAX_NAME_SIZE 128
#define MAX_NAME_COUNT 10000
/* end config.h for CMake builds */
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for PCRE2 10.43.
+# Generated by GNU Autoconf 2.72 for PCRE2 10.44.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation,
# Identity of this package.
PACKAGE_NAME='PCRE2'
PACKAGE_TARNAME='pcre2'
-PACKAGE_VERSION='10.43'
-PACKAGE_STRING='PCRE2 10.43'
+PACKAGE_VERSION='10.44'
+PACKAGE_STRING='PCRE2 10.44'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-'configure' configures PCRE2 10.43 to adapt to many kinds of systems.
+'configure' configures PCRE2 10.44 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of PCRE2 10.43:";;
+ short | recursive ) echo "Configuration of PCRE2 10.44:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-PCRE2 configure 10.43
+PCRE2 configure 10.44
generated by GNU Autoconf 2.72
Copyright (C) 2023 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by PCRE2 $as_me 10.43, which was
+It was created by PCRE2 $as_me 10.44, which was
generated by GNU Autoconf 2.72. Invocation command line was
$ $0$ac_configure_args_raw
# Define the identity of the package.
PACKAGE='pcre2'
- VERSION='10.43'
+ VERSION='10.44'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
-macro_version='2.4.7.4-1ec8f-dirty'
-macro_revision='2.4.7.4'
+macro_version='2.5.0.1-38c1-dirty'
+macro_revision='2.5.0.1'
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
printf %s "checking for ld used by $CC... " >&6; }
case $host in
- *-*-mingw*)
+ *-*-mingw* | *-*-windows*)
# gcc leaves a trailing carriage return, which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
# Tru64's nm complains that /dev/null is an invalid object file
# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
case $build_os in
- mingw*) lt_bad_file=conftest.nm/nofile ;;
+ mingw* | windows*) lt_bad_file=conftest.nm/nofile ;;
*) lt_bad_file=/dev/null ;;
esac
case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in
lt_cv_sys_max_cmd_len=-1;
;;
- cygwin* | mingw* | cegcc*)
+ cygwin* | mingw* | windows* | cegcc*)
# On Win9x/ME, this test blows up -- it succeeds, but takes
# about 5 minutes as the teststring grows exponentially.
# Worse, since 9x/ME are not pre-emptively multitasking,
lt_cv_sys_max_cmd_len=8192;
;;
- bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*)
+ darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
e) case $host in
*-*-mingw* )
case $build in
- *-*-mingw* ) # actually msys
+ *-*-mingw* | *-*-windows* ) # actually msys
lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
;;
*-*-cygwin* )
;;
*-*-cygwin* )
case $build in
- *-*-mingw* ) # actually msys
+ *-*-mingw* | *-*-windows* ) # actually msys
lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
;;
*-*-cygwin* )
e) #assume ordinary cross tools, or native build.
lt_cv_to_tool_file_cmd=func_convert_file_noop
case $host in
- *-*-mingw* )
+ *-*-mingw* | *-*-windows* )
case $build in
- *-*-mingw* ) # actually msys
+ *-*-mingw* | *-*-windows* ) # actually msys
lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
;;
esac
esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
if test yes != "$GCC"; then
reload_cmds=false
fi
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}file", so it can be a program name with args.
-set dummy ${ac_tool_prefix}file; ac_word=$2
+# Extract the first word of "file", so it can be a program name with args.
+set dummy file; ac_word=$2
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
printf %s "checking for $ac_word... " >&6; }
if test ${ac_cv_prog_FILECMD+y}
esac
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_FILECMD="${ac_tool_prefix}file"
+ ac_cv_prog_FILECMD=":"
printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
fi
-fi
-if test -z "$ac_cv_prog_FILECMD"; then
- ac_ct_FILECMD=$FILECMD
- # Extract the first word of "file", so it can be a program name with args.
-set dummy file; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_FILECMD+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_FILECMD"; then
- ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_FILECMD="file"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi ;;
-esac
-fi
-ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD
-if test -n "$ac_ct_FILECMD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5
-printf "%s\n" "$ac_ct_FILECMD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_FILECMD" = x; then
- FILECMD=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- FILECMD=$ac_ct_FILECMD
- fi
-else
- FILECMD="$ac_cv_prog_FILECMD"
-fi
-
# 'none' -- dependencies not supported.
# 'unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
# 'file_magic [[regex]]' -- check by looking for files in library path
# that responds to the $file_magic_cmd with a given extended regex.
# If you have 'file' or equivalent on your system and you're not sure
lt_cv_file_magic_cmd='func_win32_libid'
;;
-mingw* | pw32*)
+mingw* | windows* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
# func_win32_libid shell function, so use a weaker test based on 'objdump',
# unless we find 'file', for example because we are cross-compiling.
lt_cv_deplibs_check_method=pass_all
;;
-openbsd* | bitrig*)
+openbsd*)
if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
else
want_nocaseglob=no
if test "$build" = "$host"; then
case $host_os in
- mingw* | pw32*)
+ mingw* | windows* | pw32*)
if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
want_nocaseglob=yes
else
e) lt_cv_sharedlib_from_linklib_cmd='unknown'
case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
# two different shell functions defined in ltmain.sh;
# decide which one to use based on capabilities of $DLLTOOL
case `$DLLTOOL --help 2>&1` in
# Use ARFLAGS variable as AR's operation code to sync the variable naming with
# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have
-# higher priority because thats what people were doing historically (setting
+# higher priority because that's what people were doing historically (setting
# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS
# variable obsoleted/removed.
old_postuninstall_cmds=
if test -n "$RANLIB"; then
- case $host_os in
- bitrig* | openbsd*)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
- ;;
- *)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
- ;;
- esac
old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
fi
case $host_os in
aix*)
symcode='[BCDT]'
;;
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
symcode='[ABCDGISTW]'
;;
hpux*)
symcode='[BCDEGQRST]'
;;
solaris*)
- symcode='[BDRT]'
+ symcode='[BCDRT]'
;;
sco3.2v5*)
symcode='[DT]'
# Handle CRLF in mingw tool chain
opt_cr=
case $build_os in
-mingw*)
+mingw* | windows*)
opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
;;
esac
case $with_sysroot in #(
yes)
if test yes = "$GCC"; then
- lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ # Trim trailing / since we'll always append absolute paths and we want
+ # to avoid //, if only for less confusing output for the user.
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'`
fi
;; #(
/*)
;;
x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*)
# Find out what ABI is being produced by ac_compile, and set linker
# options accordingly. Note that the listed cases only cover the
# situations where additional linker options are needed (such as when
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_i386_fbsd"
;;
- x86_64-*linux*)
+ x86_64-*linux*|x86_64-gnu*)
case `$FILECMD conftest.o` in
*x86-64*)
LD="${LD-ld} -m elf32_x86_64"
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_x86_64_fbsd"
;;
- x86_64-*linux*)
+ x86_64-*linux*|x86_64-gnu*)
LD="${LD-ld} -m elf_x86_64"
;;
powerpcle-*linux*)
test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
-if test ${lt_cv_path_mainfest_tool+y}
+if test ${lt_cv_path_manifest_tool+y}
then :
printf %s "(cached) " >&6
else case e in #(
- e) lt_cv_path_mainfest_tool=no
+ e) lt_cv_path_manifest_tool=no
echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
$MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
cat conftest.err >&5
if $GREP 'Manifest Tool' conftest.out > /dev/null; then
- lt_cv_path_mainfest_tool=yes
+ lt_cv_path_manifest_tool=yes
fi
rm -f conftest* ;;
esac
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
-printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; }
-if test yes != "$lt_cv_path_mainfest_tool"; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5
+printf "%s\n" "$lt_cv_path_manifest_tool" >&6; }
+if test yes != "$lt_cv_path_manifest_tool"; then
MANIFEST_TOOL=:
fi
enable_win32_dll=yes
case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-cegcc*)
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
set dummy ${ac_tool_prefix}as; ac_word=$2
# PIC is the default for these OSes.
;;
- mingw* | cygwin* | pw32* | os2* | cegcc*)
+ mingw* | windows* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
esac
;;
- mingw* | cygwin* | pw32* | os2* | cegcc*)
+ mingw* | windows* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
lt_prog_compiler_pic='-DDLL_EXPORT'
lt_prog_compiler_pic='-KPIC'
lt_prog_compiler_static='-static'
;;
+ *flang)
+ # Flang compiler.
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
# icc used to be incompatible with GCC.
# ICC 10 doesn't accept -KPIC any more.
icc* | ifort*)
extract_expsyms_cmds=
case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
# FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++ or Intel C++ Compiler.
# we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
with_gnu_ld=yes
;;
- openbsd* | bitrig*)
+ openbsd*)
with_gnu_ld=no
;;
esac
fi
;;
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
# _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
# as there is no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
emximp -o $lib $output_objdir/$libname.def'
- old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
enable_shared_with_static_runtimes=yes
file_list_spec='@'
;;
export_dynamic_flag_spec=-rdynamic
;;
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++ or Intel C++ Compiler.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# Tell ltmain to make .dll files, not .so files.
shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ archive_cmds='$CC -Fe $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
cp "$export_symbols" "$output_objdir/$soname.def";
echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
else
$SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ $CC -Fe $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
*nto* | *qnx*)
;;
- openbsd* | bitrig*)
+ openbsd*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
hardcode_shlibpath_var=no
cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
emximp -o $lib $output_objdir/$libname.def'
- old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
enable_shared_with_static_runtimes=yes
file_list_spec='@'
;;
*) lt_awk_arg='/^libraries:/' ;;
esac
case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+ mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
*) lt_sed_strip_eq='s|=/|/|g' ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
# AWK program above erroneously prepends '/' to C:/dos/paths
# for these hosts.
case $host_os in
- mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
$SED 's|/\([A-Za-z]:\)|\1|g'` ;;
esac
sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
# libtool to hard-code these into programs
;;
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
version_type=windows
shrext_cmds=.dll
need_version=no
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
;;
- mingw* | cegcc*)
+ mingw* | windows* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
library_names_spec='$libname.dll.lib'
case $build_os in
- mingw*)
+ mingw* | windows*)
sys_lib_search_path_spec=
lt_save_ifs=$IFS
IFS=';'
version_type=none # Android doesn't support versioned libraries.
need_lib_prefix=no
need_version=no
- library_names_spec='$libname$release$shared_ext'
+ library_names_spec='$libname$release$shared_ext $libname$shared_ext'
soname_spec='$libname$release$shared_ext'
finish_cmds=
shlibpath_var=LD_LIBRARY_PATH
hardcode_into_libs=yes
dynamic_linker='Android linker'
- # Don't embed -rpath directories since the linker doesn't support them.
- hardcode_libdir_flag_spec='-L$libdir'
+ # -rpath works at least for libraries that are not overridden by
+ # libraries installed in system locations.
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
;;
# This must be glibc/ELF.
# before this can be enabled.
hardcode_into_libs=yes
- # Ideally, we could use ldconfig to report *all* directores which are
+ # Ideally, we could use ldconfig to report *all* directories which are
# searched for libraries, however this is still not possible. Aside from not
# being certain /sbin/ldconfig is available, command
# 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
dynamic_linker='ldqnx.so'
;;
-openbsd* | bitrig*)
+openbsd*)
version_type=sunos
sys_lib_dlsearch_path_spec=/usr/lib
need_lib_prefix=no
lt_cv_dlopen_self=yes
;;
- mingw* | pw32* | cegcc*)
+ mingw* | windows* | pw32* | cegcc*)
lt_cv_dlopen=LoadLibrary
lt_cv_dlopen_libs=
;;
printf "%s\n" "#define PCRE2_EXPORT /**/" >>confdefs.h
fi
+ else
+
+printf "%s\n" "#define PCRE2_EXPORT /**/" >>confdefs.h
+
fi
# Versioning
PCRE2_MAJOR="10"
-PCRE2_MINOR="43"
+PCRE2_MINOR="44"
PCRE2_PRERELEASE=""
-PCRE2_DATE="2024-02-16"
+PCRE2_DATE="2024-06-07"
if test "$PCRE2_MINOR" = "08" -o "$PCRE2_MINOR" = "09"
then
/* end confdefs.h. */
#define SLJIT_CONFIG_AUTO 1
- #include "src/sljit/sljitConfigInternal.h"
+ #include "src/sljit/sljitConfigCPU.h"
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#error unsupported
#endif
-printf "%s\n" "#define MAX_NAME_SIZE 32" >>confdefs.h
+printf "%s\n" "#define MAX_NAME_SIZE 128" >>confdefs.h
# are m4 variables, assigned above.
EXTRA_LIBPCRE2_8_LDFLAGS="$EXTRA_LIBPCRE2_8_LDFLAGS \
- $NO_UNDEFINED -version-info 12:0:12"
+ $NO_UNDEFINED -version-info 13:0:13"
EXTRA_LIBPCRE2_16_LDFLAGS="$EXTRA_LIBPCRE2_16_LDFLAGS \
- $NO_UNDEFINED -version-info 12:0:12"
+ $NO_UNDEFINED -version-info 13:0:13"
EXTRA_LIBPCRE2_32_LDFLAGS="$EXTRA_LIBPCRE2_32_LDFLAGS \
- $NO_UNDEFINED -version-info 12:0:12"
+ $NO_UNDEFINED -version-info 13:0:13"
EXTRA_LIBPCRE2_POSIX_LDFLAGS="$EXTRA_LIBPCRE2_POSIX_LDFLAGS \
$NO_UNDEFINED -version-info 3:5:0"
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by PCRE2 $as_me 10.43, which was
+This file was extended by PCRE2 $as_me 10.44, which was
generated by GNU Autoconf 2.72. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-PCRE2 config.status 10.43
+PCRE2 config.status 10.44
configured by $0, generated by GNU Autoconf 2.72,
with options \\"\$ac_cs_config\\"
# Provide generalized library-building support services.
# Written by Gordon Matzigkeit, 1996
-# Copyright (C) 2014 Free Software Foundation, Inc.
+# Copyright (C) 2024 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# GNU Libtool is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# As a special exception to the GNU General Public License, if you
# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
# DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# "absolute",i.e. impossible to change by setting \$shlibpath_var if the
# library is relocated.
hardcode_direct_absolute=$hardcode_direct_absolute
dnl be defined as -RC2, for example. For real releases, it should be empty.
m4_define(pcre2_major, [10])
-m4_define(pcre2_minor, [43])
+m4_define(pcre2_minor, [44])
m4_define(pcre2_prerelease, [])
-m4_define(pcre2_date, [2024-02-16])
+m4_define(pcre2_date, [2024-06-07])
# Libtool shared library interface versions (current:revision:age)
-m4_define(libpcre2_8_version, [12:0:12])
-m4_define(libpcre2_16_version, [12:0:12])
-m4_define(libpcre2_32_version, [12:0:12])
+m4_define(libpcre2_8_version, [13:0:13])
+m4_define(libpcre2_16_version, [13:0:13])
+m4_define(libpcre2_32_version, [13:0:13])
m4_define(libpcre2_posix_version, [3:5:0])
# NOTE: The CMakeLists.txt file searches for the above variables in the first
CPPFLAGS=-I$srcdir
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#define SLJIT_CONFIG_AUTO 1
- #include "src/sljit/sljitConfigInternal.h"
+ #include "src/sljit/sljitConfigCPU.h"
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#error unsupported
#endif]])], enable_jit=yes, enable_jit=no)
a pattern. It applies to both pcre2_match() and pcre2_dfa_match(). It does
not apply to JIT matching. The value is in kibibytes (units of 1024 bytes).])
-AC_DEFINE([MAX_NAME_SIZE], [32], [
+AC_DEFINE([MAX_NAME_SIZE], [128], [
This limit is parameterized just in case anybody ever wants to
change it. Care must be taken if it is increased, because it guards
against integer overflow caused by enormously large patterns.])
Building PCRE2 on Windows with Visual Studio
Testing with RunTest.bat
Building PCRE2 on native z/OS and z/VM
+ Building PCRE2 under VMS
GENERAL
z/OS file formats. The port provides an API for LE languages such as COBOL and
for the z/OS and z/VM versions of the Rexx languages.
+
+BUILDING PCRE2 UNDER VMS
+
+Alexey Chuphin has contributed some auxiliary files for building PCRE2 under
+OpenVMS. They are in the "vms" directory in the distribution tarball. Please
+read the file called vms/openvms_readme.txt. The pcre2test and pcre2grep
+programs contain some VMS-specific code.
+
===========================
-Last Updated: 15 April 2023
+Last Updated: 16 April 2024
===========================
The PCRE2 APIs
Documentation for PCRE2
- Contributions by users of PCRE2
Building PCRE2 on non-Unix-like systems
Building PCRE2 without using autotools
Building PCRE2 using autotools
src/config.h.generic ) a version of config.h for use in non-"configure"
) environments
+(F) Auxiliary files for building PCRE2 under OpenVMS
+
+ vms/configure.com )
+ vms/openvms_readme.txt ) These files were contributed by a PCRE2 user.
+ vms/pcre2.h_patch )
+ vms/stdint.h )
+
Philip Hazel
Email local part: Philip.Hazel
Email domain: gmail.com
-Last updated: 24 November 2023
+Last updated: 15 April 2024
<tr><td><a href="pcre2_set_match_limit.html">pcre2_set_match_limit</a></td>
<td> Set the match limit</td></tr>
+<tr><td><a href="pcre2_set_max_pattern_compiled_length.html">pcre2_set_max_pattern_compiled_length</a></td>
+ <td> Set the maximum length of a compiled pattern</td></tr>
+
<tr><td><a href="pcre2_set_max_pattern_length.html">pcre2_set_max_pattern_length</a></td>
- <td> Set the maximum length of pattern</td></tr>
+ <td> Set the maximum length of a pattern</td></tr>
<tr><td><a href="pcre2_set_max_varlookbehind.html">pcre2_set_max_varlookbehind</a></td>
<td> Set the maximum match length for a variable-length lookbehind</td></tr>
--- /dev/null
+<html>
+<head>
+<title>pcre2_set_max_pattern_compiled_length specification</title>
+</head>
+<body bgcolor="#FFFFFF" text="#00005A" link="#0066FF" alink="#3399FF" vlink="#2222BB">
+<h1>pcre2_set_max_pattern_compiled_length man page</h1>
+<p>
+Return to the <a href="index.html">PCRE2 index page</a>.
+</p>
+<p>
+This page is part of the PCRE2 HTML documentation. It was generated
+automatically from the original man page. If there is any nonsense in it,
+please consult the man page, in case the conversion went wrong.
+<br>
+<br><b>
+SYNOPSIS
+</b><br>
+<P>
+<b>#include <pcre2.h></b>
+</P>
+<P>
+<b>int pcre2_set_max_pattern_compiled_length(</b>
+<b> pcre2_compile_context *<i>ccontext</i>, PCRE2_SIZE <i>value</i>);</b>
+</P>
+<br><b>
+DESCRIPTION
+</b><br>
+<P>
+This function sets, in a compile context, the maximum size (in bytes) for the
+memory needed to hold the compiled version of a pattern that is compiled with
+this context. The result is always zero. If a pattern that is passed to
+<b>pcre2_compile()</b> with this context needs more memory, an error is
+generated. The default is the largest number that a PCRE2_SIZE variable can
+hold, which is effectively unlimited.
+</P>
+<P>
+There is a complete description of the PCRE2 native API in the
+<a href="pcre2api.html"><b>pcre2api</b></a>
+page and a description of the POSIX API in the
+<a href="pcre2posix.html"><b>pcre2posix</b></a>
+page.
+<p>
+Return to the <a href="index.html">PCRE2 index page</a>.
+</p>
<b> PCRE2_SIZE <i>value</i>);</b>
<br>
<br>
+<b>int pcre2_set_max_pattern_compiled_length(</b>
+<b> pcre2_compile_context *<i>ccontext</i>, PCRE2_SIZE <i>value</i>);</b>
+<br>
+<br>
<b>int pcre2_set_max_varlookbehind(pcre2_compile_contest *<i>ccontext</i>,</b>
<b>" uint32_t <i>value</i>);</b>
<br>
PCRE2_SIZE variable can hold, which is effectively unlimited.
<br>
<br>
+<b>int pcre2_set_max_pattern_compiled_length(</b>
+<b> pcre2_compile_context *<i>ccontext</i>, PCRE2_SIZE <i>value</i>);</b>
+<br>
+<br>
+This sets a maximum size, in bytes, for the memory needed to hold the compiled
+version of a pattern that is compiled with this context. If the pattern needs
+more memory, an error is generated. This facility is provided so that
+applications that accept patterns from external sources can limit the amount of
+memory they use. The default is the largest number that a PCRE2_SIZE variable
+can hold, which is effectively unlimited.
+<br>
+<br>
<b>int pcre2_set_max_varlookbehind(pcre2_compile_contest *<i>ccontext</i>,</b>
<b>" uint32_t <i>value</i>);</b>
<br>
</P>
<br><a name="SEC43" href="#TOC1">REVISION</a><br>
<P>
-Last updated: 27 January 2024
+Last updated: 24 April 2024
<br>
Copyright © 1997-2024 University of Cambridge.
<br>
<a href="README.txt"><b>README</b></a>
contains general information about building with Autotools (some of which is
repeated below), and also has some comments about building on various operating
-systems. There is a lot more information about building PCRE2 without using
+systems. The files in the <b>vms</b> directory support building under OpenVMS.
+There is a lot more information about building PCRE2 without using
Autotools (including information about using <b>CMake</b> and building "by
hand") in the text file called
<a href="NON-AUTOTOOLS-BUILD.txt"><b>NON-AUTOTOOLS-BUILD</b>.</a>
</P>
<br><a name="SEC27" href="#TOC1">REVISION</a><br>
<P>
-Last updated: 24 November 2023
+Last updated: 15 April 2024
<br>
-Copyright © 1997-2023 University of Cambridge.
+Copyright © 1997-2024 University of Cambridge.
<br>
<p>
Return to the <a href="index.html">PCRE2 index page</a>.
you want to use JIT. The support is limited to the following hardware
platforms:
<pre>
- ARM 32-bit (v5, v7, and Thumb2)
+ ARM 32-bit (v7, and Thumb2)
ARM 64-bit
IBM s390x 64 bit
Intel x86 32-bit and 64-bit
</P>
<br><a name="SEC14" href="#TOC1">REVISION</a><br>
<P>
-Last updated: 23 January 2023
+Last updated: 21 February 2024
<br>
-Copyright © 1997-2023 University of Cambridge.
+Copyright © 1997-2024 University of Cambridge.
<br>
<p>
Return to the <a href="index.html">PCRE2 index page</a>.
character; an LVT or T character may be followed only by a T character.
</P>
<P>
-4. Do not end before extending characters or spacing marks or the "zero-width
-joiner" character. Characters with the "mark" property always have the
+4. Do not end before extending characters or spacing marks or the zero-width
+joiner (ZWJ) character. Characters with the "mark" property always have the
"extend" grapheme breaking property.
</P>
<P>
5. Do not end after prepend characters.
</P>
<P>
-6. Do not break within emoji modifier sequences or emoji zwj sequences. That
-is, do not break between characters with the Extended_Pictographic property.
-Extend and ZWJ characters are allowed between the characters.
+6. Do not end within emoji modifier sequences or emoji ZWJ (zero-width
+joiner) sequences. An emoji ZWJ sequence consists of a character with the
+Extended_Pictographic property, optionally followed by one or more characters
+with the Extend property, followed by the ZWJ character, followed by another
+Extended_Pictographic character.
</P>
<P>
7. Do not break within emoji flag sequences. That is, do not break between
</P>
<P>
In PCRE2, a capture group can be named in one of three ways: (?<name>...) or
-(?'name'...) as in Perl, or (?P<name>...) as in Python. Names may be up to 32
+(?'name'...) as in Perl, or (?P<name>...) as in Python. Names may be up to 128
code units long. When PCRE2_UTF is not set, they may contain only ASCII
alphanumeric characters and underscores, but must start with a non-digit. When
PCRE2_UTF is set, the syntax of group names is extended to allow any Unicode
</P>
<br><a name="SEC32" href="#TOC1">REVISION</a><br>
<P>
-Last updated: 19 January 2024
+Last updated: 04 June 2024
<br>
Copyright © 1997-2024 University of Cambridge.
<br>
jitfast use JIT fast path
jitverify verify JIT use
locale=<name> use this locale
- max_pattern_length=<n> set maximum pattern length
+ max_pattern_compiled ) set maximum compiled pattern
+ _length=<n> ) length (bytes)
+ max_pattern_length=<n> set maximum pattern length (code units)
max_varlookbehind=<n> set maximum variable lookbehind length
memory show memory used
newline=<type> set newline type
length of pattern that <b>pcre2_compile()</b> will accept. Breaching the limit
causes a compilation error. The default is the largest number a PCRE2_SIZE
variable can hold (essentially unlimited).
+</P>
+<br><b>
+Limiting the size of a compiled pattern
+</b><br>
+<P>
+The <b>max_pattern_compiled_length</b> modifier sets a limit, in bytes, to the
+amount of memory used by a compiled pattern. Breaching the limit causes a
+compilation error. The default is the largest number a PCRE2_SIZE variable can
+hold (essentially unlimited).
<a name="posixwrapper"></a></P>
<br><b>
Using the POSIX wrapper API
</P>
<br><a name="SEC21" href="#TOC1">REVISION</a><br>
<P>
-Last updated: 27 January 2024
+Last updated: 24 April 2024
<br>
Copyright © 1997-2024 University of Cambridge.
<br>
<tr><td><a href="pcre2_set_match_limit.html">pcre2_set_match_limit</a></td>
<td> Set the match limit</td></tr>
+<tr><td><a href="pcre2_set_max_pattern_compiled_length.html">pcre2_set_max_pattern_compiled_length</a></td>
+ <td> Set the maximum length of a compiled pattern</td></tr>
+
<tr><td><a href="pcre2_set_max_pattern_length.html">pcre2_set_max_pattern_length</a></td>
- <td> Set the maximum length of pattern</td></tr>
+ <td> Set the maximum length of a pattern</td></tr>
<tr><td><a href="pcre2_set_max_varlookbehind.html">pcre2_set_max_varlookbehind</a></td>
<td> Set the maximum match length for a variable-length lookbehind</td></tr>
int pcre2_set_max_pattern_length(pcre2_compile_context *ccontext,
PCRE2_SIZE value);
+ int pcre2_set_max_pattern_compiled_length(
+ pcre2_compile_context *ccontext, PCRE2_SIZE value);
+
int pcre2_set_max_varlookbehind(pcre2_compile_contest *ccontext,
uint32_t value);
largest number that a PCRE2_SIZE variable can hold, which is effec-
tively unlimited.
+ int pcre2_set_max_pattern_compiled_length(
+ pcre2_compile_context *ccontext, PCRE2_SIZE value);
+
+ This sets a maximum size, in bytes, for the memory needed to hold the
+ compiled version of a pattern that is compiled with this context. If
+ the pattern needs more memory, an error is generated. This facility is
+ provided so that applications that accept patterns from external
+ sources can limit the amount of memory they use. The default is the
+ largest number that a PCRE2_SIZE variable can hold, which is effec-
+ tively unlimited.
+
int pcre2_set_max_varlookbehind(pcre2_compile_contest *ccontext,
uint32_t value);
REVISION
- Last updated: 27 January 2024
+ Last updated: 24 April 2024
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.43 27 January 2024 PCRE2API(3)
+PCRE2 10.44 24 April 2024 PCRE2API(3)
------------------------------------------------------------------------------
CMake instead of configure. The text file README contains general in-
formation about building with Autotools (some of which is repeated be-
low), and also has some comments about building on various operating
- systems. There is a lot more information about building PCRE2 without
- using Autotools (including information about using CMake and building
- "by hand") in the text file called NON-AUTOTOOLS-BUILD. You should
- consult this file as well as the README file if you are building in a
- non-Unix-like environment.
+ systems. The files in the vms directory support building under OpenVMS.
+ There is a lot more information about building PCRE2 without using Au-
+ totools (including information about using CMake and building "by
+ hand") in the text file called NON-AUTOTOOLS-BUILD. You should consult
+ this file as well as the README file if you are building in a non-Unix-
+ like environment.
PCRE2 BUILD-TIME OPTIONS
REVISION
- Last updated: 24 November 2023
- Copyright (c) 1997-2023 University of Cambridge.
+ Last updated: 15 April 2024
+ Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.43 24 November PCRE2BUILD(3)
+PCRE2 10.44 15 April 2024 PCRE2BUILD(3)
------------------------------------------------------------------------------
built if you want to use JIT. The support is limited to the following
hardware platforms:
- ARM 32-bit (v5, v7, and Thumb2)
+ ARM 32-bit (v7, and Thumb2)
ARM 64-bit
IBM s390x 64 bit
Intel x86 32-bit and 64-bit
REVISION
- Last updated: 23 January 2023
- Copyright (c) 1997-2023 University of Cambridge.
+ Last updated: 21 February 2024
+ Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.43 23 January 2023 PCRE2JIT(3)
+PCRE2 10.43 21 February 2024 PCRE2JIT(3)
------------------------------------------------------------------------------
be followed by a V or T character; an LVT or T character may be fol-
lowed only by a T character.
- 4. Do not end before extending characters or spacing marks or the
- "zero-width joiner" character. Characters with the "mark" property al-
+ 4. Do not end before extending characters or spacing marks or the zero-
+ width joiner (ZWJ) character. Characters with the "mark" property al-
ways have the "extend" grapheme breaking property.
5. Do not end after prepend characters.
- 6. Do not break within emoji modifier sequences or emoji zwj sequences.
- That is, do not break between characters with the Extended_Pictographic
- property. Extend and ZWJ characters are allowed between the charac-
- ters.
+ 6. Do not end within emoji modifier sequences or emoji ZWJ (zero-width
+ joiner) sequences. An emoji ZWJ sequence consists of a character with
+ the Extended_Pictographic property, optionally followed by one or more
+ characters with the Extend property, followed by the ZWJ character,
+ followed by another Extended_Pictographic character.
7. Do not break within emoji flag sequences. That is, do not break be-
tween regional indicator (RI) characters if there are an odd number of
In PCRE2, a capture group can be named in one of three ways:
(?<name>...) or (?'name'...) as in Perl, or (?P<name>...) as in Python.
- Names may be up to 32 code units long. When PCRE2_UTF is not set, they
- may contain only ASCII alphanumeric characters and underscores, but
+ Names may be up to 128 code units long. When PCRE2_UTF is not set, they
+ may contain only ASCII alphanumeric characters and underscores, but
must start with a non-digit. When PCRE2_UTF is set, the syntax of group
names is extended to allow any Unicode letter or Unicode decimal digit.
In other words, group names must match one of these patterns:
^[_A-Za-z][_A-Za-z0-9]*\z when PCRE2_UTF is not set
^[_\p{L}][_\p{L}\p{Nd}]*\z when PCRE2_UTF is set
- References to capture groups from other parts of the pattern, such as
- backreferences, recursion, and conditions, can all be made by name as
+ References to capture groups from other parts of the pattern, such as
+ backreferences, recursion, and conditions, can all be made by name as
well as by number.
Named capture groups are allocated numbers as well as names, exactly as
- if the names were not present. In both PCRE2 and Perl, capture groups
- are primarily identified by numbers; any names are just aliases for
+ if the names were not present. In both PCRE2 and Perl, capture groups
+ are primarily identified by numbers; any names are just aliases for
these numbers. The PCRE2 API provides function calls for extracting the
- complete name-to-number translation table from a compiled pattern, as
- well as convenience functions for extracting captured substrings by
+ complete name-to-number translation table from a compiled pattern, as
+ well as convenience functions for extracting captured substrings by
name.
- Warning: When more than one capture group has the same number, as de-
+ Warning: When more than one capture group has the same number, as de-
scribed in the previous section, a name given to one of them applies to
- all of them. Perl allows identically numbered groups to have different
+ all of them. Perl allows identically numbered groups to have different
names. Consider this pattern, where there are two capture groups, both
numbered 1:
(?|(?<AA>aa)|(?<BB>bb))
- Perl allows this, with both names AA and BB as aliases of group 1.
+ Perl allows this, with both names AA and BB as aliases of group 1.
Thus, after a successful match, both names yield the same value (either
"aa" or "bb").
- In an attempt to reduce confusion, PCRE2 does not allow the same group
+ In an attempt to reduce confusion, PCRE2 does not allow the same group
number to be associated with more than one name. The example above pro-
- vokes a compile-time error. However, there is still scope for confu-
+ vokes a compile-time error. However, there is still scope for confu-
sion. Consider this pattern:
(?|(?<AA>aa)|(bb))
Although the second group number 1 is not explicitly named, the name AA
- is still an alias for any group 1. Whether the pattern matches "aa" or
+ is still an alias for any group 1. Whether the pattern matches "aa" or
"bb", a reference by name to group AA yields the matched string.
- By default, a name must be unique within a pattern, except that dupli-
+ By default, a name must be unique within a pattern, except that dupli-
cate names are permitted for groups with the same number, for example:
(?|(?<AA>aa)|(?<AA>bb))
NAMES option at compile time, or by the use of (?J) within the pattern,
as described in the section entitled "Internal Option Setting" above.
- Duplicate names can be useful for patterns where only one instance of
- the named capture group can match. Suppose you want to match the name
- of a weekday, either as a 3-letter abbreviation or as the full name,
- and in both cases you want to extract the abbreviation. This pattern
+ Duplicate names can be useful for patterns where only one instance of
+ the named capture group can match. Suppose you want to match the name
+ of a weekday, either as a 3-letter abbreviation or as the full name,
+ and in both cases you want to extract the abbreviation. This pattern
(ignoring the line breaks) does the job:
(?J)
(?<DN>Thu)(?:rsday)?|
(?<DN>Sat)(?:urday)?
- There are five capture groups, but only one is ever set after a match.
- The convenience functions for extracting the data by name returns the
- substring for the first (and in this example, the only) group of that
+ There are five capture groups, but only one is ever set after a match.
+ The convenience functions for extracting the data by name returns the
+ substring for the first (and in this example, the only) group of that
name that matched. This saves searching to find which numbered group it
- was. (An alternative way of solving this problem is to use a "branch
+ was. (An alternative way of solving this problem is to use a "branch
reset" group, as described in the previous section.)
- If you make a backreference to a non-unique named group from elsewhere
- in the pattern, the groups to which the name refers are checked in the
- order in which they appear in the overall pattern. The first one that
- is set is used for the reference. For example, this pattern matches
+ If you make a backreference to a non-unique named group from elsewhere
+ in the pattern, the groups to which the name refers are checked in the
+ order in which they appear in the overall pattern. The first one that
+ is set is used for the reference. For example, this pattern matches
both "foofoo" and "barbar" but not "foobar" or "barfoo":
(?J)(?:(?<n>foo)|(?<n>bar))\k<n>
If you use a named reference in a condition test (see the section about
conditions below), either to check whether a capture group has matched,
or to check for recursion, all groups with the same name are tested. If
- the condition is true for any one of them, the overall condition is
- true. This is the same behaviour as testing by number. For further de-
- tails of the interfaces for handling named capture groups, see the
+ the condition is true for any one of them, the overall condition is
+ true. This is the same behaviour as testing by number. For further de-
+ tails of the interfaces for handling named capture groups, see the
pcre2api documentation.
REPETITION
- Repetition is specified by quantifiers, which may follow any one of
+ Repetition is specified by quantifiers, which may follow any one of
these items:
a literal data character
If a quantifier does not follow a repeatable item, an error occurs. The
general repetition quantifier specifies a minimum and maximum number of
- permitted matches by giving two numbers in curly brackets (braces),
- separated by a comma. The numbers must be less than 65536, and the
+ permitted matches by giving two numbers in curly brackets (braces),
+ separated by a comma. The numbers must be less than 65536, and the
first must be less than or equal to the second. For example,
z{2,4}
- matches "zz", "zzz", or "zzzz". A closing brace on its own is not a
- special character. If the second number is omitted, but the comma is
- present, there is no upper limit; if the second number and the comma
- are both omitted, the quantifier specifies an exact number of required
+ matches "zz", "zzz", or "zzzz". A closing brace on its own is not a
+ special character. If the second number is omitted, but the comma is
+ present, there is no upper limit; if the second number and the comma
+ are both omitted, the quantifier specifies an exact number of required
matches. Thus
[aeiou]{3,}
\d{8}
- matches exactly 8 digits. If the first number is omitted, the lower
+ matches exactly 8 digits. If the first number is omitted, the lower
limit is taken as zero; in this case the upper limit must be present.
X{,4} is interpreted as X{0,4}
- This is a change in behaviour that happened in Perl 5.34.0 and PCRE2
- 10.43. In earlier versions such a sequence was not interpreted as a
+ This is a change in behaviour that happened in Perl 5.34.0 and PCRE2
+ 10.43. In earlier versions such a sequence was not interpreted as a
quantifier. Other regular expression engines may behave either way.
- If the characters that follow an opening brace do not match the syntax
+ If the characters that follow an opening brace do not match the syntax
of a quantifier, the brace is taken as a literal character. In particu-
lar, this means that {,} is a literal string of three characters.
Note that not every opening brace is potentially the start of a quanti-
- fier because braces are used in other items such as \N{U+345} or
+ fier because braces are used in other items such as \N{U+345} or
\k{name}.
In UTF modes, quantifiers apply to characters rather than to individual
- code units. Thus, for example, \x{100}{2} matches two characters, each
+ code units. Thus, for example, \x{100}{2} matches two characters, each
of which is represented by a two-byte sequence in a UTF-8 string. Simi-
- larly, \X{3} matches three Unicode extended grapheme clusters, each of
- which may be several code units long (and they may be of different
+ larly, \X{3} matches three Unicode extended grapheme clusters, each of
+ which may be several code units long (and they may be of different
lengths).
The quantifier {0} is permitted, causing the expression to behave as if
the previous item and the quantifier were not present. This may be use-
- ful for capture groups that are referenced as subroutines from else-
- where in the pattern (but see also the section entitled "Defining cap-
+ ful for capture groups that are referenced as subroutines from else-
+ where in the pattern (but see also the section entitled "Defining cap-
ture groups for use by reference only" below). Except for parenthesized
- groups, items that have a {0} quantifier are omitted from the compiled
+ groups, items that have a {0} quantifier are omitted from the compiled
pattern.
- For convenience, the three most common quantifiers have single-charac-
+ For convenience, the three most common quantifiers have single-charac-
ter abbreviations:
* is equivalent to {0,}
+ is equivalent to {1,}
? is equivalent to {0,1}
- It is possible to construct infinite loops by following a group that
- can match no characters with a quantifier that has no upper limit, for
+ It is possible to construct infinite loops by following a group that
+ can match no characters with a quantifier that has no upper limit, for
example:
(a?)*
- Earlier versions of Perl and PCRE1 used to give an error at compile
+ Earlier versions of Perl and PCRE1 used to give an error at compile
time for such patterns. However, because there are cases where this can
be useful, such patterns are now accepted, but whenever an iteration of
- such a group matches no characters, matching moves on to the next item
- in the pattern instead of repeatedly matching an empty string. This
- does not prevent backtracking into any of the iterations if a subse-
+ such a group matches no characters, matching moves on to the next item
+ in the pattern instead of repeatedly matching an empty string. This
+ does not prevent backtracking into any of the iterations if a subse-
quent item fails to match.
- By default, quantifiers are "greedy", that is, they match as much as
- possible (up to the maximum number of permitted repetitions), without
- causing the rest of the pattern to fail. The classic example of where
+ By default, quantifiers are "greedy", that is, they match as much as
+ possible (up to the maximum number of permitted repetitions), without
+ causing the rest of the pattern to fail. The classic example of where
this gives problems is in trying to match comments in C programs. These
- appear between /* and */ and within the comment, individual * and /
- characters may appear. An attempt to match C comments by applying the
+ appear between /* and */ and within the comment, individual * and /
+ characters may appear. An attempt to match C comments by applying the
pattern
/\*.*\*/
/* first comment */ not comment /* second comment */
- fails, because it matches the entire string owing to the greediness of
- the .* item. However, if a quantifier is followed by a question mark,
+ fails, because it matches the entire string owing to the greediness of
+ the .* item. However, if a quantifier is followed by a question mark,
it ceases to be greedy, and instead matches the minimum number of times
possible, so the pattern
/\*.*?\*/
- does the right thing with C comments. The meaning of the various quan-
+ does the right thing with C comments. The meaning of the various quan-
tifiers is not otherwise changed, just the preferred number of matches.
- Do not confuse this use of question mark with its use as a quantifier
- in its own right. Because it has two uses, it can sometimes appear
+ Do not confuse this use of question mark with its use as a quantifier
+ in its own right. Because it has two uses, it can sometimes appear
doubled, as in
\d??\d
only way the rest of the pattern matches.
If the PCRE2_UNGREEDY option is set (an option that is not available in
- Perl), the quantifiers are not greedy by default, but individual ones
- can be made greedy by following them with a question mark. In other
+ Perl), the quantifiers are not greedy by default, but individual ones
+ can be made greedy by following them with a question mark. In other
words, it inverts the default behaviour.
- When a parenthesized group is quantified with a minimum repeat count
- that is greater than 1 or with a limited maximum, more memory is re-
+ When a parenthesized group is quantified with a minimum repeat count
+ that is greater than 1 or with a limited maximum, more memory is re-
quired for the compiled pattern, in proportion to the size of the mini-
mum or maximum.
- If a pattern starts with .* or .{0,} and the PCRE2_DOTALL option
- (equivalent to Perl's /s) is set, thus allowing the dot to match new-
- lines, the pattern is implicitly anchored, because whatever follows
- will be tried against every character position in the subject string,
- so there is no point in retrying the overall match at any position af-
- ter the first. PCRE2 normally treats such a pattern as though it were
+ If a pattern starts with .* or .{0,} and the PCRE2_DOTALL option
+ (equivalent to Perl's /s) is set, thus allowing the dot to match new-
+ lines, the pattern is implicitly anchored, because whatever follows
+ will be tried against every character position in the subject string,
+ so there is no point in retrying the overall match at any position af-
+ ter the first. PCRE2 normally treats such a pattern as though it were
preceded by \A.
- In cases where it is known that the subject string contains no new-
- lines, it is worth setting PCRE2_DOTALL in order to obtain this opti-
+ In cases where it is known that the subject string contains no new-
+ lines, it is worth setting PCRE2_DOTALL in order to obtain this opti-
mization, or alternatively, using ^ to indicate anchoring explicitly.
- However, there are some cases where the optimization cannot be used.
- When .* is inside capturing parentheses that are the subject of a
- backreference elsewhere in the pattern, a match at the start may fail
+ However, there are some cases where the optimization cannot be used.
+ When .* is inside capturing parentheses that are the subject of a
+ backreference elsewhere in the pattern, a match at the start may fail
where a later one succeeds. Consider, for example:
(.*)abc\1
- If the subject is "xyz123abc123" the match point is the fourth charac-
+ If the subject is "xyz123abc123" the match point is the fourth charac-
ter. For this reason, such a pattern is not implicitly anchored.
- Another case where implicit anchoring is not applied is when the lead-
- ing .* is inside an atomic group. Once again, a match at the start may
+ Another case where implicit anchoring is not applied is when the lead-
+ ing .* is inside an atomic group. Once again, a match at the start may
fail where a later one succeeds. Consider this pattern:
(?>.*?a)b
- It matches "ab" in the subject "aab". The use of the backtracking con-
- trol verbs (*PRUNE) and (*SKIP) also disable this optimization, and
+ It matches "ab" in the subject "aab". The use of the backtracking con-
+ trol verbs (*PRUNE) and (*SKIP) also disable this optimization, and
there is an option, PCRE2_NO_DOTSTAR_ANCHOR, to do so explicitly.
- When a capture group is repeated, the value captured is the substring
+ When a capture group is repeated, the value captured is the substring
that matched the final iteration. For example, after
(tweedle[dume]{3}\s*)+
has matched "tweedledum tweedledee" the value of the captured substring
- is "tweedledee". However, if there are nested capture groups, the cor-
- responding captured values may have been set in previous iterations.
+ is "tweedledee". However, if there are nested capture groups, the cor-
+ responding captured values may have been set in previous iterations.
For example, after
(a|(b))+
ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS
- With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy")
- repetition, failure of what follows normally causes the repeated item
- to be re-evaluated to see if a different number of repeats allows the
- rest of the pattern to match. Sometimes it is useful to prevent this,
- either to change the nature of the match, or to cause it fail earlier
- than it otherwise might, when the author of the pattern knows there is
+ With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy")
+ repetition, failure of what follows normally causes the repeated item
+ to be re-evaluated to see if a different number of repeats allows the
+ rest of the pattern to match. Sometimes it is useful to prevent this,
+ either to change the nature of the match, or to cause it fail earlier
+ than it otherwise might, when the author of the pattern knows there is
no point in carrying on.
- Consider, for example, the pattern \d+foo when applied to the subject
+ Consider, for example, the pattern \d+foo when applied to the subject
line
123456bar
After matching all 6 digits and then failing to match "foo", the normal
- action of the matcher is to try again with only 5 digits matching the
- \d+ item, and then with 4, and so on, before ultimately failing.
- "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides
+ action of the matcher is to try again with only 5 digits matching the
+ \d+ item, and then with 4, and so on, before ultimately failing.
+ "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides
the means for specifying that once a group has matched, it is not to be
re-evaluated in this way.
- If we use atomic grouping for the previous example, the matcher gives
- up immediately on failing to match "foo" the first time. The notation
+ If we use atomic grouping for the previous example, the matcher gives
+ up immediately on failing to match "foo" the first time. The notation
is a kind of special parenthesis, starting with (?> as in this example:
(?>\d+)foo
- Perl 5.28 introduced an experimental alphabetic form starting with (*
+ Perl 5.28 introduced an experimental alphabetic form starting with (*
which may be easier to remember:
(*atomic:\d+)foo
- This kind of parenthesized group "locks up" the part of the pattern it
+ This kind of parenthesized group "locks up" the part of the pattern it
contains once it has matched, and a failure further into the pattern is
- prevented from backtracking into it. Backtracking past it to previous
+ prevented from backtracking into it. Backtracking past it to previous
items, however, works as normal.
An alternative description is that a group of this type matches exactly
- the string of characters that an identical standalone pattern would
+ the string of characters that an identical standalone pattern would
match, if anchored at the current point in the subject string.
- Atomic groups are not capture groups. Simple cases such as the above
- example can be thought of as a maximizing repeat that must swallow
- everything it can. So, while both \d+ and \d+? are prepared to adjust
- the number of digits they match in order to make the rest of the pat-
+ Atomic groups are not capture groups. Simple cases such as the above
+ example can be thought of as a maximizing repeat that must swallow
+ everything it can. So, while both \d+ and \d+? are prepared to adjust
+ the number of digits they match in order to make the rest of the pat-
tern match, (?>\d+) can only match an entire sequence of digits.
- Atomic groups in general can of course contain arbitrarily complicated
+ Atomic groups in general can of course contain arbitrarily complicated
expressions, and can be nested. However, when the contents of an atomic
- group is just a single repeated item, as in the example above, a sim-
- pler notation, called a "possessive quantifier" can be used. This con-
- sists of an additional + character following a quantifier. Using this
+ group is just a single repeated item, as in the example above, a sim-
+ pler notation, called a "possessive quantifier" can be used. This con-
+ sists of an additional + character following a quantifier. Using this
notation, the previous example can be rewritten as
\d++foo
(abc|xyz){2,3}+
- Possessive quantifiers are always greedy; the setting of the PCRE2_UN-
- GREEDY option is ignored. They are a convenient notation for the sim-
- pler forms of atomic group. However, there is no difference in the
- meaning of a possessive quantifier and the equivalent atomic group,
- though there may be a performance difference; possessive quantifiers
+ Possessive quantifiers are always greedy; the setting of the PCRE2_UN-
+ GREEDY option is ignored. They are a convenient notation for the sim-
+ pler forms of atomic group. However, there is no difference in the
+ meaning of a possessive quantifier and the equivalent atomic group,
+ though there may be a performance difference; possessive quantifiers
should be slightly faster.
- The possessive quantifier syntax is an extension to the Perl 5.8 syn-
- tax. Jeffrey Friedl originated the idea (and the name) in the first
+ The possessive quantifier syntax is an extension to the Perl 5.8 syn-
+ tax. Jeffrey Friedl originated the idea (and the name) in the first
edition of his book. Mike McCloskey liked it, so implemented it when he
- built Sun's Java package, and PCRE1 copied it from there. It found its
+ built Sun's Java package, and PCRE1 copied it from there. It found its
way into Perl at release 5.10.
- PCRE2 has an optimization that automatically "possessifies" certain
- simple pattern constructs. For example, the sequence A+B is treated as
- A++B because there is no point in backtracking into a sequence of A's
+ PCRE2 has an optimization that automatically "possessifies" certain
+ simple pattern constructs. For example, the sequence A+B is treated as
+ A++B because there is no point in backtracking into a sequence of A's
when B must follow. This feature can be disabled by the PCRE2_NO_AUTO-
POSSESS option, or starting the pattern with (*NO_AUTO_POSSESS).
When a pattern contains an unlimited repeat inside a group that can it-
- self be repeated an unlimited number of times, the use of an atomic
- group is the only way to avoid some failing matches taking a very long
+ self be repeated an unlimited number of times, the use of an atomic
+ group is the only way to avoid some failing matches taking a very long
time indeed. The pattern
(\D+|<\d+>)*[!?]
- matches an unlimited number of substrings that either consist of non-
- digits, or digits enclosed in <>, followed by either ! or ?. When it
+ matches an unlimited number of substrings that either consist of non-
+ digits, or digits enclosed in <>, followed by either ! or ?. When it
matches, it runs quickly. However, if it is applied to
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- it takes a long time before reporting failure. This is because the
- string can be divided between the internal \D+ repeat and the external
- * repeat in a large number of ways, and all have to be tried. (The ex-
+ it takes a long time before reporting failure. This is because the
+ string can be divided between the internal \D+ repeat and the external
+ * repeat in a large number of ways, and all have to be tried. (The ex-
ample uses [!?] rather than a single character at the end, because both
PCRE2 and Perl have an optimization that allows for fast failure when a
- single character is used. They remember the last single character that
- is required for a match, and fail early if it is not present in the
- string.) If the pattern is changed so that it uses an atomic group,
+ single character is used. They remember the last single character that
+ is required for a match, and fail early if it is not present in the
+ string.) If the pattern is changed so that it uses an atomic group,
like this:
((?>\D+)|<\d+>)*[!?]
BACKREFERENCES
Outside a character class, a backslash followed by a digit greater than
- 0 (and possibly further digits) is a backreference to a capture group
+ 0 (and possibly further digits) is a backreference to a capture group
earlier (that is, to its left) in the pattern, provided there have been
that many previous capture groups.
- However, if the decimal number following the backslash is less than 8,
- it is always taken as a backreference, and causes an error only if
- there are not that many capture groups in the entire pattern. In other
+ However, if the decimal number following the backslash is less than 8,
+ it is always taken as a backreference, and causes an error only if
+ there are not that many capture groups in the entire pattern. In other
words, the group that is referenced need not be to the left of the ref-
- erence for numbers less than 8. A "forward backreference" of this type
+ erence for numbers less than 8. A "forward backreference" of this type
can make sense when a repetition is involved and the group to the right
has participated in an earlier iteration.
- It is not possible to have a numerical "forward backreference" to a
- group whose number is 8 or more using this syntax because a sequence
- such as \50 is interpreted as a character defined in octal. See the
+ It is not possible to have a numerical "forward backreference" to a
+ group whose number is 8 or more using this syntax because a sequence
+ such as \50 is interpreted as a character defined in octal. See the
subsection entitled "Non-printing characters" above for further details
- of the handling of digits following a backslash. Other forms of back-
- referencing do not suffer from this restriction. In particular, there
+ of the handling of digits following a backslash. Other forms of back-
+ referencing do not suffer from this restriction. In particular, there
is no problem when named capture groups are used (see below).
- Another way of avoiding the ambiguity inherent in the use of digits
- following a backslash is to use the \g escape sequence. This escape
+ Another way of avoiding the ambiguity inherent in the use of digits
+ following a backslash is to use the \g escape sequence. This escape
must be followed by a signed or unsigned number, optionally enclosed in
braces. These examples are all identical:
(ring), \g1
(ring), \g{1}
- An unsigned number specifies an absolute reference without the ambigu-
+ An unsigned number specifies an absolute reference without the ambigu-
ity that is present in the older syntax. It is also useful when literal
- digits follow the reference. A signed number is a relative reference.
+ digits follow the reference. A signed number is a relative reference.
Consider this example:
(abc(def)ghi)\g{-1}
The sequence \g{-1} is a reference to the capture group whose number is
- one less than the number of the next group to be started, so in this
- example (where the next group would be numbered 3) is it equivalent to
- \2, and \g{-2} would be equivalent to \1. Note that if this construct
- is inside a capture group, that group is included in the count, so in
+ one less than the number of the next group to be started, so in this
+ example (where the next group would be numbered 3) is it equivalent to
+ \2, and \g{-2} would be equivalent to \1. Note that if this construct
+ is inside a capture group, that group is included in the count, so in
this example \g{-2} also refers to group 1:
(A)(\g{-2}B)
- The use of relative references can be helpful in long patterns, and
- also in patterns that are created by joining together fragments that
+ The use of relative references can be helpful in long patterns, and
+ also in patterns that are created by joining together fragments that
contain references within themselves.
- The sequence \g{+1} is a reference to the next capture group that is
- started after this item, and \g{+2} refers to the one after that, and
- so on. This kind of forward reference can be useful in patterns that
+ The sequence \g{+1} is a reference to the next capture group that is
+ started after this item, and \g{+2} refers to the one after that, and
+ so on. This kind of forward reference can be useful in patterns that
repeat. Perl does not support the use of + in this way.
- A backreference matches whatever actually most recently matched the
- capture group in the current subject string, rather than anything at
+ A backreference matches whatever actually most recently matched the
+ capture group in the current subject string, rather than anything at
all that matches the group (see "Groups as subroutines" below for a way
of doing that). So the pattern
(sens|respons)e and \1ibility
- matches "sense and sensibility" and "response and responsibility", but
- not "sense and responsibility". If caseful matching is in force at the
- time of the backreference, the case of letters is relevant. For exam-
+ matches "sense and sensibility" and "response and responsibility", but
+ not "sense and responsibility". If caseful matching is in force at the
+ time of the backreference, the case of letters is relevant. For exam-
ple,
((?i)rah)\s+\1
- matches "rah rah" and "RAH RAH", but not "RAH rah", even though the
+ matches "rah rah" and "RAH RAH", but not "RAH rah", even though the
original capture group is matched caselessly.
- There are several different ways of writing backreferences to named
- capture groups. The .NET syntax is \k{name}, the Python syntax is
- (?=name), and the original Perl syntax is \k<name> or \k'name'. All of
- these are now supported by both Perl and PCRE2. Perl 5.10's unified
- backreference syntax, in which \g can be used for both numeric and
- named references, is also supported by PCRE2. We could rewrite the
+ There are several different ways of writing backreferences to named
+ capture groups. The .NET syntax is \k{name}, the Python syntax is
+ (?=name), and the original Perl syntax is \k<name> or \k'name'. All of
+ these are now supported by both Perl and PCRE2. Perl 5.10's unified
+ backreference syntax, in which \g can be used for both numeric and
+ named references, is also supported by PCRE2. We could rewrite the
above example in any of the following ways:
(?<p1>(?i)rah)\s+\k<p1>
(?P<p1>(?i)rah)\s+(?P=p1)
(?<p1>(?i)rah)\s+\g{p1}
- A capture group that is referenced by name may appear in the pattern
+ A capture group that is referenced by name may appear in the pattern
before or after the reference.
- There may be more than one backreference to the same group. If a group
- has not actually been used in a particular match, backreferences to it
+ There may be more than one backreference to the same group. If a group
+ has not actually been used in a particular match, backreferences to it
always fail by default. For example, the pattern
(a|(bc))\2
- always fails if it starts to match "a" rather than "bc". However, if
+ always fails if it starts to match "a" rather than "bc". However, if
the PCRE2_MATCH_UNSET_BACKREF option is set at compile time, a backref-
erence to an unset value matches an empty string.
- Because there may be many capture groups in a pattern, all digits fol-
- lowing a backslash are taken as part of a potential backreference num-
- ber. If the pattern continues with a digit character, some delimiter
- must be used to terminate the backreference. If the PCRE2_EXTENDED or
- PCRE2_EXTENDED_MORE option is set, this can be white space. Otherwise,
+ Because there may be many capture groups in a pattern, all digits fol-
+ lowing a backslash are taken as part of a potential backreference num-
+ ber. If the pattern continues with a digit character, some delimiter
+ must be used to terminate the backreference. If the PCRE2_EXTENDED or
+ PCRE2_EXTENDED_MORE option is set, this can be white space. Otherwise,
the \g{} syntax or an empty comment (see "Comments" below) can be used.
Recursive backreferences
- A backreference that occurs inside the group to which it refers fails
- when the group is first used, so, for example, (a\1) never matches.
- However, such references can be useful inside repeated groups. For ex-
+ A backreference that occurs inside the group to which it refers fails
+ when the group is first used, so, for example, (a\1) never matches.
+ However, such references can be useful inside repeated groups. For ex-
ample, the pattern
(a|b\1)+
matches any number of "a"s and also "aba", "ababbaa" etc. At each iter-
ation of the group, the backreference matches the character string cor-
- responding to the previous iteration. In order for this to work, the
- pattern must be such that the first iteration does not need to match
- the backreference. This can be done using alternation, as in the exam-
+ responding to the previous iteration. In order for this to work, the
+ pattern must be such that the first iteration does not need to match
+ the backreference. This can be done using alternation, as in the exam-
ple above, or by a quantifier with a minimum of zero.
For versions of PCRE2 less than 10.25, backreferences of this type used
- to cause the group that they reference to be treated as an atomic
- group. This restriction no longer applies, and backtracking into such
+ to cause the group that they reference to be treated as an atomic
+ group. This restriction no longer applies, and backtracking into such
groups can occur as normal.
ASSERTIONS
- An assertion is a test on the characters following or preceding the
+ An assertion is a test on the characters following or preceding the
current matching point that does not consume any characters. The simple
- assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are described
+ assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are described
above.
- More complicated assertions are coded as parenthesized groups. There
- are two kinds: those that look ahead of the current position in the
- subject string, and those that look behind it, and in each case an as-
- sertion may be positive (must match for the assertion to be true) or
- negative (must not match for the assertion to be true). An assertion
+ More complicated assertions are coded as parenthesized groups. There
+ are two kinds: those that look ahead of the current position in the
+ subject string, and those that look behind it, and in each case an as-
+ sertion may be positive (must match for the assertion to be true) or
+ negative (must not match for the assertion to be true). An assertion
group is matched in the normal way, and if it is true, matching contin-
- ues after it, but with the matching position in the subject string re-
+ ues after it, but with the matching position in the subject string re-
set to what it was before the assertion was processed.
- The Perl-compatible lookaround assertions are atomic. If an assertion
- is true, but there is a subsequent matching failure, there is no back-
- tracking into the assertion. However, there are some cases where non-
- atomic assertions can be useful. PCRE2 has some support for these, de-
+ The Perl-compatible lookaround assertions are atomic. If an assertion
+ is true, but there is a subsequent matching failure, there is no back-
+ tracking into the assertion. However, there are some cases where non-
+ atomic assertions can be useful. PCRE2 has some support for these, de-
scribed in the section entitled "Non-atomic assertions" below, but they
are not Perl-compatible.
- A lookaround assertion may appear as the condition in a conditional
- group (see below). In this case, the result of matching the assertion
+ A lookaround assertion may appear as the condition in a conditional
+ group (see below). In this case, the result of matching the assertion
determines which branch of the condition is followed.
- Assertion groups are not capture groups. If an assertion contains cap-
- ture groups within it, these are counted for the purposes of numbering
- the capture groups in the whole pattern. Within each branch of an as-
- sertion, locally captured substrings may be referenced in the usual
- way. For example, a sequence such as (.)\g{-1} can be used to check
+ Assertion groups are not capture groups. If an assertion contains cap-
+ ture groups within it, these are counted for the purposes of numbering
+ the capture groups in the whole pattern. Within each branch of an as-
+ sertion, locally captured substrings may be referenced in the usual
+ way. For example, a sequence such as (.)\g{-1} can be used to check
that two adjacent characters are the same.
- When a branch within an assertion fails to match, any substrings that
- were captured are discarded (as happens with any pattern branch that
- fails to match). A negative assertion is true only when all its
+ When a branch within an assertion fails to match, any substrings that
+ were captured are discarded (as happens with any pattern branch that
+ fails to match). A negative assertion is true only when all its
branches fail to match; this means that no captured substrings are ever
- retained after a successful negative assertion. When an assertion con-
+ retained after a successful negative assertion. When an assertion con-
tains a matching branch, what happens depends on the type of assertion.
- For a positive assertion, internally captured substrings in the suc-
- cessful branch are retained, and matching continues with the next pat-
- tern item after the assertion. For a negative assertion, a matching
- branch means that the assertion is not true. If such an assertion is
- being used as a condition in a conditional group (see below), captured
- substrings are retained, because matching continues with the "no"
+ For a positive assertion, internally captured substrings in the suc-
+ cessful branch are retained, and matching continues with the next pat-
+ tern item after the assertion. For a negative assertion, a matching
+ branch means that the assertion is not true. If such an assertion is
+ being used as a condition in a conditional group (see below), captured
+ substrings are retained, because matching continues with the "no"
branch of the condition. For other failing negative assertions, control
passes to the previous backtracking point, thus discarding any captured
strings within the assertion.
- Most assertion groups may be repeated; though it makes no sense to as-
+ Most assertion groups may be repeated; though it makes no sense to as-
sert the same thing several times, the side effect of capturing in pos-
itive assertions may occasionally be useful. However, an assertion that
- forms the condition for a conditional group may not be quantified.
- PCRE2 used to restrict the repetition of assertions, but from release
- 10.35 the only restriction is that an unlimited maximum repetition is
- changed to be one more than the minimum. For example, {3,} is treated
+ forms the condition for a conditional group may not be quantified.
+ PCRE2 used to restrict the repetition of assertions, but from release
+ 10.35 the only restriction is that an unlimited maximum repetition is
+ changed to be one more than the minimum. For example, {3,} is treated
as {3,4}.
Alphabetic assertion names
- Traditionally, symbolic sequences such as (?= and (?<= have been used
- to specify lookaround assertions. Perl 5.28 introduced some experimen-
+ Traditionally, symbolic sequences such as (?= and (?<= have been used
+ to specify lookaround assertions. Perl 5.28 introduced some experimen-
tal alphabetic alternatives which might be easier to remember. They all
- start with (* instead of (? and must be written using lower case let-
+ start with (* instead of (? and must be written using lower case let-
ters. PCRE2 supports the following synonyms:
(*positive_lookahead: or (*pla: is the same as (?=
(*positive_lookbehind: or (*plb: is the same as (?<=
(*negative_lookbehind: or (*nlb: is the same as (?<!
- For example, (*pla:foo) is the same assertion as (?=foo). In the fol-
- lowing sections, the various assertions are described using the origi-
+ For example, (*pla:foo) is the same assertion as (?=foo). In the fol-
+ lowing sections, the various assertions are described using the origi-
nal symbolic forms.
Lookahead assertions
\w+(?=;)
- matches a word followed by a semicolon, but does not include the semi-
+ matches a word followed by a semicolon, but does not include the semi-
colon in the match, and
foo(?!bar)
- matches any occurrence of "foo" that is not followed by "bar". Note
+ matches any occurrence of "foo" that is not followed by "bar". Note
that the apparently similar pattern
(?!foo)bar
- does not find an occurrence of "bar" that is preceded by something
- other than "foo"; it finds any occurrence of "bar" whatsoever, because
+ does not find an occurrence of "bar" that is preceded by something
+ other than "foo"; it finds any occurrence of "bar" whatsoever, because
the assertion (?!foo) is always true when the next three characters are
"bar". A lookbehind assertion is needed to achieve the other effect.
If you want to force a matching failure at some point in a pattern, the
- most convenient way to do it is with (?!) because an empty string al-
- ways matches, so an assertion that requires there not to be an empty
+ most convenient way to do it is with (?!) because an empty string al-
+ ways matches, so an assertion that requires there not to be an empty
string must always fail. The backtracking control verb (*FAIL) or (*F)
is a synonym for (?!).
Lookbehind assertions
- Lookbehind assertions start with (?<= for positive assertions and (?<!
+ Lookbehind assertions start with (?<= for positive assertions and (?<!
for negative assertions. For example,
(?<!foo)bar
- does find an occurrence of "bar" that is not preceded by "foo". The
- contents of a lookbehind assertion are restricted such that there must
- be a known maximum to the lengths of all the strings it matches. There
+ does find an occurrence of "bar" that is not preceded by "foo". The
+ contents of a lookbehind assertion are restricted such that there must
+ be a known maximum to the lengths of all the strings it matches. There
are two cases:
If every top-level alternative matches a fixed length, for example
(?<=colour|color)
- there is a limit of 65535 characters to the lengths, which do not have
- to be the same, as this example demonstrates. This is the only kind of
- lookbehind supported by PCRE2 versions earlier than 10.43 and by the
+ there is a limit of 65535 characters to the lengths, which do not have
+ to be the same, as this example demonstrates. This is the only kind of
+ lookbehind supported by PCRE2 versions earlier than 10.43 and by the
alternative matching function pcre2_dfa_match().
- In PCRE2 10.43 and later, pcre2_match() supports lookbehind assertions
- in which one or more top-level alternatives can match more than one
+ In PCRE2 10.43 and later, pcre2_match() supports lookbehind assertions
+ in which one or more top-level alternatives can match more than one
string length, for example
(?<=colou?r)
The maximum matching length for any branch of the lookbehind is limited
- to a value set by the calling program (default 255 characters). Unlim-
- ited repetition (for example \d*) is not supported. In some cases, the
- escape sequence \K (see above) can be used instead of a lookbehind as-
- sertion at the start of a pattern to get round the length limit re-
+ to a value set by the calling program (default 255 characters). Unlim-
+ ited repetition (for example \d*) is not supported. In some cases, the
+ escape sequence \K (see above) can be used instead of a lookbehind as-
+ sertion at the start of a pattern to get round the length limit re-
striction.
- In UTF-8 and UTF-16 modes, PCRE2 does not allow the \C escape (which
- matches a single code unit even in a UTF mode) to appear in lookbehind
- assertions, because it makes it impossible to calculate the length of
- the lookbehind. The \X and \R escapes, which can match different num-
+ In UTF-8 and UTF-16 modes, PCRE2 does not allow the \C escape (which
+ matches a single code unit even in a UTF mode) to appear in lookbehind
+ assertions, because it makes it impossible to calculate the length of
+ the lookbehind. The \X and \R escapes, which can match different num-
bers of code units, are never permitted in lookbehinds.
- "Subroutine" calls (see below) such as (?2) or (?&X) are permitted in
- lookbehinds, as long as the called capture group matches a limited-
- length string. However, recursion, that is, a "subroutine" call into a
+ "Subroutine" calls (see below) such as (?2) or (?&X) are permitted in
+ lookbehinds, as long as the called capture group matches a limited-
+ length string. However, recursion, that is, a "subroutine" call into a
group that is already active, is not supported.
- PCRE2 supports backreferences in lookbehinds, but only if certain con-
- ditions are met. The PCRE2_MATCH_UNSET_BACKREF option must not be set,
- there must be no use of (?| in the pattern (it creates duplicate group
+ PCRE2 supports backreferences in lookbehinds, but only if certain con-
+ ditions are met. The PCRE2_MATCH_UNSET_BACKREF option must not be set,
+ there must be no use of (?| in the pattern (it creates duplicate group
numbers), and if the backreference is by name, the name must be unique.
Of course, the referenced group must itself match a limited length sub-
- string. The following pattern matches words containing at least two
+ string. The following pattern matches words containing at least two
characters that begin and end with the same character:
\b(\w)\w++(?<=\1)
- Possessive quantifiers can be used in conjunction with lookbehind as-
- sertions to specify efficient matching at the end of subject strings.
+ Possessive quantifiers can be used in conjunction with lookbehind as-
+ sertions to specify efficient matching at the end of subject strings.
Consider a simple pattern such as
abcd$
- when applied to a long string that does not match. Because matching
- proceeds from left to right, PCRE2 will look for each "a" in the sub-
- ject and then see if what follows matches the rest of the pattern. If
+ when applied to a long string that does not match. Because matching
+ proceeds from left to right, PCRE2 will look for each "a" in the sub-
+ ject and then see if what follows matches the rest of the pattern. If
the pattern is specified as
^.*abcd$
- the initial .* matches the entire string at first, but when this fails
+ the initial .* matches the entire string at first, but when this fails
(because there is no following "a"), it backtracks to match all but the
- last character, then all but the last two characters, and so on. Once
- again the search for "a" covers the entire string, from right to left,
+ last character, then all but the last two characters, and so on. Once
+ again the search for "a" covers the entire string, from right to left,
so we are no better off. However, if the pattern is written as
^.*+(?<=abcd)
there can be no backtracking for the .*+ item because of the possessive
quantifier; it can match only the entire string. The subsequent lookbe-
- hind assertion does a single test on the last four characters. If it
- fails, the match fails immediately. For long strings, this approach
+ hind assertion does a single test on the last four characters. If it
+ fails, the match fails immediately. For long strings, this approach
makes a significant difference to the processing time.
Using multiple assertions
(?<=\d{3})(?<!999)foo
- matches "foo" preceded by three digits that are not "999". Notice that
- each of the assertions is applied independently at the same point in
- the subject string. First there is a check that the previous three
- characters are all digits, and then there is a check that the same
+ matches "foo" preceded by three digits that are not "999". Notice that
+ each of the assertions is applied independently at the same point in
+ the subject string. First there is a check that the previous three
+ characters are all digits, and then there is a check that the same
three characters are not "999". This pattern does not match "foo" pre-
- ceded by six characters, the first of which are digits and the last
- three of which are not "999". For example, it doesn't match "123abc-
+ ceded by six characters, the first of which are digits and the last
+ three of which are not "999". For example, it doesn't match "123abc-
foo". A pattern to do that is
(?<=\d{3}...)(?<!999)foo
- This time the first assertion looks at the preceding six characters,
+ This time the first assertion looks at the preceding six characters,
checking that the first three are digits, and then the second assertion
checks that the preceding three characters are not "999".
(?<=(?<!foo)bar)baz
- matches an occurrence of "baz" that is preceded by "bar" which in turn
+ matches an occurrence of "baz" that is preceded by "bar" which in turn
is not preceded by "foo", while
(?<=\d{3}(?!999)...)foo
- is another pattern that matches "foo" preceded by three digits and any
+ is another pattern that matches "foo" preceded by three digits and any
three characters that are not "999".
NON-ATOMIC ASSERTIONS
- Traditional lookaround assertions are atomic. That is, if an assertion
- is true, but there is a subsequent matching failure, there is no back-
- tracking into the assertion. However, there are some cases where non-
- atomic positive assertions can be useful. PCRE2 provides these using
+ Traditional lookaround assertions are atomic. That is, if an assertion
+ is true, but there is a subsequent matching failure, there is no back-
+ tracking into the assertion. However, there are some cases where non-
+ atomic positive assertions can be useful. PCRE2 provides these using
the following syntax:
(*non_atomic_positive_lookahead: or (*napla: or (?*
(*non_atomic_positive_lookbehind: or (*naplb: or (?<*
- Consider the problem of finding the right-most word in a string that
- also appears earlier in the string, that is, it must appear at least
- twice in total. This pattern returns the required result as captured
+ Consider the problem of finding the right-most word in a string that
+ also appears earlier in the string, that is, it must appear at least
+ twice in total. This pattern returns the required result as captured
substring 1:
^(?x)(*napla: .* \b(\w++)) (?> .*? \b\1\b ){2}
- For a subject such as "word1 word2 word3 word2 word3 word4" the result
- is "word3". How does it work? At the start, ^(?x) anchors the pattern
+ For a subject such as "word1 word2 word3 word2 word3 word4" the result
+ is "word3". How does it work? At the start, ^(?x) anchors the pattern
and sets the "x" option, which causes white space (introduced for read-
- ability) to be ignored. Inside the assertion, the greedy .* at first
+ ability) to be ignored. Inside the assertion, the greedy .* at first
consumes the entire string, but then has to backtrack until the rest of
- the assertion can match a word, which is captured by group 1. In other
- words, when the assertion first succeeds, it captures the right-most
+ the assertion can match a word, which is captured by group 1. In other
+ words, when the assertion first succeeds, it captures the right-most
word in the string.
- The current matching point is then reset to the start of the subject,
- and the rest of the pattern match checks for two occurrences of the
- captured word, using an ungreedy .*? to scan from the left. If this
- succeeds, we are done, but if the last word in the string does not oc-
- cur twice, this part of the pattern fails. If a traditional atomic
- lookahead (?= or (*pla: had been used, the assertion could not be re-
+ The current matching point is then reset to the start of the subject,
+ and the rest of the pattern match checks for two occurrences of the
+ captured word, using an ungreedy .*? to scan from the left. If this
+ succeeds, we are done, but if the last word in the string does not oc-
+ cur twice, this part of the pattern fails. If a traditional atomic
+ lookahead (?= or (*pla: had been used, the assertion could not be re-
entered, and the whole match would fail. The pattern would succeed only
if the very last word in the subject was found twice.
- Using a non-atomic lookahead, however, means that when the last word
- does not occur twice in the string, the lookahead can backtrack and
- find the second-last word, and so on, until either the match succeeds,
+ Using a non-atomic lookahead, however, means that when the last word
+ does not occur twice in the string, the lookahead can backtrack and
+ find the second-last word, and so on, until either the match succeeds,
or all words have been tested.
Two conditions must be met for a non-atomic assertion to be useful: the
- contents of one or more capturing groups must change after a backtrack
- into the assertion, and there must be a backreference to a changed
- group later in the pattern. If this is not the case, the rest of the
- pattern match fails exactly as before because nothing has changed, so
+ contents of one or more capturing groups must change after a backtrack
+ into the assertion, and there must be a backreference to a changed
+ group later in the pattern. If this is not the case, the rest of the
+ pattern match fails exactly as before because nothing has changed, so
using a non-atomic assertion just wastes resources.
- There is one exception to backtracking into a non-atomic assertion. If
- an (*ACCEPT) control verb is triggered, the assertion succeeds atomi-
- cally. That is, a subsequent match failure cannot backtrack into the
+ There is one exception to backtracking into a non-atomic assertion. If
+ an (*ACCEPT) control verb is triggered, the assertion succeeds atomi-
+ cally. That is, a subsequent match failure cannot backtrack into the
assertion.
- Non-atomic assertions are not supported by the alternative matching
+ Non-atomic assertions are not supported by the alternative matching
function pcre2_dfa_match(). They are supported by JIT, but only if they
do not contain any control verbs such as (*ACCEPT). (This may change in
future). Note that assertions that appear as conditions for conditional
SCRIPT RUNS
- In concept, a script run is a sequence of characters that are all from
- the same Unicode script such as Latin or Greek. However, because some
- scripts are commonly used together, and because some diacritical and
- other marks are used with multiple scripts, it is not that simple.
+ In concept, a script run is a sequence of characters that are all from
+ the same Unicode script such as Latin or Greek. However, because some
+ scripts are commonly used together, and because some diacritical and
+ other marks are used with multiple scripts, it is not that simple.
There is a full description of the rules that PCRE2 uses in the section
entitled "Script Runs" in the pcre2unicode documentation.
- If part of a pattern is enclosed between (*script_run: or (*sr: and a
- closing parenthesis, it fails if the sequence of characters that it
- matches are not a script run. After a failure, normal backtracking oc-
- curs. Script runs can be used to detect spoofing attacks using charac-
- ters that look the same, but are from different scripts. The string
- "paypal.com" is an infamous example, where the letters could be a mix-
+ If part of a pattern is enclosed between (*script_run: or (*sr: and a
+ closing parenthesis, it fails if the sequence of characters that it
+ matches are not a script run. After a failure, normal backtracking oc-
+ curs. Script runs can be used to detect spoofing attacks using charac-
+ ters that look the same, but are from different scripts. The string
+ "paypal.com" is an infamous example, where the letters could be a mix-
ture of Latin and Cyrillic. This pattern ensures that the matched char-
acters in a sequence of non-spaces that follow white space are a script
run:
\s+(*sr:\S+)
- To be sure that they are all from the Latin script (for example), a
+ To be sure that they are all from the Latin script (for example), a
lookahead can be used:
\s+(?=\p{Latin})(*sr:\S+)
This works as long as the first character is expected to be a character
- in that script, and not (for example) punctuation, which is allowed
- with any script. If this is not the case, a more creative lookahead is
- needed. For example, if digits, underscore, and dots are permitted at
+ in that script, and not (for example) punctuation, which is allowed
+ with any script. If this is not the case, a more creative lookahead is
+ needed. For example, if digits, underscore, and dots are permitted at
the start:
\s+(?=[0-9_.]*\p{Latin})(*sr:\S+)
- In many cases, backtracking into a script run pattern fragment is not
- desirable. The script run can employ an atomic group to prevent this.
- Because this is a common requirement, a shorthand notation is provided
+ In many cases, backtracking into a script run pattern fragment is not
+ desirable. The script run can employ an atomic group to prevent this.
+ Because this is a common requirement, a shorthand notation is provided
by (*atomic_script_run: or (*asr:
(*asr:...) is the same as (*sr:(?>...))
Note that the atomic group is inside the script run. Putting it outside
would not prevent backtracking into the script run pattern.
- Support for script runs is not available if PCRE2 is compiled without
+ Support for script runs is not available if PCRE2 is compiled without
Unicode support. A compile-time error is given if any of the above con-
- structs is encountered. Script runs are not supported by the alternate
- matching function, pcre2_dfa_match() because they use the same mecha-
+ structs is encountered. Script runs are not supported by the alternate
+ matching function, pcre2_dfa_match() because they use the same mecha-
nism as capturing parentheses.
- Warning: The (*ACCEPT) control verb (see below) should not be used
+ Warning: The (*ACCEPT) control verb (see below) should not be used
within a script run group, because it causes an immediate exit from the
group, bypassing the script run checking.
It is possible to cause the matching process to obey a pattern fragment
conditionally or to choose between two alternative fragments, depending
- on the result of an assertion, or whether a specific capture group has
+ on the result of an assertion, or whether a specific capture group has
already been matched. The two possible forms of conditional group are:
(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)
- If the condition is satisfied, the yes-pattern is used; otherwise the
- no-pattern (if present) is used. An absent no-pattern is equivalent to
- an empty string (it always matches). If there are more than two alter-
- natives in the group, a compile-time error occurs. Each of the two al-
+ If the condition is satisfied, the yes-pattern is used; otherwise the
+ no-pattern (if present) is used. An absent no-pattern is equivalent to
+ an empty string (it always matches). If there are more than two alter-
+ natives in the group, a compile-time error occurs. Each of the two al-
ternatives may itself contain nested groups of any form, including con-
- ditional groups; the restriction to two alternatives applies only at
- the level of the condition itself. This pattern fragment is an example
+ ditional groups; the restriction to two alternatives applies only at
+ the level of the condition itself. This pattern fragment is an example
where the alternatives are complex:
(?(1) (A|B|C) | (D | (?(2)E|F) | E) )
There are five kinds of condition: references to capture groups, refer-
- ences to recursion, two pseudo-conditions called DEFINE and VERSION,
+ ences to recursion, two pseudo-conditions called DEFINE and VERSION,
and assertions.
Checking for a used capture group by number
- If the text between the parentheses consists of a sequence of digits,
- the condition is true if a capture group of that number has previously
- matched. If there is more than one capture group with the same number
- (see the earlier section about duplicate group numbers), the condition
- is true if any of them have matched. An alternative notation, which is
+ If the text between the parentheses consists of a sequence of digits,
+ the condition is true if a capture group of that number has previously
+ matched. If there is more than one capture group with the same number
+ (see the earlier section about duplicate group numbers), the condition
+ is true if any of them have matched. An alternative notation, which is
a PCRE2 extension, not supported by Perl, is to precede the digits with
a plus or minus sign. In this case, the group number is relative rather
- than absolute. The most recently opened capture group (which could be
- enclosing this condition) can be referenced by (?(-1), the next most
+ than absolute. The most recently opened capture group (which could be
+ enclosing this condition) can be referenced by (?(-1), the next most
recent by (?(-2), and so on. Inside loops it can also make sense to re-
- fer to subsequent groups. The next capture group to be opened can be
- referenced as (?(+1), and so on. The value zero in any of these forms
+ fer to subsequent groups. The next capture group to be opened can be
+ referenced as (?(+1), and so on. The value zero in any of these forms
is not used; it provokes a compile-time error.
- Consider the following pattern, which contains non-significant white
- space to make it more readable (assume the PCRE2_EXTENDED option) and
+ Consider the following pattern, which contains non-significant white
+ space to make it more readable (assume the PCRE2_EXTENDED option) and
to divide it into three parts for ease of discussion:
( \( )? [^()]+ (?(1) \) )
- The first part matches an optional opening parenthesis, and if that
+ The first part matches an optional opening parenthesis, and if that
character is present, sets it as the first captured substring. The sec-
- ond part matches one or more characters that are not parentheses. The
- third part is a conditional group that tests whether or not the first
- capture group matched. If it did, that is, if subject started with an
- opening parenthesis, the condition is true, and so the yes-pattern is
- executed and a closing parenthesis is required. Otherwise, since no-
+ ond part matches one or more characters that are not parentheses. The
+ third part is a conditional group that tests whether or not the first
+ capture group matched. If it did, that is, if subject started with an
+ opening parenthesis, the condition is true, and so the yes-pattern is
+ executed and a closing parenthesis is required. Otherwise, since no-
pattern is not present, the conditional group matches nothing. In other
- words, this pattern matches a sequence of non-parentheses, optionally
+ words, this pattern matches a sequence of non-parentheses, optionally
enclosed in parentheses.
- If you were embedding this pattern in a larger one, you could use a
+ If you were embedding this pattern in a larger one, you could use a
relative reference:
...other stuff... ( \( )? [^()]+ (?(-1) \) ) ...
- This makes the fragment independent of the parentheses in the larger
+ This makes the fragment independent of the parentheses in the larger
pattern.
Checking for a used capture group by name
- Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a
- used capture group by name. For compatibility with earlier versions of
- PCRE1, which had this facility before Perl, the syntax (?(name)...) is
- also recognized. Note, however, that undelimited names consisting of
- the letter R followed by digits are ambiguous (see the following sec-
+ Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a
+ used capture group by name. For compatibility with earlier versions of
+ PCRE1, which had this facility before Perl, the syntax (?(name)...) is
+ also recognized. Note, however, that undelimited names consisting of
+ the letter R followed by digits are ambiguous (see the following sec-
tion). Rewriting the above example to use a named group gives this:
(?<OPEN> \( )? [^()]+ (?(<OPEN>) \) )
- If the name used in a condition of this kind is a duplicate, the test
- is applied to all groups of the same name, and is true if any one of
+ If the name used in a condition of this kind is a duplicate, the test
+ is applied to all groups of the same name, and is true if any one of
them has matched.
Checking for pattern recursion
- "Recursion" in this sense refers to any subroutine-like call from one
- part of the pattern to another, whether or not it is actually recur-
- sive. See the sections entitled "Recursive patterns" and "Groups as
+ "Recursion" in this sense refers to any subroutine-like call from one
+ part of the pattern to another, whether or not it is actually recur-
+ sive. See the sections entitled "Recursive patterns" and "Groups as
subroutines" below for details of recursion and subroutine calls.
- If a condition is the string (R), and there is no capture group with
- the name R, the condition is true if matching is currently in a recur-
- sion or subroutine call to the whole pattern or any capture group. If
- digits follow the letter R, and there is no group with that name, the
- condition is true if the most recent call is into a group with the
- given number, which must exist somewhere in the overall pattern. This
+ If a condition is the string (R), and there is no capture group with
+ the name R, the condition is true if matching is currently in a recur-
+ sion or subroutine call to the whole pattern or any capture group. If
+ digits follow the letter R, and there is no group with that name, the
+ condition is true if the most recent call is into a group with the
+ given number, which must exist somewhere in the overall pattern. This
is a contrived example that is equivalent to a+b:
((?(R1)a+|(?1)b))
- However, in both cases, if there is a capture group with a matching
- name, the condition tests for its being set, as described in the sec-
- tion above, instead of testing for recursion. For example, creating a
- group with the name R1 by adding (?<R1>) to the above pattern com-
+ However, in both cases, if there is a capture group with a matching
+ name, the condition tests for its being set, as described in the sec-
+ tion above, instead of testing for recursion. For example, creating a
+ group with the name R1 by adding (?<R1>) to the above pattern com-
pletely changes its meaning.
If a name preceded by ampersand follows the letter R, for example:
(?(R&name)...)
- the condition is true if the most recent recursion is into a group of
+ the condition is true if the most recent recursion is into a group of
that name (which must exist within the pattern).
This condition does not check the entire recursion stack. It tests only
- the current level. If the name used in a condition of this kind is a
- duplicate, the test is applied to all groups of the same name, and is
+ the current level. If the name used in a condition of this kind is a
+ duplicate, the test is applied to all groups of the same name, and is
true if any one of them is the most recent recursion.
At "top level", all these recursion test conditions are false.
Defining capture groups for use by reference only
If the condition is the string (DEFINE), the condition is always false,
- even if there is a group with the name DEFINE. In this case, there may
+ even if there is a group with the name DEFINE. In this case, there may
be only one alternative in the rest of the conditional group. It is al-
- ways skipped if control reaches this point in the pattern; the idea of
- DEFINE is that it can be used to define subroutines that can be refer-
- enced from elsewhere. (The use of subroutines is described below.) For
- example, a pattern to match an IPv4 address such as "192.168.23.245"
+ ways skipped if control reaches this point in the pattern; the idea of
+ DEFINE is that it can be used to define subroutines that can be refer-
+ enced from elsewhere. (The use of subroutines is described below.) For
+ example, a pattern to match an IPv4 address such as "192.168.23.245"
could be written like this (ignore white space and line breaks):
(?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) )
\b (?&byte) (\.(?&byte)){3} \b
- The first part of the pattern is a DEFINE group inside which another
- group named "byte" is defined. This matches an individual component of
- an IPv4 address (a number less than 256). When matching takes place,
- this part of the pattern is skipped because DEFINE acts like a false
- condition. The rest of the pattern uses references to the named group
- to match the four dot-separated components of an IPv4 address, insist-
+ The first part of the pattern is a DEFINE group inside which another
+ group named "byte" is defined. This matches an individual component of
+ an IPv4 address (a number less than 256). When matching takes place,
+ this part of the pattern is skipped because DEFINE acts like a false
+ condition. The rest of the pattern uses references to the named group
+ to match the four dot-separated components of an IPv4 address, insist-
ing on a word boundary at each end.
Checking the PCRE2 version
- Programs that link with a PCRE2 library can check the version by call-
- ing pcre2_config() with appropriate arguments. Users of applications
- that do not have access to the underlying code cannot do this. A spe-
- cial "condition" called VERSION exists to allow such users to discover
+ Programs that link with a PCRE2 library can check the version by call-
+ ing pcre2_config() with appropriate arguments. Users of applications
+ that do not have access to the underlying code cannot do this. A spe-
+ cial "condition" called VERSION exists to allow such users to discover
which version of PCRE2 they are dealing with by using this condition to
- match a string such as "yesno". VERSION must be followed either by "="
+ match a string such as "yesno". VERSION must be followed either by "="
or ">=" and a version number. For example:
(?(VERSION>=10.4)yes|no)
- This pattern matches "yes" if the PCRE2 version is greater or equal to
- 10.4, or "no" otherwise. The fractional part of the version number may
+ This pattern matches "yes" if the PCRE2 version is greater or equal to
+ 10.4, or "no" otherwise. The fractional part of the version number may
not contain more than two digits.
Assertion conditions
- If the condition is not in any of the above formats, it must be a
- parenthesized assertion. This may be a positive or negative lookahead
- or lookbehind assertion. However, it must be a traditional atomic as-
+ If the condition is not in any of the above formats, it must be a
+ parenthesized assertion. This may be a positive or negative lookahead
+ or lookbehind assertion. However, it must be a traditional atomic as-
sertion, not one of the non-atomic assertions.
- Consider this pattern, again containing non-significant white space,
+ Consider this pattern, again containing non-significant white space,
and with the two alternatives on the second line:
(?(?=[^a-z]*[a-z])
\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )
- The condition is a positive lookahead assertion that matches an op-
+ The condition is a positive lookahead assertion that matches an op-
tional sequence of non-letters followed by a letter. In other words, it
tests for the presence of at least one letter in the subject. If a let-
- ter is found, the subject is matched against the first alternative;
- otherwise it is matched against the second. This pattern matches
- strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are
+ ter is found, the subject is matched against the first alternative;
+ otherwise it is matched against the second. This pattern matches
+ strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are
letters and dd are digits.
When an assertion that is a condition contains capture groups, any cap-
- turing that occurs in a matching branch is retained afterwards, for
- both positive and negative assertions, because matching always contin-
- ues after the assertion, whether it succeeds or fails. (Compare non-
- conditional assertions, for which captures are retained only for posi-
+ turing that occurs in a matching branch is retained afterwards, for
+ both positive and negative assertions, because matching always contin-
+ ues after the assertion, whether it succeeds or fails. (Compare non-
+ conditional assertions, for which captures are retained only for posi-
tive assertions that succeed.)
COMMENTS
There are two ways of including comments in patterns that are processed
- by PCRE2. In both cases, the start of the comment must not be in a
- character class, nor in the middle of any other sequence of related
- characters such as (?: or a group name or number. The characters that
+ by PCRE2. In both cases, the start of the comment must not be in a
+ character class, nor in the middle of any other sequence of related
+ characters such as (?: or a group name or number. The characters that
make up a comment play no part in the pattern matching.
- The sequence (?# marks the start of a comment that continues up to the
- next closing parenthesis. Nested parentheses are not permitted. If the
- PCRE2_EXTENDED or PCRE2_EXTENDED_MORE option is set, an unescaped #
- character also introduces a comment, which in this case continues to
- immediately after the next newline character or character sequence in
+ The sequence (?# marks the start of a comment that continues up to the
+ next closing parenthesis. Nested parentheses are not permitted. If the
+ PCRE2_EXTENDED or PCRE2_EXTENDED_MORE option is set, an unescaped #
+ character also introduces a comment, which in this case continues to
+ immediately after the next newline character or character sequence in
the pattern. Which characters are interpreted as newlines is controlled
- by an option passed to the compiling function or by a special sequence
+ by an option passed to the compiling function or by a special sequence
at the start of the pattern, as described in the section entitled "New-
line conventions" above. Note that the end of this type of comment is a
- literal newline sequence in the pattern; escape sequences that happen
+ literal newline sequence in the pattern; escape sequences that happen
to represent a newline do not count. For example, consider this pattern
- when PCRE2_EXTENDED is set, and the default newline convention (a sin-
+ when PCRE2_EXTENDED is set, and the default newline convention (a sin-
gle linefeed character) is in force:
abc #comment \n still comment
- On encountering the # character, pcre2_compile() skips along, looking
- for a newline in the pattern. The sequence \n is still literal at this
- stage, so it does not terminate the comment. Only an actual character
+ On encountering the # character, pcre2_compile() skips along, looking
+ for a newline in the pattern. The sequence \n is still literal at this
+ stage, so it does not terminate the comment. Only an actual character
with the code value 0x0a (the default newline) does so.
RECURSIVE PATTERNS
- Consider the problem of matching a string in parentheses, allowing for
- unlimited nested parentheses. Without the use of recursion, the best
- that can be done is to use a pattern that matches up to some fixed
- depth of nesting. It is not possible to handle an arbitrary nesting
+ Consider the problem of matching a string in parentheses, allowing for
+ unlimited nested parentheses. Without the use of recursion, the best
+ that can be done is to use a pattern that matches up to some fixed
+ depth of nesting. It is not possible to handle an arbitrary nesting
depth.
For some time, Perl has provided a facility that allows regular expres-
- sions to recurse (amongst other things). It does this by interpolating
- Perl code in the expression at run time, and the code can refer to the
+ sions to recurse (amongst other things). It does this by interpolating
+ Perl code in the expression at run time, and the code can refer to the
expression itself. A Perl pattern using code interpolation to solve the
parentheses problem can be created like this:
The (?p{...}) item interpolates Perl code at run time, and in this case
refers recursively to the pattern in which it appears.
- Obviously, PCRE2 cannot support the interpolation of Perl code. In-
- stead, it supports special syntax for recursion of the entire pattern,
+ Obviously, PCRE2 cannot support the interpolation of Perl code. In-
+ stead, it supports special syntax for recursion of the entire pattern,
and also for individual capture group recursion. After its introduction
in PCRE1 and Python, this kind of recursion was subsequently introduced
into Perl at release 5.10.
- A special item that consists of (? followed by a number greater than
- zero and a closing parenthesis is a recursive subroutine call of the
- capture group of the given number, provided that it occurs inside that
- group. (If not, it is a non-recursive subroutine call, which is de-
+ A special item that consists of (? followed by a number greater than
+ zero and a closing parenthesis is a recursive subroutine call of the
+ capture group of the given number, provided that it occurs inside that
+ group. (If not, it is a non-recursive subroutine call, which is de-
scribed in the next section.) The special item (?R) or (?0) is a recur-
sive call of the entire regular expression.
- This PCRE2 pattern solves the nested parentheses problem (assume the
+ This PCRE2 pattern solves the nested parentheses problem (assume the
PCRE2_EXTENDED option is set so that white space is ignored):
\( ( [^()]++ | (?R) )* \)
- First it matches an opening parenthesis. Then it matches any number of
- substrings which can either be a sequence of non-parentheses, or a re-
+ First it matches an opening parenthesis. Then it matches any number of
+ substrings which can either be a sequence of non-parentheses, or a re-
cursive match of the pattern itself (that is, a correctly parenthesized
- substring). Finally there is a closing parenthesis. Note the use of a
- possessive quantifier to avoid backtracking into sequences of non-
+ substring). Finally there is a closing parenthesis. Note the use of a
+ possessive quantifier to avoid backtracking into sequences of non-
parentheses.
- If this were part of a larger pattern, you would not want to recurse
+ If this were part of a larger pattern, you would not want to recurse
the entire pattern, so instead you could use this:
( \( ( [^()]++ | (?1) )* \) )
- We have put the pattern into parentheses, and caused the recursion to
+ We have put the pattern into parentheses, and caused the recursion to
refer to them instead of the whole pattern.
- In a larger pattern, keeping track of parenthesis numbers can be
- tricky. This is made easier by the use of relative references. Instead
+ In a larger pattern, keeping track of parenthesis numbers can be
+ tricky. This is made easier by the use of relative references. Instead
of (?1) in the pattern above you can write (?-2) to refer to the second
- most recently opened parentheses preceding the recursion. In other
- words, a negative number counts capturing parentheses leftwards from
+ most recently opened parentheses preceding the recursion. In other
+ words, a negative number counts capturing parentheses leftwards from
the point at which it is encountered.
- Be aware however, that if duplicate capture group numbers are in use,
- relative references refer to the earliest group with the appropriate
+ Be aware however, that if duplicate capture group numbers are in use,
+ relative references refer to the earliest group with the appropriate
number. Consider, for example:
(?|(a)|(b)) (c) (?-2)
The first two capture groups (a) and (b) are both numbered 1, and group
- (c) is number 2. When the reference (?-2) is encountered, the second
- most recently opened parentheses has the number 1, but it is the first
+ (c) is number 2. When the reference (?-2) is encountered, the second
+ most recently opened parentheses has the number 1, but it is the first
such group (the (a) group) to which the recursion refers. This would be
- the same if an absolute reference (?1) was used. In other words, rela-
+ the same if an absolute reference (?1) was used. In other words, rela-
tive references are just a shorthand for computing a group number.
- It is also possible to refer to subsequent capture groups, by writing
- references such as (?+2). However, these cannot be recursive because
- the reference is not inside the parentheses that are referenced. They
- are always non-recursive subroutine calls, as described in the next
+ It is also possible to refer to subsequent capture groups, by writing
+ references such as (?+2). However, these cannot be recursive because
+ the reference is not inside the parentheses that are referenced. They
+ are always non-recursive subroutine calls, as described in the next
section.
- An alternative approach is to use named parentheses. The Perl syntax
- for this is (?&name); PCRE1's earlier syntax (?P>name) is also sup-
+ An alternative approach is to use named parentheses. The Perl syntax
+ for this is (?&name); PCRE1's earlier syntax (?P>name) is also sup-
ported. We could rewrite the above example as follows:
(?<pn> \( ( [^()]++ | (?&pn) )* \) )
used.
The example pattern that we have been looking at contains nested unlim-
- ited repeats, and so the use of a possessive quantifier for matching
- strings of non-parentheses is important when applying the pattern to
+ ited repeats, and so the use of a possessive quantifier for matching
+ strings of non-parentheses is important when applying the pattern to
strings that do not match. For example, when this pattern is applied to
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
- it yields "no match" quickly. However, if a possessive quantifier is
- not used, the match runs for a very long time indeed because there are
- so many different ways the + and * repeats can carve up the subject,
+ it yields "no match" quickly. However, if a possessive quantifier is
+ not used, the match runs for a very long time indeed because there are
+ so many different ways the + and * repeats can carve up the subject,
and all have to be tested before failure can be reported.
- At the end of a match, the values of capturing parentheses are those
- from the outermost level. If you want to obtain intermediate values, a
+ At the end of a match, the values of capturing parentheses are those
+ from the outermost level. If you want to obtain intermediate values, a
callout function can be used (see below and the pcre2callout documenta-
tion). If the pattern above is matched against
(ab(cd)ef)
- the value for the inner capturing parentheses (numbered 2) is "ef",
- which is the last value taken on at the top level. If a capture group
- is not matched at the top level, its final captured value is unset,
- even if it was (temporarily) set at a deeper level during the matching
+ the value for the inner capturing parentheses (numbered 2) is "ef",
+ which is the last value taken on at the top level. If a capture group
+ is not matched at the top level, its final captured value is unset,
+ even if it was (temporarily) set at a deeper level during the matching
process.
- Do not confuse the (?R) item with the condition (R), which tests for
- recursion. Consider this pattern, which matches text in angle brack-
- ets, allowing for arbitrary nesting. Only digits are allowed in nested
- brackets (that is, when recursing), whereas any characters are permit-
+ Do not confuse the (?R) item with the condition (R), which tests for
+ recursion. Consider this pattern, which matches text in angle brack-
+ ets, allowing for arbitrary nesting. Only digits are allowed in nested
+ brackets (that is, when recursing), whereas any characters are permit-
ted at the outer level.
< (?: (?(R) \d++ | [^<>]*+) | (?R)) * >
- In this pattern, (?(R) is the start of a conditional group, with two
- different alternatives for the recursive and non-recursive cases. The
+ In this pattern, (?(R) is the start of a conditional group, with two
+ different alternatives for the recursive and non-recursive cases. The
(?R) item is the actual recursive call.
Differences in recursion processing between PCRE2 and Perl
Some former differences between PCRE2 and Perl no longer exist.
- Before release 10.30, recursion processing in PCRE2 differed from Perl
- in that a recursive subroutine call was always treated as an atomic
- group. That is, once it had matched some of the subject string, it was
- never re-entered, even if it contained untried alternatives and there
- was a subsequent matching failure. (Historical note: PCRE implemented
+ Before release 10.30, recursion processing in PCRE2 differed from Perl
+ in that a recursive subroutine call was always treated as an atomic
+ group. That is, once it had matched some of the subject string, it was
+ never re-entered, even if it contained untried alternatives and there
+ was a subsequent matching failure. (Historical note: PCRE implemented
recursion before Perl did.)
- Starting with release 10.30, recursive subroutine calls are no longer
+ Starting with release 10.30, recursive subroutine calls are no longer
treated as atomic. That is, they can be re-entered to try unused alter-
- natives if there is a matching failure later in the pattern. This is
- now compatible with the way Perl works. If you want a subroutine call
+ natives if there is a matching failure later in the pattern. This is
+ now compatible with the way Perl works. If you want a subroutine call
to be atomic, you must explicitly enclose it in an atomic group.
Supporting backtracking into recursions simplifies certain types of re-
^((.)(?1)\2|.?)$
- The second branch in the group matches a single central character in
- the palindrome when there are an odd number of characters, or nothing
- when there are an even number of characters, but in order to work it
- has to be able to try the second case when the rest of the pattern
+ The second branch in the group matches a single central character in
+ the palindrome when there are an odd number of characters, or nothing
+ when there are an even number of characters, but in order to work it
+ has to be able to try the second case when the rest of the pattern
match fails. If you want to match typical palindromic phrases, the pat-
- tern has to ignore all non-word characters, which can be done like
+ tern has to ignore all non-word characters, which can be done like
this:
^\W*+((.)\W*+(?1)\W*+\2|\W*+.?)\W*+$
- If run with the PCRE2_CASELESS option, this pattern matches phrases
- such as "A man, a plan, a canal: Panama!". Note the use of the posses-
- sive quantifier *+ to avoid backtracking into sequences of non-word
+ If run with the PCRE2_CASELESS option, this pattern matches phrases
+ such as "A man, a plan, a canal: Panama!". Note the use of the posses-
+ sive quantifier *+ to avoid backtracking into sequences of non-word
characters. Without this, PCRE2 takes a great deal longer (ten times or
- more) to match typical phrases, and Perl takes so long that you think
+ more) to match typical phrases, and Perl takes so long that you think
it has gone into a loop.
- Another way in which PCRE2 and Perl used to differ in their recursion
- processing is in the handling of captured values. Formerly in Perl,
- when a group was called recursively or as a subroutine (see the next
+ Another way in which PCRE2 and Perl used to differ in their recursion
+ processing is in the handling of captured values. Formerly in Perl,
+ when a group was called recursively or as a subroutine (see the next
section), it had no access to any values that were captured outside the
- recursion, whereas in PCRE2 these values can be referenced. Consider
+ recursion, whereas in PCRE2 these values can be referenced. Consider
this pattern:
^(.)(\1|a(?2))
- This pattern matches "bab". The first capturing parentheses match "b",
+ This pattern matches "bab". The first capturing parentheses match "b",
then in the second group, when the backreference \1 fails to match "b",
the second alternative matches "a" and then recurses. In the recursion,
- \1 does now match "b" and so the whole match succeeds. This match used
+ \1 does now match "b" and so the whole match succeeds. This match used
to fail in Perl, but in later versions (I tried 5.024) it now works.
GROUPS AS SUBROUTINES
- If the syntax for a recursive group call (either by number or by name)
- is used outside the parentheses to which it refers, it operates a bit
- like a subroutine in a programming language. More accurately, PCRE2
+ If the syntax for a recursive group call (either by number or by name)
+ is used outside the parentheses to which it refers, it operates a bit
+ like a subroutine in a programming language. More accurately, PCRE2
treats the referenced group as an independent subpattern which it tries
- to match at the current matching position. The called group may be de-
- fined before or after the reference. A numbered reference can be ab-
+ to match at the current matching position. The called group may be de-
+ fined before or after the reference. A numbered reference can be ab-
solute or relative, as in these examples:
(...(absolute)...)...(?2)...
(sens|respons)e and \1ibility
- matches "sense and sensibility" and "response and responsibility", but
+ matches "sense and sensibility" and "response and responsibility", but
not "sense and responsibility". If instead the pattern
(sens|respons)e and (?1)ibility
- is used, it does match "sense and responsibility" as well as the other
- two strings. Another example is given in the discussion of DEFINE
+ is used, it does match "sense and responsibility" as well as the other
+ two strings. Another example is given in the discussion of DEFINE
above.
- Like recursions, subroutine calls used to be treated as atomic, but
- this changed at PCRE2 release 10.30, so backtracking into subroutine
- calls can now occur. However, any capturing parentheses that are set
+ Like recursions, subroutine calls used to be treated as atomic, but
+ this changed at PCRE2 release 10.30, so backtracking into subroutine
+ calls can now occur. However, any capturing parentheses that are set
during the subroutine call revert to their previous values afterwards.
- Processing options such as case-independence are fixed when a group is
- defined, so if it is used as a subroutine, such options cannot be
+ Processing options such as case-independence are fixed when a group is
+ defined, so if it is used as a subroutine, such options cannot be
changed for different calls. For example, consider this pattern:
(abc)(?i:(?-1))
- It matches "abcabc". It does not match "abcABC" because the change of
+ It matches "abcabc". It does not match "abcABC" because the change of
processing option does not affect the called group.
- The behaviour of backtracking control verbs in groups when called as
+ The behaviour of backtracking control verbs in groups when called as
subroutines is described in the section entitled "Backtracking verbs in
subroutines" below.
ONIGURUMA SUBROUTINE SYNTAX
- For compatibility with Oniguruma, the non-Perl syntax \g followed by a
+ For compatibility with Oniguruma, the non-Perl syntax \g followed by a
name or a number enclosed either in angle brackets or single quotes, is
an alternative syntax for calling a group as a subroutine, possibly re-
- cursively. Here are two of the examples used above, rewritten using
+ cursively. Here are two of the examples used above, rewritten using
this syntax:
(?<pn> \( ( (?>[^()]+) | \g<pn> )* \) )
(sens|respons)e and \g'1'ibility
- PCRE2 supports an extension to Oniguruma: if a number is preceded by a
+ PCRE2 supports an extension to Oniguruma: if a number is preceded by a
plus or a minus sign it is taken as a relative reference. For example:
(abc)(?i:\g<-1>)
- Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not
- synonymous. The former is a backreference; the latter is a subroutine
+ Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not
+ synonymous. The former is a backreference; the latter is a subroutine
call.
CALLOUTS
Perl has a feature whereby using the sequence (?{...}) causes arbitrary
- Perl code to be obeyed in the middle of matching a regular expression.
+ Perl code to be obeyed in the middle of matching a regular expression.
This makes it possible, amongst other things, to extract different sub-
strings that match the same pair of parentheses when there is a repeti-
tion.
- PCRE2 provides a similar feature, but of course it cannot obey arbi-
- trary Perl code. The feature is called "callout". The caller of PCRE2
- provides an external function by putting its entry point in a match
- context using the function pcre2_set_callout(), and then passing that
- context to pcre2_match() or pcre2_dfa_match(). If no match context is
+ PCRE2 provides a similar feature, but of course it cannot obey arbi-
+ trary Perl code. The feature is called "callout". The caller of PCRE2
+ provides an external function by putting its entry point in a match
+ context using the function pcre2_set_callout(), and then passing that
+ context to pcre2_match() or pcre2_dfa_match(). If no match context is
passed, or if the callout entry point is set to NULL, callouts are dis-
abled.
- Within a regular expression, (?C<arg>) indicates a point at which the
- external function is to be called. There are two kinds of callout:
- those with a numerical argument and those with a string argument. (?C)
- on its own with no argument is treated as (?C0). A numerical argument
- allows the application to distinguish between different callouts.
- String arguments were added for release 10.20 to make it possible for
- script languages that use PCRE2 to embed short scripts within patterns
+ Within a regular expression, (?C<arg>) indicates a point at which the
+ external function is to be called. There are two kinds of callout:
+ those with a numerical argument and those with a string argument. (?C)
+ on its own with no argument is treated as (?C0). A numerical argument
+ allows the application to distinguish between different callouts.
+ String arguments were added for release 10.20 to make it possible for
+ script languages that use PCRE2 to embed short scripts within patterns
in a similar way to Perl.
During matching, when PCRE2 reaches a callout point, the external func-
- tion is called. It is provided with the number or string argument of
- the callout, the position in the pattern, and one item of data that is
+ tion is called. It is provided with the number or string argument of
+ the callout, the position in the pattern, and one item of data that is
also set in the match block. The callout function may cause matching to
proceed, to backtrack, or to fail.
- By default, PCRE2 implements a number of optimizations at matching
- time, and one side-effect is that sometimes callouts are skipped. If
- you need all possible callouts to happen, you need to set options that
- disable the relevant optimizations. More details, including a complete
- description of the programming interface to the callout function, are
+ By default, PCRE2 implements a number of optimizations at matching
+ time, and one side-effect is that sometimes callouts are skipped. If
+ you need all possible callouts to happen, you need to set options that
+ disable the relevant optimizations. More details, including a complete
+ description of the programming interface to the callout function, are
given in the pcre2callout documentation.
Callouts with numerical arguments
- If you just want to have a means of identifying different callout
- points, put a number less than 256 after the letter C. For example,
+ If you just want to have a means of identifying different callout
+ points, put a number less than 256 after the letter C. For example,
this pattern has two callout points:
(?C1)abc(?C2)def
- If the PCRE2_AUTO_CALLOUT flag is passed to pcre2_compile(), numerical
- callouts are automatically installed before each item in the pattern.
- They are all numbered 255. If there is a conditional group in the pat-
+ If the PCRE2_AUTO_CALLOUT flag is passed to pcre2_compile(), numerical
+ callouts are automatically installed before each item in the pattern.
+ They are all numbered 255. If there is a conditional group in the pat-
tern whose condition is an assertion, an additional callout is inserted
- just before the condition. An explicit callout may also be set at this
+ just before the condition. An explicit callout may also be set at this
position, as in this example:
(?(?C9)(?=a)abc|def)
Callouts with string arguments
- A delimited string may be used instead of a number as a callout argu-
- ment. The starting delimiter must be one of ` ' " ^ % # $ { and the
+ A delimited string may be used instead of a number as a callout argu-
+ ment. The starting delimiter must be one of ` ' " ^ % # $ { and the
ending delimiter is the same as the start, except for {, where the end-
- ing delimiter is }. If the ending delimiter is needed within the
+ ing delimiter is }. If the ending delimiter is needed within the
string, it must be doubled. For example:
(?C'ab ''c'' d')xyz(?C{any text})pqr
- The doubling is removed before the string is passed to the callout
+ The doubling is removed before the string is passed to the callout
function.
BACKTRACKING CONTROL
- There are a number of special "Backtracking Control Verbs" (to use
- Perl's terminology) that modify the behaviour of backtracking during
- matching. They are generally of the form (*VERB) or (*VERB:NAME). Some
+ There are a number of special "Backtracking Control Verbs" (to use
+ Perl's terminology) that modify the behaviour of backtracking during
+ matching. They are generally of the form (*VERB) or (*VERB:NAME). Some
verbs take either form, and may behave differently depending on whether
- or not a name argument is present. The names are not required to be
+ or not a name argument is present. The names are not required to be
unique within the pattern.
- By default, for compatibility with Perl, a name is any sequence of
+ By default, for compatibility with Perl, a name is any sequence of
characters that does not include a closing parenthesis. The name is not
- processed in any way, and it is not possible to include a closing
- parenthesis in the name. This can be changed by setting the
- PCRE2_ALT_VERBNAMES option, but the result is no longer Perl-compati-
+ processed in any way, and it is not possible to include a closing
+ parenthesis in the name. This can be changed by setting the
+ PCRE2_ALT_VERBNAMES option, but the result is no longer Perl-compati-
ble.
- When PCRE2_ALT_VERBNAMES is set, backslash processing is applied to
- verb names and only an unescaped closing parenthesis terminates the
- name. However, the only backslash items that are permitted are \Q, \E,
- and sequences such as \x{100} that define character code points. Char-
+ When PCRE2_ALT_VERBNAMES is set, backslash processing is applied to
+ verb names and only an unescaped closing parenthesis terminates the
+ name. However, the only backslash items that are permitted are \Q, \E,
+ and sequences such as \x{100} that define character code points. Char-
acter type escapes such as \d are faulted.
A closing parenthesis can be included in a name either as \) or between
- \Q and \E. In addition to backslash processing, if the PCRE2_EXTENDED
+ \Q and \E. In addition to backslash processing, if the PCRE2_EXTENDED
or PCRE2_EXTENDED_MORE option is also set, unescaped whitespace in verb
names is skipped, and #-comments are recognized, exactly as in the rest
- of the pattern. PCRE2_EXTENDED and PCRE2_EXTENDED_MORE do not affect
+ of the pattern. PCRE2_EXTENDED and PCRE2_EXTENDED_MORE do not affect
verb names unless PCRE2_ALT_VERBNAMES is also set.
- The maximum length of a name is 255 in the 8-bit library and 65535 in
- the 16-bit and 32-bit libraries. If the name is empty, that is, if the
- closing parenthesis immediately follows the colon, the effect is as if
+ The maximum length of a name is 255 in the 8-bit library and 65535 in
+ the 16-bit and 32-bit libraries. If the name is empty, that is, if the
+ closing parenthesis immediately follows the colon, the effect is as if
the colon were not there. Any number of these verbs may occur in a pat-
tern. Except for (*ACCEPT), they may not be quantified.
- Since these verbs are specifically related to backtracking, most of
- them can be used only when the pattern is to be matched using the tra-
+ Since these verbs are specifically related to backtracking, most of
+ them can be used only when the pattern is to be matched using the tra-
ditional matching function, because that uses a backtracking algorithm.
- With the exception of (*FAIL), which behaves like a failing negative
+ With the exception of (*FAIL), which behaves like a failing negative
assertion, the backtracking control verbs cause an error if encountered
by the DFA matching function.
- The behaviour of these verbs in repeated groups, assertions, and in
- capture groups called as subroutines (whether or not recursively) is
+ The behaviour of these verbs in repeated groups, assertions, and in
+ capture groups called as subroutines (whether or not recursively) is
documented below.
Optimizations that affect backtracking verbs
PCRE2 contains some optimizations that are used to speed up matching by
running some checks at the start of each match attempt. For example, it
- may know the minimum length of matching subject, or that a particular
+ may know the minimum length of matching subject, or that a particular
character must be present. When one of these optimizations bypasses the
- running of a match, any included backtracking verbs will not, of
+ running of a match, any included backtracking verbs will not, of
course, be processed. You can suppress the start-of-match optimizations
- by setting the PCRE2_NO_START_OPTIMIZE option when calling pcre2_com-
- pile(), or by starting the pattern with (*NO_START_OPT). There is more
+ by setting the PCRE2_NO_START_OPTIMIZE option when calling pcre2_com-
+ pile(), or by starting the pattern with (*NO_START_OPT). There is more
discussion of this option in the section entitled "Compiling a pattern"
in the pcre2api documentation.
- Experiments with Perl suggest that it too has similar optimizations,
+ Experiments with Perl suggest that it too has similar optimizations,
and like PCRE2, turning them off can change the result of a match.
Verbs that act immediately
(*ACCEPT) or (*ACCEPT:NAME)
- This verb causes the match to end successfully, skipping the remainder
- of the pattern. However, when it is inside a capture group that is
+ This verb causes the match to end successfully, skipping the remainder
+ of the pattern. However, when it is inside a capture group that is
called as a subroutine, only that group is ended successfully. Matching
then continues at the outer level. If (*ACCEPT) in triggered in a posi-
- tive assertion, the assertion succeeds; in a negative assertion, the
+ tive assertion, the assertion succeeds; in a negative assertion, the
assertion fails.
- If (*ACCEPT) is inside capturing parentheses, the data so far is cap-
+ If (*ACCEPT) is inside capturing parentheses, the data so far is cap-
tured. For example:
A((?:A|B(*ACCEPT)|C)D)
- This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap-
+ This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap-
tured by the outer parentheses.
- (*ACCEPT) is the only backtracking verb that is allowed to be quanti-
- fied because an ungreedy quantification with a minimum of zero acts
+ (*ACCEPT) is the only backtracking verb that is allowed to be quanti-
+ fied because an ungreedy quantification with a minimum of zero acts
only when a backtrack happens. Consider, for example,
(A(*ACCEPT)??B)C
- where A, B, and C may be complex expressions. After matching "A", the
- matcher processes "BC"; if that fails, causing a backtrack, (*ACCEPT)
- is triggered and the match succeeds. In both cases, all but C is cap-
- tured. Whereas (*COMMIT) (see below) means "fail on backtrack", a re-
+ where A, B, and C may be complex expressions. After matching "A", the
+ matcher processes "BC"; if that fails, causing a backtrack, (*ACCEPT)
+ is triggered and the match succeeds. In both cases, all but C is cap-
+ tured. Whereas (*COMMIT) (see below) means "fail on backtrack", a re-
peated (*ACCEPT) of this type means "succeed on backtrack".
- Warning: (*ACCEPT) should not be used within a script run group, be-
- cause it causes an immediate exit from the group, bypassing the script
+ Warning: (*ACCEPT) should not be used within a script run group, be-
+ cause it causes an immediate exit from the group, bypassing the script
run checking.
(*FAIL) or (*FAIL:NAME)
- This verb causes a matching failure, forcing backtracking to occur. It
- may be abbreviated to (*F). It is equivalent to (?!) but easier to
+ This verb causes a matching failure, forcing backtracking to occur. It
+ may be abbreviated to (*F). It is equivalent to (?!) but easier to
read. The Perl documentation notes that it is probably useful only when
combined with (?{}) or (??{}). Those are, of course, Perl features that
- are not present in PCRE2. The nearest equivalent is the callout fea-
+ are not present in PCRE2. The nearest equivalent is the callout fea-
ture, as for example in this pattern:
a+(?C)(*FAIL)
- A match with the string "aaaa" always fails, but the callout is taken
+ A match with the string "aaaa" always fails, but the callout is taken
before each backtrack happens (in this example, 10 times).
- (*ACCEPT:NAME) and (*FAIL:NAME) behave the same as (*MARK:NAME)(*AC-
- CEPT) and (*MARK:NAME)(*FAIL), respectively, that is, a (*MARK) is
+ (*ACCEPT:NAME) and (*FAIL:NAME) behave the same as (*MARK:NAME)(*AC-
+ CEPT) and (*MARK:NAME)(*FAIL), respectively, that is, a (*MARK) is
recorded just before the verb acts.
Recording which path was taken
- There is one verb whose main purpose is to track how a match was ar-
- rived at, though it also has a secondary use in conjunction with ad-
+ There is one verb whose main purpose is to track how a match was ar-
+ rived at, though it also has a secondary use in conjunction with ad-
vancing the match starting point (see (*SKIP) below).
(*MARK:NAME) or (*:NAME)
- A name is always required with this verb. For all the other backtrack-
+ A name is always required with this verb. For all the other backtrack-
ing control verbs, a NAME argument is optional.
- When a match succeeds, the name of the last-encountered mark name on
+ When a match succeeds, the name of the last-encountered mark name on
the matching path is passed back to the caller as described in the sec-
tion entitled "Other information about the match" in the pcre2api docu-
- mentation. This applies to all instances of (*MARK) and other verbs,
+ mentation. This applies to all instances of (*MARK) and other verbs,
including those inside assertions and atomic groups. However, there are
- differences in those cases when (*MARK) is used in conjunction with
+ differences in those cases when (*MARK) is used in conjunction with
(*SKIP) as described below.
- The mark name that was last encountered on the matching path is passed
- back. A verb without a NAME argument is ignored for this purpose. Here
- is an example of pcre2test output, where the "mark" modifier requests
+ The mark name that was last encountered on the matching path is passed
+ back. A verb without a NAME argument is ignored for this purpose. Here
+ is an example of pcre2test output, where the "mark" modifier requests
the retrieval and outputting of (*MARK) data:
re> /X(*MARK:A)Y|X(*MARK:B)Z/mark
MK: B
The (*MARK) name is tagged with "MK:" in this output, and in this exam-
- ple it indicates which of the two alternatives matched. This is a more
- efficient way of obtaining this information than putting each alterna-
+ ple it indicates which of the two alternatives matched. This is a more
+ efficient way of obtaining this information than putting each alterna-
tive in its own capturing parentheses.
- If a verb with a name is encountered in a positive assertion that is
- true, the name is recorded and passed back if it is the last-encoun-
+ If a verb with a name is encountered in a positive assertion that is
+ true, the name is recorded and passed back if it is the last-encoun-
tered. This does not happen for negative assertions or failing positive
assertions.
- After a partial match or a failed match, the last encountered name in
+ After a partial match or a failed match, the last encountered name in
the entire match process is returned. For example:
re> /X(*MARK:A)Y|X(*MARK:B)Z/mark
data> XP
No match, mark = B
- Note that in this unanchored example the mark is retained from the
+ Note that in this unanchored example the mark is retained from the
match attempt that started at the letter "X" in the subject. Subsequent
match attempts starting at "P" and then with an empty string do not get
as far as the (*MARK) item, but nevertheless do not reset it.
- If you are interested in (*MARK) values after failed matches, you
- should probably set the PCRE2_NO_START_OPTIMIZE option (see above) to
+ If you are interested in (*MARK) values after failed matches, you
+ should probably set the PCRE2_NO_START_OPTIMIZE option (see above) to
ensure that the match is always attempted.
Verbs that act after backtracking
The following verbs do nothing when they are encountered. Matching con-
- tinues with what follows, but if there is a subsequent match failure,
- causing a backtrack to the verb, a failure is forced. That is, back-
- tracking cannot pass to the left of the verb. However, when one of
+ tinues with what follows, but if there is a subsequent match failure,
+ causing a backtrack to the verb, a failure is forced. That is, back-
+ tracking cannot pass to the left of the verb. However, when one of
these verbs appears inside an atomic group or in a lookaround assertion
- that is true, its effect is confined to that group, because once the
- group has been matched, there is never any backtracking into it. Back-
+ that is true, its effect is confined to that group, because once the
+ group has been matched, there is never any backtracking into it. Back-
tracking from beyond an assertion or an atomic group ignores the entire
group, and seeks a preceding backtracking point.
- These verbs differ in exactly what kind of failure occurs when back-
- tracking reaches them. The behaviour described below is what happens
- when the verb is not in a subroutine or an assertion. Subsequent sec-
+ These verbs differ in exactly what kind of failure occurs when back-
+ tracking reaches them. The behaviour described below is what happens
+ when the verb is not in a subroutine or an assertion. Subsequent sec-
tions cover these special cases.
(*COMMIT) or (*COMMIT:NAME)
- This verb causes the whole match to fail outright if there is a later
+ This verb causes the whole match to fail outright if there is a later
matching failure that causes backtracking to reach it. Even if the pat-
- tern is unanchored, no further attempts to find a match by advancing
- the starting point take place. If (*COMMIT) is the only backtracking
+ tern is unanchored, no further attempts to find a match by advancing
+ the starting point take place. If (*COMMIT) is the only backtracking
verb that is encountered, once it has been passed pcre2_match() is com-
mitted to finding a match at the current starting point, or not at all.
For example:
a+(*COMMIT)b
- This matches "xxaab" but not "aacaab". It can be thought of as a kind
+ This matches "xxaab" but not "aacaab". It can be thought of as a kind
of dynamic anchor, or "I've started, so I must finish."
- The behaviour of (*COMMIT:NAME) is not the same as (*MARK:NAME)(*COM-
- MIT). It is like (*MARK:NAME) in that the name is remembered for pass-
- ing back to the caller. However, (*SKIP:NAME) searches only for names
+ The behaviour of (*COMMIT:NAME) is not the same as (*MARK:NAME)(*COM-
+ MIT). It is like (*MARK:NAME) in that the name is remembered for pass-
+ ing back to the caller. However, (*SKIP:NAME) searches only for names
that are set with (*MARK), ignoring those set by any of the other back-
tracking verbs.
- If there is more than one backtracking verb in a pattern, a different
- one that follows (*COMMIT) may be triggered first, so merely passing
+ If there is more than one backtracking verb in a pattern, a different
+ one that follows (*COMMIT) may be triggered first, so merely passing
(*COMMIT) during a match does not always guarantee that a match must be
at this starting point.
Note that (*COMMIT) at the start of a pattern is not the same as an an-
- chor, unless PCRE2's start-of-match optimizations are turned off, as
+ chor, unless PCRE2's start-of-match optimizations are turned off, as
shown in this output from pcre2test:
re> /(*COMMIT)abc/
data> xyzabc
No match
- For the first pattern, PCRE2 knows that any match must start with "a",
- so the optimization skips along the subject to "a" before applying the
- pattern to the first set of data. The match attempt then succeeds. The
- second pattern disables the optimization that skips along to the first
- character. The pattern is now applied starting at "x", and so the
- (*COMMIT) causes the match to fail without trying any other starting
+ For the first pattern, PCRE2 knows that any match must start with "a",
+ so the optimization skips along the subject to "a" before applying the
+ pattern to the first set of data. The match attempt then succeeds. The
+ second pattern disables the optimization that skips along to the first
+ character. The pattern is now applied starting at "x", and so the
+ (*COMMIT) causes the match to fail without trying any other starting
points.
(*PRUNE) or (*PRUNE:NAME)
- This verb causes the match to fail at the current starting position in
+ This verb causes the match to fail at the current starting position in
the subject if there is a later matching failure that causes backtrack-
- ing to reach it. If the pattern is unanchored, the normal "bumpalong"
- advance to the next starting character then happens. Backtracking can
- occur as usual to the left of (*PRUNE), before it is reached, or when
- matching to the right of (*PRUNE), but if there is no match to the
- right, backtracking cannot cross (*PRUNE). In simple cases, the use of
- (*PRUNE) is just an alternative to an atomic group or possessive quan-
+ ing to reach it. If the pattern is unanchored, the normal "bumpalong"
+ advance to the next starting character then happens. Backtracking can
+ occur as usual to the left of (*PRUNE), before it is reached, or when
+ matching to the right of (*PRUNE), but if there is no match to the
+ right, backtracking cannot cross (*PRUNE). In simple cases, the use of
+ (*PRUNE) is just an alternative to an atomic group or possessive quan-
tifier, but there are some uses of (*PRUNE) that cannot be expressed in
- any other way. In an anchored pattern (*PRUNE) has the same effect as
+ any other way. In an anchored pattern (*PRUNE) has the same effect as
(*COMMIT).
The behaviour of (*PRUNE:NAME) is not the same as (*MARK:NAME)(*PRUNE).
It is like (*MARK:NAME) in that the name is remembered for passing back
- to the caller. However, (*SKIP:NAME) searches only for names set with
+ to the caller. However, (*SKIP:NAME) searches only for names set with
(*MARK), ignoring those set by other backtracking verbs.
(*SKIP)
- This verb, when given without a name, is like (*PRUNE), except that if
- the pattern is unanchored, the "bumpalong" advance is not to the next
+ This verb, when given without a name, is like (*PRUNE), except that if
+ the pattern is unanchored, the "bumpalong" advance is not to the next
character, but to the position in the subject where (*SKIP) was encoun-
- tered. (*SKIP) signifies that whatever text was matched leading up to
- it cannot be part of a successful match if there is a later mismatch.
+ tered. (*SKIP) signifies that whatever text was matched leading up to
+ it cannot be part of a successful match if there is a later mismatch.
Consider:
a+(*SKIP)b
- If the subject is "aaaac...", after the first match attempt fails
- (starting at the first character in the string), the starting point
+ If the subject is "aaaac...", after the first match attempt fails
+ (starting at the first character in the string), the starting point
skips on to start the next attempt at "c". Note that a possessive quan-
tifier does not have the same effect as this example; although it would
- suppress backtracking during the first match attempt, the second at-
- tempt would start at the second character instead of skipping on to
+ suppress backtracking during the first match attempt, the second at-
+ tempt would start at the second character instead of skipping on to
"c".
- If (*SKIP) is used to specify a new starting position that is the same
- as the starting position of the current match, or (by being inside a
- lookbehind) earlier, the position specified by (*SKIP) is ignored, and
+ If (*SKIP) is used to specify a new starting position that is the same
+ as the starting position of the current match, or (by being inside a
+ lookbehind) earlier, the position specified by (*SKIP) is ignored, and
instead the normal "bumpalong" occurs.
(*SKIP:NAME)
- When (*SKIP) has an associated name, its behaviour is modified. When
- such a (*SKIP) is triggered, the previous path through the pattern is
- searched for the most recent (*MARK) that has the same name. If one is
- found, the "bumpalong" advance is to the subject position that corre-
- sponds to that (*MARK) instead of to where (*SKIP) was encountered. If
+ When (*SKIP) has an associated name, its behaviour is modified. When
+ such a (*SKIP) is triggered, the previous path through the pattern is
+ searched for the most recent (*MARK) that has the same name. If one is
+ found, the "bumpalong" advance is to the subject position that corre-
+ sponds to that (*MARK) instead of to where (*SKIP) was encountered. If
no (*MARK) with a matching name is found, the (*SKIP) is ignored.
- The search for a (*MARK) name uses the normal backtracking mechanism,
- which means that it does not see (*MARK) settings that are inside
+ The search for a (*MARK) name uses the normal backtracking mechanism,
+ which means that it does not see (*MARK) settings that are inside
atomic groups or assertions, because they are never re-entered by back-
tracking. Compare the following pcre2test examples:
0: b
1: b
- In the first example, the (*MARK) setting is in an atomic group, so it
+ In the first example, the (*MARK) setting is in an atomic group, so it
is not seen when (*SKIP:X) triggers, causing the (*SKIP) to be ignored.
- This allows the second branch of the pattern to be tried at the first
- character position. In the second example, the (*MARK) setting is not
- in an atomic group. This allows (*SKIP:X) to find the (*MARK) when it
+ This allows the second branch of the pattern to be tried at the first
+ character position. In the second example, the (*MARK) setting is not
+ in an atomic group. This allows (*SKIP:X) to find the (*MARK) when it
backtracks, and this causes a new matching attempt to start at the sec-
- ond character. This time, the (*MARK) is never seen because "a" does
+ ond character. This time, the (*MARK) is never seen because "a" does
not match "b", so the matcher immediately jumps to the second branch of
the pattern.
- Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It
+ Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It
ignores names that are set by other backtracking verbs.
(*THEN) or (*THEN:NAME)
- This verb causes a skip to the next innermost alternative when back-
- tracking reaches it. That is, it cancels any further backtracking
- within the current alternative. Its name comes from the observation
+ This verb causes a skip to the next innermost alternative when back-
+ tracking reaches it. That is, it cancels any further backtracking
+ within the current alternative. Its name comes from the observation
that it can be used for a pattern-based if-then-else block:
( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ...
- If the COND1 pattern matches, FOO is tried (and possibly further items
- after the end of the group if FOO succeeds); on failure, the matcher
- skips to the second alternative and tries COND2, without backtracking
- into COND1. If that succeeds and BAR fails, COND3 is tried. If subse-
- quently BAZ fails, there are no more alternatives, so there is a back-
- track to whatever came before the entire group. If (*THEN) is not in-
+ If the COND1 pattern matches, FOO is tried (and possibly further items
+ after the end of the group if FOO succeeds); on failure, the matcher
+ skips to the second alternative and tries COND2, without backtracking
+ into COND1. If that succeeds and BAR fails, COND3 is tried. If subse-
+ quently BAZ fails, there are no more alternatives, so there is a back-
+ track to whatever came before the entire group. If (*THEN) is not in-
side an alternation, it acts like (*PRUNE).
- The behaviour of (*THEN:NAME) is not the same as (*MARK:NAME)(*THEN).
+ The behaviour of (*THEN:NAME) is not the same as (*MARK:NAME)(*THEN).
It is like (*MARK:NAME) in that the name is remembered for passing back
- to the caller. However, (*SKIP:NAME) searches only for names set with
+ to the caller. However, (*SKIP:NAME) searches only for names set with
(*MARK), ignoring those set by other backtracking verbs.
- A group that does not contain a | character is just a part of the en-
- closing alternative; it is not a nested alternation with only one al-
+ A group that does not contain a | character is just a part of the en-
+ closing alternative; it is not a nested alternation with only one al-
ternative. The effect of (*THEN) extends beyond such a group to the en-
- closing alternative. Consider this pattern, where A, B, etc. are com-
- plex pattern fragments that do not contain any | characters at this
+ closing alternative. Consider this pattern, where A, B, etc. are com-
+ plex pattern fragments that do not contain any | characters at this
level:
A (B(*THEN)C) | D
- If A and B are matched, but there is a failure in C, matching does not
+ If A and B are matched, but there is a failure in C, matching does not
backtrack into A; instead it moves to the next alternative, that is, D.
- However, if the group containing (*THEN) is given an alternative, it
+ However, if the group containing (*THEN) is given an alternative, it
behaves differently:
A (B(*THEN)C | (*FAIL)) | D
The effect of (*THEN) is now confined to the inner group. After a fail-
- ure in C, matching moves to (*FAIL), which causes the whole group to
- fail because there are no more alternatives to try. In this case,
+ ure in C, matching moves to (*FAIL), which causes the whole group to
+ fail because there are no more alternatives to try. In this case,
matching does backtrack into A.
- Note that a conditional group is not considered as having two alterna-
- tives, because only one is ever used. In other words, the | character
- in a conditional group has a different meaning. Ignoring white space,
+ Note that a conditional group is not considered as having two alterna-
+ tives, because only one is ever used. In other words, the | character
+ in a conditional group has a different meaning. Ignoring white space,
consider:
^.*? (?(?=a) a | b(*THEN)c )
If the subject is "ba", this pattern does not match. Because .*? is un-
- greedy, it initially matches zero characters. The condition (?=a) then
- fails, the character "b" is matched, but "c" is not. At this point,
- matching does not backtrack to .*? as might perhaps be expected from
- the presence of the | character. The conditional group is part of the
- single alternative that comprises the whole pattern, and so the match
- fails. (If there was a backtrack into .*?, allowing it to match "b",
+ greedy, it initially matches zero characters. The condition (?=a) then
+ fails, the character "b" is matched, but "c" is not. At this point,
+ matching does not backtrack to .*? as might perhaps be expected from
+ the presence of the | character. The conditional group is part of the
+ single alternative that comprises the whole pattern, and so the match
+ fails. (If there was a backtrack into .*?, allowing it to match "b",
the match would succeed.)
- The verbs just described provide four different "strengths" of control
+ The verbs just described provide four different "strengths" of control
when subsequent matching fails. (*THEN) is the weakest, carrying on the
- match at the next alternative. (*PRUNE) comes next, failing the match
- at the current starting position, but allowing an advance to the next
- character (for an unanchored pattern). (*SKIP) is similar, except that
+ match at the next alternative. (*PRUNE) comes next, failing the match
+ at the current starting position, but allowing an advance to the next
+ character (for an unanchored pattern). (*SKIP) is similar, except that
the advance may be more than one character. (*COMMIT) is the strongest,
causing the entire match to fail.
More than one backtracking verb
- If more than one backtracking verb is present in a pattern, the one
- that is backtracked onto first acts. For example, consider this pat-
+ If more than one backtracking verb is present in a pattern, the one
+ that is backtracked onto first acts. For example, consider this pat-
tern, where A, B, etc. are complex pattern fragments:
(A(*COMMIT)B(*THEN)C|ABD)
- If A matches but B fails, the backtrack to (*COMMIT) causes the entire
+ If A matches but B fails, the backtrack to (*COMMIT) causes the entire
match to fail. However, if A and B match, but C fails, the backtrack to
- (*THEN) causes the next alternative (ABD) to be tried. This behaviour
- is consistent, but is not always the same as Perl's. It means that if
- two or more backtracking verbs appear in succession, all but the last
+ (*THEN) causes the next alternative (ABD) to be tried. This behaviour
+ is consistent, but is not always the same as Perl's. It means that if
+ two or more backtracking verbs appear in succession, all but the last
of them has no effect. Consider this example:
...(*COMMIT)(*PRUNE)...
If there is a matching failure to the right, backtracking onto (*PRUNE)
- causes it to be triggered, and its action is taken. There can never be
+ causes it to be triggered, and its action is taken. There can never be
a backtrack onto (*COMMIT).
Backtracking verbs in repeated groups
/(a(*COMMIT)b)+ac/
- If the subject is "abac", Perl matches unless its optimizations are
- disabled, but PCRE2 always fails because the (*COMMIT) in the second
+ If the subject is "abac", Perl matches unless its optimizations are
+ disabled, but PCRE2 always fails because the (*COMMIT) in the second
repeat of the group acts.
Backtracking verbs in assertions
- (*FAIL) in any assertion has its normal effect: it forces an immediate
- backtrack. The behaviour of the other backtracking verbs depends on
- whether or not the assertion is standalone or acting as the condition
+ (*FAIL) in any assertion has its normal effect: it forces an immediate
+ backtrack. The behaviour of the other backtracking verbs depends on
+ whether or not the assertion is standalone or acting as the condition
in a conditional group.
- (*ACCEPT) in a standalone positive assertion causes the assertion to
- succeed without any further processing; captured strings and a mark
- name (if set) are retained. In a standalone negative assertion, (*AC-
+ (*ACCEPT) in a standalone positive assertion causes the assertion to
+ succeed without any further processing; captured strings and a mark
+ name (if set) are retained. In a standalone negative assertion, (*AC-
CEPT) causes the assertion to fail without any further processing; cap-
tured substrings and any mark name are discarded.
- If the assertion is a condition, (*ACCEPT) causes the condition to be
- true for a positive assertion and false for a negative one; captured
+ If the assertion is a condition, (*ACCEPT) causes the condition to be
+ true for a positive assertion and false for a negative one; captured
substrings are retained in both cases.
The remaining verbs act only when a later failure causes a backtrack to
- reach them. This means that, for the Perl-compatible assertions, their
+ reach them. This means that, for the Perl-compatible assertions, their
effect is confined to the assertion, because Perl lookaround assertions
are atomic. A backtrack that occurs after such an assertion is complete
- does not jump back into the assertion. Note in particular that a
- (*MARK) name that is set in an assertion is not "seen" by an instance
+ does not jump back into the assertion. Note in particular that a
+ (*MARK) name that is set in an assertion is not "seen" by an instance
of (*SKIP:NAME) later in the pattern.
- PCRE2 now supports non-atomic positive assertions, as described in the
- section entitled "Non-atomic assertions" above. These assertions must
- be standalone (not used as conditions). They are not Perl-compatible.
- For these assertions, a later backtrack does jump back into the asser-
- tion, and therefore verbs such as (*COMMIT) can be triggered by back-
+ PCRE2 now supports non-atomic positive assertions, as described in the
+ section entitled "Non-atomic assertions" above. These assertions must
+ be standalone (not used as conditions). They are not Perl-compatible.
+ For these assertions, a later backtrack does jump back into the asser-
+ tion, and therefore verbs such as (*COMMIT) can be triggered by back-
tracks from later in the pattern.
- The effect of (*THEN) is not allowed to escape beyond an assertion. If
- there are no more branches to try, (*THEN) causes a positive assertion
+ The effect of (*THEN) is not allowed to escape beyond an assertion. If
+ there are no more branches to try, (*THEN) causes a positive assertion
to be false, and a negative assertion to be true.
- The other backtracking verbs are not treated specially if they appear
- in a standalone positive assertion. In a conditional positive asser-
+ The other backtracking verbs are not treated specially if they appear
+ in a standalone positive assertion. In a conditional positive asser-
tion, backtracking (from within the assertion) into (*COMMIT), (*SKIP),
- or (*PRUNE) causes the condition to be false. However, for both stand-
+ or (*PRUNE) causes the condition to be false. However, for both stand-
alone and conditional negative assertions, backtracking into (*COMMIT),
(*SKIP), or (*PRUNE) causes the assertion to be true, without consider-
ing any further alternative branches.
These behaviours occur whether or not the group is called recursively.
(*ACCEPT) in a group called as a subroutine causes the subroutine match
- to succeed without any further processing. Matching then continues af-
- ter the subroutine call. Perl documents this behaviour. Perl's treat-
+ to succeed without any further processing. Matching then continues af-
+ ter the subroutine call. Perl documents this behaviour. Perl's treat-
ment of the other verbs in subroutines is different in some cases.
- (*FAIL) in a group called as a subroutine has its normal effect: it
+ (*FAIL) in a group called as a subroutine has its normal effect: it
forces an immediate backtrack.
- (*COMMIT), (*SKIP), and (*PRUNE) cause the subroutine match to fail
- when triggered by being backtracked to in a group called as a subrou-
+ (*COMMIT), (*SKIP), and (*PRUNE) cause the subroutine match to fail
+ when triggered by being backtracked to in a group called as a subrou-
tine. There is then a backtrack at the outer level.
(*THEN), when triggered, skips to the next alternative in the innermost
- enclosing group that has alternatives (its normal behaviour). However,
+ enclosing group that has alternatives (its normal behaviour). However,
if there is no such group within the subroutine's group, the subroutine
match fails and there is a backtrack at the outer level.
SEE ALSO
- pcre2api(3), pcre2callout(3), pcre2matching(3), pcre2syntax(3),
+ pcre2api(3), pcre2callout(3), pcre2matching(3), pcre2syntax(3),
pcre2(3).
REVISION
- Last updated: 19 January 2024
+ Last updated: 04 June 2024
Copyright (c) 1997-2024 University of Cambridge.
-PCRE2 10.43 19 January 2024 PCRE2PATTERN(3)
+PCRE2 10.44 04 June 2024 PCRE2PATTERN(3)
------------------------------------------------------------------------------
--- /dev/null
+.TH PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH 3 "24 April 2024" "PCRE2 10.44"
+.SH NAME
+PCRE2 - Perl-compatible regular expressions (revised API)
+.SH SYNOPSIS
+.rs
+.sp
+.B #include <pcre2.h>
+.PP
+.nf
+.B int pcre2_set_max_pattern_compiled_length(
+.B " pcre2_compile_context *\fIccontext\fP, PCRE2_SIZE \fIvalue\fP);"
+.fi
+.
+.SH DESCRIPTION
+.rs
+.sp
+This function sets, in a compile context, the maximum size (in bytes) for the
+memory needed to hold the compiled version of a pattern that is compiled with
+this context. The result is always zero. If a pattern that is passed to
+\fBpcre2_compile()\fP with this context needs more memory, an error is
+generated. The default is the largest number that a PCRE2_SIZE variable can
+hold, which is effectively unlimited.
+.P
+There is a complete description of the PCRE2 native API in the
+.\" HREF
+\fBpcre2api\fP
+.\"
+page and a description of the POSIX API in the
+.\" HREF
+\fBpcre2posix\fP
+.\"
+page.
-.TH PCRE2API 3 "27 January 2024" "PCRE2 10.43"
+.TH PCRE2API 3 "24 April 2024" "PCRE2 10.44"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.sp
.B int pcre2_set_max_pattern_length(pcre2_compile_context *\fIccontext\fP,
.B " PCRE2_SIZE \fIvalue\fP);"
.sp
+.B int pcre2_set_max_pattern_compiled_length(
+.B " pcre2_compile_context *\fIccontext\fP, PCRE2_SIZE \fIvalue\fP);"
+.sp
.B int pcre2_set_max_varlookbehind(pcre2_compile_contest *\fIccontext\fP,
.B " uint32_t \fIvalue\fP);
.sp
PCRE2_SIZE variable can hold, which is effectively unlimited.
.sp
.nf
+.B int pcre2_set_max_pattern_compiled_length(
+.B " pcre2_compile_context *\fIccontext\fP, PCRE2_SIZE \fIvalue\fP);"
+.fi
+.sp
+This sets a maximum size, in bytes, for the memory needed to hold the compiled
+version of a pattern that is compiled with this context. If the pattern needs
+more memory, an error is generated. This facility is provided so that
+applications that accept patterns from external sources can limit the amount of
+memory they use. The default is the largest number that a PCRE2_SIZE variable
+can hold, which is effectively unlimited.
+.sp
+.nf
.B int pcre2_set_max_varlookbehind(pcre2_compile_contest *\fIccontext\fP,
.B " uint32_t \fIvalue\fP);
.fi
.rs
.sp
.nf
-Last updated: 27 January 2024
+Last updated: 24 April 2024
Copyright (c) 1997-2024 University of Cambridge.
.fi
-.TH PCRE2BUILD 3 "24 November" "PCRE2 10.43"
+.TH PCRE2BUILD 3 "15 April 2024" "PCRE2 10.44"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.
.\"
contains general information about building with Autotools (some of which is
repeated below), and also has some comments about building on various operating
-systems. There is a lot more information about building PCRE2 without using
+systems. The files in the \fBvms\fP directory support building under OpenVMS.
+There is a lot more information about building PCRE2 without using
Autotools (including information about using \fBCMake\fP and building "by
hand") in the text file called
.\" HTML <a href="NON-AUTOTOOLS-BUILD.txt">
.rs
.sp
.nf
-Last updated: 24 November 2023
-Copyright (c) 1997-2023 University of Cambridge.
+Last updated: 15 April 2024
+Copyright (c) 1997-2024 University of Cambridge.
.fi
-.TH PCRE2DEMO 3 "16 February 2024" "PCRE2 10.43-RC1"
+.TH PCRE2DEMO 3 " 7 June 2024" "PCRE2 10.44"
.\"AUTOMATICALLY GENERATED BY PrepareRelease - do not EDIT!
.SH NAME
PCRE2DEMO - A demonstration C program for PCRE2
-.TH PCRE2JIT 3 "23 January 2023" "PCRE2 10.43"
+.TH PCRE2JIT 3 "21 February 2024" "PCRE2 10.43"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 JUST-IN-TIME COMPILER SUPPORT"
you want to use JIT. The support is limited to the following hardware
platforms:
.sp
- ARM 32-bit (v5, v7, and Thumb2)
+ ARM 32-bit (v7, and Thumb2)
ARM 64-bit
IBM s390x 64 bit
Intel x86 32-bit and 64-bit
.rs
.sp
.nf
-Last updated: 23 January 2023
-Copyright (c) 1997-2023 University of Cambridge.
+Last updated: 21 February 2024
+Copyright (c) 1997-2024 University of Cambridge.
.fi
-.TH PCRE2PATTERN 3 "19 January 2024" "PCRE2 10.43"
+.TH PCRE2PATTERN 3 "04 June 2024" "PCRE2 10.44"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 REGULAR EXPRESSION DETAILS"
L, V, LV, or LVT character; an LV or V character may be followed by a V or T
character; an LVT or T character may be followed only by a T character.
.P
-4. Do not end before extending characters or spacing marks or the "zero-width
-joiner" character. Characters with the "mark" property always have the
+4. Do not end before extending characters or spacing marks or the zero-width
+joiner (ZWJ) character. Characters with the "mark" property always have the
"extend" grapheme breaking property.
.P
5. Do not end after prepend characters.
.P
-6. Do not break within emoji modifier sequences or emoji zwj sequences. That
-is, do not break between characters with the Extended_Pictographic property.
-Extend and ZWJ characters are allowed between the characters.
+6. Do not end within emoji modifier sequences or emoji ZWJ (zero-width
+joiner) sequences. An emoji ZWJ sequence consists of a character with the
+Extended_Pictographic property, optionally followed by one or more characters
+with the Extend property, followed by the ZWJ character, followed by another
+Extended_Pictographic character.
.P
7. Do not break within emoji flag sequences. That is, do not break between
regional indicator (RI) characters if there are an odd number of RI characters
using the Python syntax. PCRE2 supports both the Perl and the Python syntax.
.P
In PCRE2, a capture group can be named in one of three ways: (?<name>...) or
-(?'name'...) as in Perl, or (?P<name>...) as in Python. Names may be up to 32
+(?'name'...) as in Perl, or (?P<name>...) as in Python. Names may be up to 128
code units long. When PCRE2_UTF is not set, they may contain only ASCII
alphanumeric characters and underscores, but must start with a non-digit. When
PCRE2_UTF is set, the syntax of group names is extended to allow any Unicode
.rs
.sp
.nf
-Last updated: 19 January 2024
+Last updated: 04 June 2024
Copyright (c) 1997-2024 University of Cambridge.
.fi
-.TH PCRE2TEST 1 "27 January 2024" "PCRE 10.43"
+.TH PCRE2TEST 1 "24 April 2024" "PCRE 10.44"
.SH NAME
pcre2test - a program for testing Perl-compatible regular expressions.
.SH SYNOPSIS
jitfast use JIT fast path
jitverify verify JIT use
locale=<name> use this locale
- max_pattern_length=<n> set maximum pattern length
+ max_pattern_compiled ) set maximum compiled pattern
+ _length=<n> ) length (bytes)
+ max_pattern_length=<n> set maximum pattern length (code units)
max_varlookbehind=<n> set maximum variable lookbehind length
memory show memory used
newline=<type> set newline type
variable can hold (essentially unlimited).
.
.
+.SS "Limiting the size of a compiled pattern"
+.rs
+.sp
+The \fBmax_pattern_compiled_length\fP modifier sets a limit, in bytes, to the
+amount of memory used by a compiled pattern. Breaching the limit causes a
+compilation error. The default is the largest number a PCRE2_SIZE variable can
+hold (essentially unlimited).
+.
+.
.\" HTML <a name="posixwrapper"></a>
.SS "Using the POSIX wrapper API"
.rs
.rs
.sp
.nf
-Last updated: 27 January 2024
+Last updated: 24 April 2024
Copyright (c) 1997-2024 University of Cambridge.
.fi
jitfast use JIT fast path
jitverify verify JIT use
locale=<name> use this locale
- max_pattern_length=<n> set maximum pattern length
+ max_pattern_compiled ) set maximum compiled pattern
+ _length=<n> ) length (bytes)
+ max_pattern_length=<n> set maximum pattern length (code units)
max_varlookbehind=<n> set maximum variable lookbehind length
memory show memory used
newline=<type> set newline type
causes a compilation error. The default is the largest number a
PCRE2_SIZE variable can hold (essentially unlimited).
+ Limiting the size of a compiled pattern
+
+ The max_pattern_compiled_length modifier sets a limit, in bytes, to the
+ amount of memory used by a compiled pattern. Breaching the limit causes
+ a compilation error. The default is the largest number a PCRE2_SIZE
+ variable can hold (essentially unlimited).
+
Using the POSIX wrapper API
- The posix and posix_nosub modifiers cause pcre2test to call PCRE2 via
- the POSIX wrapper API rather than its native API. When posix_nosub is
- used, the POSIX option REG_NOSUB is passed to regcomp(). The POSIX
- wrapper supports only the 8-bit library. Note that it does not imply
+ The posix and posix_nosub modifiers cause pcre2test to call PCRE2 via
+ the POSIX wrapper API rather than its native API. When posix_nosub is
+ used, the POSIX option REG_NOSUB is passed to regcomp(). The POSIX
+ wrapper supports only the 8-bit library. Note that it does not imply
POSIX matching semantics; for more detail see the pcre2posix documenta-
- tion. The following pattern modifiers set options for the regcomp()
+ tion. The following pattern modifiers set options for the regcomp()
function:
caseless REG_ICASE
ucp REG_UCP ) the POSIX standard
utf REG_UTF8 )
- The regerror_buffsize modifier specifies a size for the error buffer
- that is passed to regerror() in the event of a compilation error. For
+ The regerror_buffsize modifier specifies a size for the error buffer
+ that is passed to regerror() in the event of a compilation error. For
example:
/abc/posix,regerror_buffsize=20
- This provides a means of testing the behaviour of regerror() when the
- buffer is too small for the error message. If this modifier has not
+ This provides a means of testing the behaviour of regerror() when the
+ buffer is too small for the error message. If this modifier has not
been set, a large buffer is used.
- The aftertext and allaftertext subject modifiers work as described be-
+ The aftertext and allaftertext subject modifiers work as described be-
low. All other modifiers are either ignored, with a warning message, or
cause an error.
- The pattern is passed to regcomp() as a zero-terminated string by de-
+ The pattern is passed to regcomp() as a zero-terminated string by de-
fault, but if the use_length or hex modifiers are set, the REG_PEND ex-
tension is used to pass it by length.
Testing the stack guard feature
- The stackguard modifier is used to test the use of pcre2_set_com-
- pile_recursion_guard(), a function that is provided to enable stack
- availability to be checked during compilation (see the pcre2api docu-
- mentation for details). If the number specified by the modifier is
+ The stackguard modifier is used to test the use of pcre2_set_com-
+ pile_recursion_guard(), a function that is provided to enable stack
+ availability to be checked during compilation (see the pcre2api docu-
+ mentation for details). If the number specified by the modifier is
greater than zero, pcre2_set_compile_recursion_guard() is called to set
- up callback from pcre2_compile() to a local function. The argument it
- receives is the current nesting parenthesis depth; if this is greater
+ up callback from pcre2_compile() to a local function. The argument it
+ receives is the current nesting parenthesis depth; if this is greater
than the value given by the modifier, non-zero is returned, causing the
compilation to be aborted.
Using alternative character tables
- The value specified for the tables modifier must be one of the digits
+ The value specified for the tables modifier must be one of the digits
0, 1, 2, or 3. It causes a specific set of built-in character tables to
- be passed to pcre2_compile(). This is used in the PCRE2 tests to check
- behaviour with different character tables. The digit specifies the ta-
+ be passed to pcre2_compile(). This is used in the PCRE2 tests to check
+ behaviour with different character tables. The digit specifies the ta-
bles as follows:
0 do not pass any special character tables
In tables 2, some characters whose codes are greater than 128 are iden-
tified as letters, digits, spaces, etc. Tables 3 can be used only after
- a #loadtables command has loaded them from a binary file. Setting al-
+ a #loadtables command has loaded them from a binary file. Setting al-
ternate character tables and a locale are mutually exclusive.
Setting certain match controls
The following modifiers are really subject modifiers, and are described
- under "Subject Modifiers" below. However, they may be included in a
- pattern's modifier list, in which case they are applied to every sub-
- ject line that is processed with that pattern. These modifiers do not
+ under "Subject Modifiers" below. However, they may be included in a
+ pattern's modifier list, in which case they are applied to every sub-
+ ject line that is processed with that pattern. These modifiers do not
affect the compilation process.
aftertext show text after match
substitute_unknown_unset use PCRE2_SUBSTITUTE_UNKNOWN_UNSET
substitute_unset_empty use PCRE2_SUBSTITUTE_UNSET_EMPTY
- These modifiers may not appear in a #pattern command. If you want them
+ These modifiers may not appear in a #pattern command. If you want them
as defaults, set them in a #subject command.
Specifying literal subject lines
- If the subject_literal modifier is present on a pattern, all the sub-
+ If the subject_literal modifier is present on a pattern, all the sub-
ject lines that it matches are taken as literal strings, with no inter-
- pretation of backslashes. It is not possible to set subject modifiers
- on such lines, but any that are set as defaults by a #subject command
+ pretation of backslashes. It is not possible to set subject modifiers
+ on such lines, but any that are set as defaults by a #subject command
are recognized.
Saving a compiled pattern
- When a pattern with the push modifier is successfully compiled, it is
- pushed onto a stack of compiled patterns, and pcre2test expects the
- next line to contain a new pattern (or a command) instead of a subject
+ When a pattern with the push modifier is successfully compiled, it is
+ pushed onto a stack of compiled patterns, and pcre2test expects the
+ next line to contain a new pattern (or a command) instead of a subject
line. This facility is used when saving compiled patterns to a file, as
- described in the section entitled "Saving and restoring compiled pat-
- terns" below. If pushcopy is used instead of push, a copy of the com-
- piled pattern is stacked, leaving the original as current, ready to
- match the following input lines. This provides a way of testing the
- pcre2_code_copy() function. The push and pushcopy modifiers are in-
- compatible with compilation modifiers such as global that act at match
+ described in the section entitled "Saving and restoring compiled pat-
+ terns" below. If pushcopy is used instead of push, a copy of the com-
+ piled pattern is stacked, leaving the original as current, ready to
+ match the following input lines. This provides a way of testing the
+ pcre2_code_copy() function. The push and pushcopy modifiers are in-
+ compatible with compilation modifiers such as global that act at match
time. Any that are specified are ignored (for the stacked copy), with a
- warning message, except for replace, which causes an error. Note that
- jitverify, which is allowed, does not carry through to any subsequent
+ warning message, except for replace, which causes an error. Note that
+ jitverify, which is allowed, does not carry through to any subsequent
matching that uses a stacked pattern.
Testing foreign pattern conversion
- The experimental foreign pattern conversion functions in PCRE2 can be
- tested by setting the convert modifier. Its argument is a colon-sepa-
- rated list of options, which set the equivalent option for the
+ The experimental foreign pattern conversion functions in PCRE2 can be
+ tested by setting the convert modifier. Its argument is a colon-sepa-
+ rated list of options, which set the equivalent option for the
pcre2_pattern_convert() function:
glob PCRE2_CONVERT_GLOB
The "unset" value is useful for turning off a default that has been set
by a #pattern command. When one of these options is set, the input pat-
- tern is passed to pcre2_pattern_convert(). If the conversion is suc-
- cessful, the result is reflected in the output and then passed to
+ tern is passed to pcre2_pattern_convert(). If the conversion is suc-
+ cessful, the result is reflected in the output and then passed to
pcre2_compile(). The normal utf and no_utf_check options, if set, cause
- the PCRE2_CONVERT_UTF and PCRE2_CONVERT_NO_UTF_CHECK options to be
+ the PCRE2_CONVERT_UTF and PCRE2_CONVERT_NO_UTF_CHECK options to be
passed to pcre2_pattern_convert().
By default, the conversion function is allowed to allocate a buffer for
- its output. However, if the convert_length modifier is set to a value
- greater than zero, pcre2test passes a buffer of the given length. This
+ its output. However, if the convert_length modifier is set to a value
+ greater than zero, pcre2test passes a buffer of the given length. This
makes it possible to test the length check.
- The convert_glob_escape and convert_glob_separator modifiers can be
- used to specify the escape and separator characters for glob process-
+ The convert_glob_escape and convert_glob_separator modifiers can be
+ used to specify the escape and separator characters for glob process-
ing, overriding the defaults, which are operating-system dependent.
Setting match options
- The following modifiers set options for pcre2_match() or
+ The following modifiers set options for pcre2_match() or
pcre2_dfa_match(). See pcreapi for a description of their effects.
anchored set PCRE2_ANCHORED
partial_hard (or ph) set PCRE2_PARTIAL_HARD
partial_soft (or ps) set PCRE2_PARTIAL_SOFT
- The partial matching modifiers are provided with abbreviations because
+ The partial matching modifiers are provided with abbreviations because
they appear frequently in tests.
- If the posix or posix_nosub modifier was present on the pattern, caus-
+ If the posix or posix_nosub modifier was present on the pattern, caus-
ing the POSIX wrapper API to be used, the only option-setting modifiers
that have any effect are notbol, notempty, and noteol, causing REG_NOT-
- BOL, REG_NOTEMPTY, and REG_NOTEOL, respectively, to be passed to
+ BOL, REG_NOTEMPTY, and REG_NOTEOL, respectively, to be passed to
regexec(). The other modifiers are ignored, with a warning message.
- There is one additional modifier that can be used with the POSIX wrap-
+ There is one additional modifier that can be used with the POSIX wrap-
per. It is ignored (with a warning) if used for non-POSIX matching.
posix_startend=<n>[:<m>]
- This causes the subject string to be passed to regexec() using the
- REG_STARTEND option, which uses offsets to specify which part of the
- string is searched. If only one number is given, the end offset is
- passed as the end of the subject string. For more detail of REG_STAR-
- TEND, see the pcre2posix documentation. If the subject string contains
- binary zeros (coded as escapes such as \x{00} because pcre2test does
+ This causes the subject string to be passed to regexec() using the
+ REG_STARTEND option, which uses offsets to specify which part of the
+ string is searched. If only one number is given, the end offset is
+ passed as the end of the subject string. For more detail of REG_STAR-
+ TEND, see the pcre2posix documentation. If the subject string contains
+ binary zeros (coded as escapes such as \x{00} because pcre2test does
not support actual binary zeros in its input), you must use posix_star-
tend to specify its length.
Setting match controls
- The following modifiers affect the matching process or request addi-
- tional information. Some of them may also be specified on a pattern
- line (see above), in which case they apply to every subject line that
- is matched against that pattern, but can be overridden by modifiers on
+ The following modifiers affect the matching process or request addi-
+ tional information. Some of them may also be specified on a pattern
+ line (see above), in which case they apply to every subject line that
+ is matched against that pattern, but can be overridden by modifiers on
the subject.
aftertext show text after match
zero_terminate pass the subject as zero-terminated
The effects of these modifiers are described in the following sections.
- When matching via the POSIX wrapper API, the aftertext, allaftertext,
- and ovector subject modifiers work as described below. All other modi-
+ When matching via the POSIX wrapper API, the aftertext, allaftertext,
+ and ovector subject modifiers work as described below. All other modi-
fiers are either ignored, with a warning message, or cause an error.
Showing more text
- The aftertext modifier requests that as well as outputting the part of
+ The aftertext modifier requests that as well as outputting the part of
the subject string that matched the entire pattern, pcre2test should in
addition output the remainder of the subject string. This is useful for
tests where the subject contains multiple copies of the same substring.
- The allaftertext modifier requests the same action for captured sub-
+ The allaftertext modifier requests the same action for captured sub-
strings as well as the main matched substring. In each case the remain-
der is output on the following line with a plus character following the
capture number.
- The allusedtext modifier requests that all the text that was consulted
- during a successful pattern match by the interpreter should be shown,
- for both full and partial matches. This feature is not supported for
- JIT matching, and if requested with JIT it is ignored (with a warning
- message). Setting this modifier affects the output if there is a look-
- behind at the start of a match, or, for a complete match, a lookahead
+ The allusedtext modifier requests that all the text that was consulted
+ during a successful pattern match by the interpreter should be shown,
+ for both full and partial matches. This feature is not supported for
+ JIT matching, and if requested with JIT it is ignored (with a warning
+ message). Setting this modifier affects the output if there is a look-
+ behind at the start of a match, or, for a complete match, a lookahead
at the end, or if \K is used in the pattern. Characters that precede or
- follow the start and end of the actual match are indicated in the out-
+ follow the start and end of the actual match are indicated in the out-
put by '<' or '>' characters underneath them. Here is an example:
re> /(?<=pqr)abc(?=xyz)/
Partial match: pqrabcxy
<<<
- The first, complete match shows that the matched string is "abc", with
- the preceding and following strings "pqr" and "xyz" having been con-
- sulted during the match (when processing the assertions). The partial
+ The first, complete match shows that the matched string is "abc", with
+ the preceding and following strings "pqr" and "xyz" having been con-
+ sulted during the match (when processing the assertions). The partial
match can indicate only the preceding string.
- The startchar modifier requests that the starting character for the
- match be indicated, if it is different to the start of the matched
+ The startchar modifier requests that the starting character for the
+ match be indicated, if it is different to the start of the matched
string. The only time when this occurs is when \K has been processed as
part of the match. In this situation, the output for the matched string
- is displayed from the starting character instead of from the match
+ is displayed from the starting character instead of from the match
point, with circumflex characters under the earlier characters. For ex-
ample:
0: abcxyz
^^^
- Unlike allusedtext, the startchar modifier can be used with JIT. How-
+ Unlike allusedtext, the startchar modifier can be used with JIT. How-
ever, these two modifiers are mutually exclusive.
Showing the value of all capture groups
The allcaptures modifier requests that the values of all potential cap-
tured parentheses be output after a match. By default, only those up to
the highest one actually used in the match are output (corresponding to
- the return code from pcre2_match()). Groups that did not take part in
- the match are output as "<unset>". This modifier is not relevant for
- DFA matching (which does no capturing) and does not apply when replace
+ the return code from pcre2_match()). Groups that did not take part in
+ the match are output as "<unset>". This modifier is not relevant for
+ DFA matching (which does no capturing) and does not apply when replace
is specified; it is ignored, with a warning message, if present.
Showing the entire ovector, for all outcomes
The allvector modifier requests that the entire ovector be shown, what-
ever the outcome of the match. Compare allcaptures, which shows only up
- to the maximum number of capture groups for the pattern, and then only
- for a successful complete non-DFA match. This modifier, which acts af-
- ter any match result, and also for DFA matching, provides a means of
- checking that there are no unexpected modifications to ovector fields.
- Before each match attempt, the ovector is filled with a special value,
- and if this is found in both elements of a capturing pair, "<un-
- changed>" is output. After a successful match, this applies to all
- groups after the maximum capture group for the pattern. In other cases
- it applies to the entire ovector. After a partial match, the first two
- elements are the only ones that should be set. After a DFA match, the
- amount of ovector that is used depends on the number of matches that
+ to the maximum number of capture groups for the pattern, and then only
+ for a successful complete non-DFA match. This modifier, which acts af-
+ ter any match result, and also for DFA matching, provides a means of
+ checking that there are no unexpected modifications to ovector fields.
+ Before each match attempt, the ovector is filled with a special value,
+ and if this is found in both elements of a capturing pair, "<un-
+ changed>" is output. After a successful match, this applies to all
+ groups after the maximum capture group for the pattern. In other cases
+ it applies to the entire ovector. After a partial match, the first two
+ elements are the only ones that should be set. After a DFA match, the
+ amount of ovector that is used depends on the number of matches that
were found.
Testing pattern callouts
- A callout function is supplied when pcre2test calls the library match-
- ing functions, unless callout_none is specified. Its behaviour can be
- controlled by various modifiers listed above whose names begin with
- callout_. Details are given in the section entitled "Callouts" below.
- Testing callouts from pcre2_substitute() is described separately in
+ A callout function is supplied when pcre2test calls the library match-
+ ing functions, unless callout_none is specified. Its behaviour can be
+ controlled by various modifiers listed above whose names begin with
+ callout_. Details are given in the section entitled "Callouts" below.
+ Testing callouts from pcre2_substitute() is described separately in
"Testing the substitution function" below.
Finding all matches in a string
Searching for all possible matches within a subject can be requested by
- the global or altglobal modifier. After finding a match, the matching
- function is called again to search the remainder of the subject. The
- difference between global and altglobal is that the former uses the
- start_offset argument to pcre2_match() or pcre2_dfa_match() to start
- searching at a new point within the entire string (which is what Perl
+ the global or altglobal modifier. After finding a match, the matching
+ function is called again to search the remainder of the subject. The
+ difference between global and altglobal is that the former uses the
+ start_offset argument to pcre2_match() or pcre2_dfa_match() to start
+ searching at a new point within the entire string (which is what Perl
does), whereas the latter passes over a shortened subject. This makes a
difference to the matching process if the pattern begins with a lookbe-
hind assertion (including \b or \B).
- If an empty string is matched, the next match is done with the
+ If an empty string is matched, the next match is done with the
PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED flags set, in order to search
for another, non-empty, match at the same point in the subject. If this
- match fails, the start offset is advanced, and the normal match is re-
- tried. This imitates the way Perl handles such cases when using the /g
- modifier or the split() function. Normally, the start offset is ad-
- vanced by one character, but if the newline convention recognizes CRLF
- as a newline, and the current character is CR followed by LF, an ad-
+ match fails, the start offset is advanced, and the normal match is re-
+ tried. This imitates the way Perl handles such cases when using the /g
+ modifier or the split() function. Normally, the start offset is ad-
+ vanced by one character, but if the newline convention recognizes CRLF
+ as a newline, and the current character is CR followed by LF, an ad-
vance of two characters occurs.
Testing substring extraction functions
- The copy and get modifiers can be used to test the pcre2_sub-
+ The copy and get modifiers can be used to test the pcre2_sub-
string_copy_xxx() and pcre2_substring_get_xxx() functions. They can be
given more than once, and each can specify a capture group name or num-
ber, for example:
abcd\=copy=1,copy=3,get=G1
- If the #subject command is used to set default copy and/or get lists,
- these can be unset by specifying a negative number to cancel all num-
+ If the #subject command is used to set default copy and/or get lists,
+ these can be unset by specifying a negative number to cancel all num-
bered groups and an empty name to cancel all named groups.
- The getall modifier tests pcre2_substring_list_get(), which extracts
+ The getall modifier tests pcre2_substring_list_get(), which extracts
all captured substrings.
- If the subject line is successfully matched, the substrings extracted
- by the convenience functions are output with C, G, or L after the
- string number instead of a colon. This is in addition to the normal
- full list. The string length (that is, the return from the extraction
+ If the subject line is successfully matched, the substrings extracted
+ by the convenience functions are output with C, G, or L after the
+ string number instead of a colon. This is in addition to the normal
+ full list. The string length (that is, the return from the extraction
function) is given in parentheses after each substring, followed by the
name when the extraction was by name.
Testing the substitution function
- If the replace modifier is set, the pcre2_substitute() function is
- called instead of one of the matching functions (or after one call of
- pcre2_match() in the case of PCRE2_SUBSTITUTE_MATCHED). Note that re-
- placement strings cannot contain commas, because a comma signifies the
- end of a modifier. This is not thought to be an issue in a test pro-
+ If the replace modifier is set, the pcre2_substitute() function is
+ called instead of one of the matching functions (or after one call of
+ pcre2_match() in the case of PCRE2_SUBSTITUTE_MATCHED). Note that re-
+ placement strings cannot contain commas, because a comma signifies the
+ end of a modifier. This is not thought to be an issue in a test pro-
gram.
- Specifying a completely empty replacement string disables this modi-
- fier. However, it is possible to specify an empty replacement by pro-
- viding a buffer length, as described below, for an otherwise empty re-
+ Specifying a completely empty replacement string disables this modi-
+ fier. However, it is possible to specify an empty replacement by pro-
+ viding a buffer length, as described below, for an otherwise empty re-
placement.
- Unlike subject strings, pcre2test does not process replacement strings
- for escape sequences. In UTF mode, a replacement string is checked to
- see if it is a valid UTF-8 string. If so, it is correctly converted to
- a UTF string of the appropriate code unit width. If it is not a valid
- UTF-8 string, the individual code units are copied directly. This pro-
+ Unlike subject strings, pcre2test does not process replacement strings
+ for escape sequences. In UTF mode, a replacement string is checked to
+ see if it is a valid UTF-8 string. If so, it is correctly converted to
+ a UTF string of the appropriate code unit width. If it is not a valid
+ UTF-8 string, the individual code units are copied directly. This pro-
vides a means of passing an invalid UTF-8 string for testing purposes.
- The following modifiers set options (in additional to the normal match
+ The following modifiers set options (in additional to the normal match
options) for pcre2_substitute():
global PCRE2_SUBSTITUTE_GLOBAL
See the pcre2api documentation for details of these options.
- After a successful substitution, the modified string is output, pre-
- ceded by the number of replacements. This may be zero if there were no
+ After a successful substitution, the modified string is output, pre-
+ ceded by the number of replacements. This may be zero if there were no
matches. Here is a simple example of a substitution test:
/abc/replace=xxx
=abc=abc=\=global
2: =xxx=xxx=
- Subject and replacement strings should be kept relatively short (fewer
- than 256 characters) for substitution tests, as fixed-size buffers are
- used. To make it easy to test for buffer overflow, if the replacement
- string starts with a number in square brackets, that number is passed
- to pcre2_substitute() as the size of the output buffer, with the re-
- placement string starting at the next character. Here is an example
+ Subject and replacement strings should be kept relatively short (fewer
+ than 256 characters) for substitution tests, as fixed-size buffers are
+ used. To make it easy to test for buffer overflow, if the replacement
+ string starts with a number in square brackets, that number is passed
+ to pcre2_substitute() as the size of the output buffer, with the re-
+ placement string starting at the next character. Here is an example
that tests the edge case:
/abc/
Failed: error -47: no more memory
The default action of pcre2_substitute() is to return PCRE2_ER-
- ROR_NOMEMORY when the output buffer is too small. However, if the
- PCRE2_SUBSTITUTE_OVERFLOW_LENGTH option is set (by using the substi-
+ ROR_NOMEMORY when the output buffer is too small. However, if the
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH option is set (by using the substi-
tute_overflow_length modifier), pcre2_substitute() continues to go
- through the motions of matching and substituting (but not doing any
- callouts), in order to compute the size of buffer that is required.
- When this happens, pcre2test shows the required buffer length (which
+ through the motions of matching and substituting (but not doing any
+ callouts), in order to compute the size of buffer that is required.
+ When this happens, pcre2test shows the required buffer length (which
includes space for the trailing zero) as part of the error message. For
example:
Failed: error -47: no more memory: 10 code units are needed
A replacement string is ignored with POSIX and DFA matching. Specifying
- partial matching provokes an error return ("bad option value") from
+ partial matching provokes an error return ("bad option value") from
pcre2_substitute().
Testing substitute callouts
If the substitute_callout modifier is set, a substitution callout func-
- tion is set up. The null_context modifier must not be set, because the
- address of the callout function is passed in a match context. When the
- callout function is called (after each substitution), details of the
+ tion is set up. The null_context modifier must not be set, because the
+ address of the callout function is passed in a match context. When the
+ callout function is called (after each substitution), details of the
input and output strings are output. For example:
/abc/g,replace=<$0>,substitute_callout
2(1) Old 6 9 "abc" New 8 13 "<abc>"
2: <abc>def<abc>pqr
- The first number on each callout line is the count of matches. The
+ The first number on each callout line is the count of matches. The
parenthesized number is the number of pairs that are set in the ovector
- (that is, one more than the number of capturing groups that were set).
+ (that is, one more than the number of capturing groups that were set).
Then are listed the offsets of the old substring, its contents, and the
same for the replacement.
- By default, the substitution callout function returns zero, which ac-
- cepts the replacement and causes matching to continue if /g was used.
- Two further modifiers can be used to test other return values. If sub-
- stitute_skip is set to a value greater than zero the callout function
- returns +1 for the match of that number, and similarly substitute_stop
- returns -1. These cause the replacement to be rejected, and -1 causes
- no further matching to take place. If either of them are set, substi-
+ By default, the substitution callout function returns zero, which ac-
+ cepts the replacement and causes matching to continue if /g was used.
+ Two further modifiers can be used to test other return values. If sub-
+ stitute_skip is set to a value greater than zero the callout function
+ returns +1 for the match of that number, and similarly substitute_stop
+ returns -1. These cause the replacement to be rejected, and -1 causes
+ no further matching to take place. If either of them are set, substi-
tute_callout is assumed. For example:
/abc/g,replace=<$0>,substitute_skip=1
Setting the JIT stack size
- The jitstack modifier provides a way of setting the maximum stack size
- that is used by the just-in-time optimization code. It is ignored if
- JIT optimization is not being used. The value is a number of kibibytes
- (units of 1024 bytes). Setting zero reverts to the default of 32KiB.
+ The jitstack modifier provides a way of setting the maximum stack size
+ that is used by the just-in-time optimization code. It is ignored if
+ JIT optimization is not being used. The value is a number of kibibytes
+ (units of 1024 bytes). Setting zero reverts to the default of 32KiB.
Providing a stack that is larger than the default is necessary only for
- very complicated patterns. If jitstack is set non-zero on a subject
+ very complicated patterns. If jitstack is set non-zero on a subject
line it overrides any value that was set on the pattern.
Setting heap, match, and depth limits
- The heap_limit, match_limit, and depth_limit modifiers set the appro-
- priate limits in the match context. These values are ignored when the
+ The heap_limit, match_limit, and depth_limit modifiers set the appro-
+ priate limits in the match context. These values are ignored when the
find_limits or find_limits_noheap modifier is specified.
Finding minimum limits
- If the find_limits modifier is present on a subject line, pcre2test
- calls the relevant matching function several times, setting different
- values in the match context via pcre2_set_heap_limit(),
- pcre2_set_match_limit(), or pcre2_set_depth_limit() until it finds the
- smallest value for each parameter that allows the match to complete
+ If the find_limits modifier is present on a subject line, pcre2test
+ calls the relevant matching function several times, setting different
+ values in the match context via pcre2_set_heap_limit(),
+ pcre2_set_match_limit(), or pcre2_set_depth_limit() until it finds the
+ smallest value for each parameter that allows the match to complete
without a "limit exceeded" error. The match itself may succeed or fail.
An alternative modifier, find_limits_noheap, omits the heap limit. This
- is used in the standard tests, because the minimum heap limit varies
- between systems. If JIT is being used, only the match limit is rele-
+ is used in the standard tests, because the minimum heap limit varies
+ between systems. If JIT is being used, only the match limit is rele-
vant, and the other two are automatically omitted.
When using this modifier, the pattern should not contain any limit set-
- tings such as (*LIMIT_MATCH=...) within it. If such a setting is
+ tings such as (*LIMIT_MATCH=...) within it. If such a setting is
present and is lower than the minimum matching value, the minimum value
- cannot be found because pcre2_set_match_limit() etc. are only able to
+ cannot be found because pcre2_set_match_limit() etc. are only able to
reduce the value of an in-pattern limit; they cannot increase it.
- For non-DFA matching, the minimum depth_limit number is a measure of
+ For non-DFA matching, the minimum depth_limit number is a measure of
how much nested backtracking happens (that is, how deeply the pattern's
- tree is searched). In the case of DFA matching, depth_limit controls
- the depth of recursive calls of the internal function that is used for
+ tree is searched). In the case of DFA matching, depth_limit controls
+ the depth of recursive calls of the internal function that is used for
handling pattern recursion, lookaround assertions, and atomic groups.
For non-DFA matching, the match_limit number is a measure of the amount
of backtracking that takes place, and learning the minimum value can be
- instructive. For most simple matches, the number is quite small, but
- for patterns with very large numbers of matching possibilities, it can
- become large very quickly with increasing length of subject string. In
- the case of DFA matching, match_limit controls the total number of
+ instructive. For most simple matches, the number is quite small, but
+ for patterns with very large numbers of matching possibilities, it can
+ become large very quickly with increasing length of subject string. In
+ the case of DFA matching, match_limit controls the total number of
calls, both recursive and non-recursive, to the internal matching func-
tion, thus controlling the overall amount of computing resource that is
used.
- For both kinds of matching, the heap_limit number, which is in
- kibibytes (units of 1024 bytes), limits the amount of heap memory used
+ For both kinds of matching, the heap_limit number, which is in
+ kibibytes (units of 1024 bytes), limits the amount of heap memory used
for matching.
Showing MARK names
The mark modifier causes the names from backtracking control verbs that
- are returned from calls to pcre2_match() to be displayed. If a mark is
- returned for a match, non-match, or partial match, pcre2test shows it.
- For a match, it is on a line by itself, tagged with "MK:". Otherwise,
+ are returned from calls to pcre2_match() to be displayed. If a mark is
+ returned for a match, non-match, or partial match, pcre2test shows it.
+ For a match, it is on a line by itself, tagged with "MK:". Otherwise,
it is added to the non-match message.
Showing memory usage
- The memory modifier causes pcre2test to log the sizes of all heap mem-
- ory allocation and freeing calls that occur during a call to
- pcre2_match() or pcre2_dfa_match(). In the latter case, heap memory is
- used only when a match requires more internal workspace that the de-
- fault allocation on the stack, so in many cases there will be no out-
- put. No heap memory is allocated during matching with JIT. For this
+ The memory modifier causes pcre2test to log the sizes of all heap mem-
+ ory allocation and freeing calls that occur during a call to
+ pcre2_match() or pcre2_dfa_match(). In the latter case, heap memory is
+ used only when a match requires more internal workspace that the de-
+ fault allocation on the stack, so in many cases there will be no out-
+ put. No heap memory is allocated during matching with JIT. For this
modifier to work, the null_context modifier must not be set on both the
pattern and the subject, though it can be set on one or the other.
Showing the heap frame overall vector size
- The heapframes_size modifier is relevant for matches using
+ The heapframes_size modifier is relevant for matches using
pcre2_match() without JIT. After a match has run (whether successful or
- not) the size, in bytes, of the allocated heap frames vector that is
- left attached to the match data block is shown. If the matching action
- involved several calls to pcre2_match() (for example, global matching
+ not) the size, in bytes, of the allocated heap frames vector that is
+ left attached to the match data block is shown. If the matching action
+ involved several calls to pcre2_match() (for example, global matching
or for timing) only the final value is shown.
- This modifier is ignored, with a warning, for POSIX or DFA matching.
+ This modifier is ignored, with a warning, for POSIX or DFA matching.
JIT matching does not use the heap frames vector, so the size is always
- zero, unless there was a previous non-JIT match. Note that specifing a
+ zero, unless there was a previous non-JIT match. Note that specifing a
size of zero for the output vector (see below) causes pcre2test to free
its match data block (and associated heap frames vector) and allocate a
new one.
Setting a starting offset
- The offset modifier sets an offset in the subject string at which
+ The offset modifier sets an offset in the subject string at which
matching starts. Its value is a number of code units, not characters.
Setting an offset limit
- The offset_limit modifier sets a limit for unanchored matches. If a
+ The offset_limit modifier sets a limit for unanchored matches. If a
match cannot be found starting at or before this offset in the subject,
a "no match" return is given. The data value is a number of code units,
- not characters. When this modifier is used, the use_offset_limit modi-
+ not characters. When this modifier is used, the use_offset_limit modi-
fier must have been set for the pattern; if not, an error is generated.
Setting the size of the output vector
- The ovector modifier applies only to the subject line in which it ap-
+ The ovector modifier applies only to the subject line in which it ap-
pears, though of course it can also be used to set a default in a #sub-
- ject command. It specifies the number of pairs of offsets that are
+ ject command. It specifies the number of pairs of offsets that are
available for storing matching information. The default is 15.
- A value of zero is useful when testing the POSIX API because it causes
+ A value of zero is useful when testing the POSIX API because it causes
regexec() to be called with a NULL capture vector. When not testing the
- POSIX API, a value of zero is used to cause pcre2_match_data_cre-
- ate_from_pattern() to be called, in order to create a new match block
- of exactly the right size for the pattern. (It is not possible to cre-
- ate a match block with a zero-length ovector; there is always at least
+ POSIX API, a value of zero is used to cause pcre2_match_data_cre-
+ ate_from_pattern() to be called, in order to create a new match block
+ of exactly the right size for the pattern. (It is not possible to cre-
+ ate a match block with a zero-length ovector; there is always at least
one pair of offsets.) The old match data block is freed.
Passing the subject as zero-terminated
By default, the subject string is passed to a native API matching func-
tion with its correct length. In order to test the facility for passing
- a zero-terminated string, the zero_terminate modifier is provided. It
- causes the length to be passed as PCRE2_ZERO_TERMINATED. When matching
+ a zero-terminated string, the zero_terminate modifier is provided. It
+ causes the length to be passed as PCRE2_ZERO_TERMINATED. When matching
via the POSIX interface, this modifier is ignored, with a warning.
- When testing pcre2_substitute(), this modifier also has the effect of
+ When testing pcre2_substitute(), this modifier also has the effect of
passing the replacement string as zero-terminated.
Passing a NULL context, subject, or replacement
- Normally, pcre2test passes a context block to pcre2_match(),
- pcre2_dfa_match(), pcre2_jit_match() or pcre2_substitute(). If the
- null_context modifier is set, however, NULL is passed. This is for
- testing that the matching and substitution functions behave correctly
- in this case (they use default values). This modifier cannot be used
- with the find_limits, find_limits_noheap, or substitute_callout modi-
+ Normally, pcre2test passes a context block to pcre2_match(),
+ pcre2_dfa_match(), pcre2_jit_match() or pcre2_substitute(). If the
+ null_context modifier is set, however, NULL is passed. This is for
+ testing that the matching and substitution functions behave correctly
+ in this case (they use default values). This modifier cannot be used
+ with the find_limits, find_limits_noheap, or substitute_callout modi-
fiers.
- Similarly, for testing purposes, if the null_subject or null_replace-
- ment modifier is set, the subject or replacement string pointers are
+ Similarly, for testing purposes, if the null_subject or null_replace-
+ ment modifier is set, the subject or replacement string pointers are
passed as NULL, respectively, to the relevant functions.
THE ALTERNATIVE MATCHING FUNCTION
- By default, pcre2test uses the standard PCRE2 matching function,
+ By default, pcre2test uses the standard PCRE2 matching function,
pcre2_match() to match each subject line. PCRE2 also supports an alter-
- native matching function, pcre2_dfa_match(), which operates in a dif-
- ferent way, and has some restrictions. The differences between the two
+ native matching function, pcre2_dfa_match(), which operates in a dif-
+ ferent way, and has some restrictions. The differences between the two
functions are described in the pcre2matching documentation.
- If the dfa modifier is set, the alternative matching function is used.
- This function finds all possible matches at a given point in the sub-
- ject. If, however, the dfa_shortest modifier is set, processing stops
- after the first match is found. This is always the shortest possible
+ If the dfa modifier is set, the alternative matching function is used.
+ This function finds all possible matches at a given point in the sub-
+ ject. If, however, the dfa_shortest modifier is set, processing stops
+ after the first match is found. This is always the shortest possible
match.
DEFAULT OUTPUT FROM pcre2test
- This section describes the output when the normal matching function,
+ This section describes the output when the normal matching function,
pcre2_match(), is being used.
- When a match succeeds, pcre2test outputs the list of captured sub-
- strings, starting with number 0 for the string that matched the whole
+ When a match succeeds, pcre2test outputs the list of captured sub-
+ strings, starting with number 0 for the string that matched the whole
pattern. Otherwise, it outputs "No match" when the return is PCRE2_ER-
- ROR_NOMATCH, or "Partial match:" followed by the partially matching
- substring when the return is PCRE2_ERROR_PARTIAL. (Note that this is
- the entire substring that was inspected during the partial match; it
- may include characters before the actual match start if a lookbehind
+ ROR_NOMATCH, or "Partial match:" followed by the partially matching
+ substring when the return is PCRE2_ERROR_PARTIAL. (Note that this is
+ the entire substring that was inspected during the partial match; it
+ may include characters before the actual match start if a lookbehind
assertion, \K, \b, or \B was involved.)
For any other return, pcre2test outputs the PCRE2 negative error number
- and a short descriptive phrase. If the error is a failed UTF string
- check, the code unit offset of the start of the failing character is
+ and a short descriptive phrase. If the error is a failed UTF string
+ check, the code unit offset of the start of the failing character is
also output. Here is an example of an interactive pcre2test run.
$ pcre2test
Unset capturing substrings that are not followed by one that is set are
not shown by pcre2test unless the allcaptures modifier is specified. In
the following example, there are two capturing substrings, but when the
- first data line is matched, the second, unset substring is not shown.
- An "internal" unset substring is shown as "<unset>", as for the second
+ first data line is matched, the second, unset substring is not shown.
+ An "internal" unset substring is shown as "<unset>", as for the second
data line.
re> /(a)|(b)/
1: <unset>
2: b
- If the strings contain any non-printing characters, they are output as
- \xhh escapes if the value is less than 256 and UTF mode is not set.
+ If the strings contain any non-printing characters, they are output as
+ \xhh escapes if the value is less than 256 and UTF mode is not set.
Otherwise they are output as \x{hh...} escapes. See below for the defi-
- nition of non-printing characters. If the aftertext modifier is set,
- the output for substring 0 is followed by the rest of the subject
+ nition of non-printing characters. If the aftertext modifier is set,
+ the output for substring 0 is followed by the rest of the subject
string, identified by "0+" like this:
re> /cat/aftertext
0: ipp
1: pp
- "No match" is output only if the first match attempt fails. Here is an
- example of a failure message (the offset 4 that is specified by the
+ "No match" is output only if the first match attempt fails. Here is an
+ example of a failure message (the offset 4 that is specified by the
offset modifier is past the end of the subject string):
re> /xyz/
Error -24 (bad offset value)
Note that whereas patterns can be continued over several lines (a plain
- ">" prompt is used for continuations), subject lines may not. However
+ ">" prompt is used for continuations), subject lines may not. However
newlines can be included in a subject by means of the \n escape (or \r,
\r\n, etc., depending on the newline sequence setting).
OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION
When the alternative matching function, pcre2_dfa_match(), is used, the
- output consists of a list of all the matches that start at the first
+ output consists of a list of all the matches that start at the first
point in the subject where there is at least one match. For example:
re> /(tang|tangerine|tan)/
1: tang
2: tan
- Using the normal matching function on this data finds only "tang". The
- longest matching string is always given first (and numbered zero). Af-
- ter a PCRE2_ERROR_PARTIAL return, the output is "Partial match:", fol-
+ Using the normal matching function on this data finds only "tang". The
+ longest matching string is always given first (and numbered zero). Af-
+ ter a PCRE2_ERROR_PARTIAL return, the output is "Partial match:", fol-
lowed by the partially matching substring. Note that this is the entire
- substring that was inspected during the partial match; it may include
+ substring that was inspected during the partial match; it may include
characters before the actual match start if a lookbehind assertion, \b,
or \B was involved. (\K is not supported for DFA matching.)
1: tan
0: tan
- The alternative matching function does not support substring capture,
- so the modifiers that are concerned with captured substrings are not
+ The alternative matching function does not support substring capture,
+ so the modifiers that are concerned with captured substrings are not
relevant.
RESTARTING AFTER A PARTIAL MATCH
- When the alternative matching function has given the PCRE2_ERROR_PAR-
+ When the alternative matching function has given the PCRE2_ERROR_PAR-
TIAL return, indicating that the subject partially matched the pattern,
- you can restart the match with additional subject data by means of the
+ you can restart the match with additional subject data by means of the
dfa_restart modifier. For example:
re> /^\d?\d(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\d\d$/
data> n05\=dfa,dfa_restart
0: n05
- For further information about partial matching, see the pcre2partial
+ For further information about partial matching, see the pcre2partial
documentation.
CALLOUTS
If the pattern contains any callout requests, pcre2test's callout func-
- tion is called during matching unless callout_none is specified. This
+ tion is called during matching unless callout_none is specified. This
works with both matching functions, and with JIT, though there are some
- differences in behaviour. The output for callouts with numerical argu-
+ differences in behaviour. The output for callouts with numerical argu-
ments and those with string arguments is slightly different.
Callouts with numerical arguments
By default, the callout function displays the callout number, the start
- and current positions in the subject text at the callout time, and the
+ and current positions in the subject text at the callout time, and the
next pattern item to be tested. For example:
--->pqrabcdef
0 ^ ^ \d
- This output indicates that callout number 0 occurred for a match at-
- tempt starting at the fourth character of the subject string, when the
- pointer was at the seventh character, and when the next pattern item
- was \d. Just one circumflex is output if the start and current posi-
+ This output indicates that callout number 0 occurred for a match at-
+ tempt starting at the fourth character of the subject string, when the
+ pointer was at the seventh character, and when the next pattern item
+ was \d. Just one circumflex is output if the start and current posi-
tions are the same, or if the current position precedes the start posi-
tion, which can happen if the callout is in a lookbehind assertion.
Callouts numbered 255 are assumed to be automatic callouts, inserted as
a result of the auto_callout pattern modifier. In this case, instead of
- showing the callout number, the offset in the pattern, preceded by a
+ showing the callout number, the offset in the pattern, preceded by a
plus, is output. For example:
re> /\d?[A-E]\*/auto_callout
+12 ^ ^
0: abc
- The mark changes between matching "a" and "b", but stays the same for
- the rest of the match, so nothing more is output. If, as a result of
- backtracking, the mark reverts to being unset, the text "<unset>" is
+ The mark changes between matching "a" and "b", but stays the same for
+ the rest of the match, so nothing more is output. If, as a result of
+ backtracking, the mark reverts to being unset, the text "<unset>" is
output.
Callouts with string arguments
The output for a callout with a string argument is similar, except that
- instead of outputting a callout number before the position indicators,
- the callout string and its offset in the pattern string are output be-
- fore the reflection of the subject string, and the subject string is
+ instead of outputting a callout number before the position indicators,
+ the callout string and its offset in the pattern string are output be-
+ fore the reflection of the subject string, and the subject string is
reflected for each callout. For example:
re> /^ab(?C'first')cd(?C"second")ef/
Callout modifiers
- The callout function in pcre2test returns zero (carry on matching) by
- default, but you can use a callout_fail modifier in a subject line to
+ The callout function in pcre2test returns zero (carry on matching) by
+ default, but you can use a callout_fail modifier in a subject line to
change this and other parameters of the callout (see below).
If the callout_capture modifier is set, the current captured groups are
output when a callout occurs. This is useful only for non-DFA matching,
- as pcre2_dfa_match() does not support capturing, so no captures are
+ as pcre2_dfa_match() does not support capturing, so no captures are
ever shown.
The normal callout output, showing the callout number or pattern offset
- (as described above) is suppressed if the callout_no_where modifier is
+ (as described above) is suppressed if the callout_no_where modifier is
set.
- When using the interpretive matching function pcre2_match() without
- JIT, setting the callout_extra modifier causes additional output from
- pcre2test's callout function to be generated. For the first callout in
- a match attempt at a new starting position in the subject, "New match
- attempt" is output. If there has been a backtrack since the last call-
+ When using the interpretive matching function pcre2_match() without
+ JIT, setting the callout_extra modifier causes additional output from
+ pcre2test's callout function to be generated. For the first callout in
+ a match attempt at a new starting position in the subject, "New match
+ attempt" is output. If there has been a backtrack since the last call-
out (or start of matching if this is the first callout), "Backtrack" is
- output, followed by "No other matching paths" if the backtrack ended
+ output, followed by "No other matching paths" if the backtrack ended
the previous match attempt. For example:
re> /(a+)b/auto_callout,no_start_optimize,no_auto_possess
+1 ^ a+
No match
- Notice that various optimizations must be turned off if you want all
- possible matching paths to be scanned. If no_start_optimize is not
- used, there is an immediate "no match", without any callouts, because
- the starting optimization fails to find "b" in the subject, which it
- knows must be present for any match. If no_auto_possess is not used,
- the "a+" item is turned into "a++", which reduces the number of back-
+ Notice that various optimizations must be turned off if you want all
+ possible matching paths to be scanned. If no_start_optimize is not
+ used, there is an immediate "no match", without any callouts, because
+ the starting optimization fails to find "b" in the subject, which it
+ knows must be present for any match. If no_auto_possess is not used,
+ the "a+" item is turned into "a++", which reduces the number of back-
tracks.
- The callout_extra modifier has no effect if used with the DFA matching
+ The callout_extra modifier has no effect if used with the DFA matching
function, or with JIT.
Return values from callouts
- The default return from the callout function is zero, which allows
+ The default return from the callout function is zero, which allows
matching to continue. The callout_fail modifier can be given one or two
numbers. If there is only one number, 1 is returned instead of 0 (caus-
ing matching to backtrack) when a callout of that number is reached. If
- two numbers (<n>:<m>) are given, 1 is returned when callout <n> is
- reached and there have been at least <m> callouts. The callout_error
+ two numbers (<n>:<m>) are given, 1 is returned when callout <n> is
+ reached and there have been at least <m> callouts. The callout_error
modifier is similar, except that PCRE2_ERROR_CALLOUT is returned, caus-
- ing the entire matching process to be aborted. If both these modifiers
- are set for the same callout number, callout_error takes precedence.
- Note that callouts with string arguments are always given the number
+ ing the entire matching process to be aborted. If both these modifiers
+ are set for the same callout number, callout_error takes precedence.
+ Note that callouts with string arguments are always given the number
zero.
- The callout_data modifier can be given an unsigned or a negative num-
- ber. This is set as the "user data" that is passed to the matching
- function, and passed back when the callout function is invoked. Any
- value other than zero is used as a return from pcre2test's callout
+ The callout_data modifier can be given an unsigned or a negative num-
+ ber. This is set as the "user data" that is passed to the matching
+ function, and passed back when the callout function is invoked. Any
+ value other than zero is used as a return from pcre2test's callout
function.
Inserting callouts can be helpful when using pcre2test to check compli-
- cated regular expressions. For further information about callouts, see
+ cated regular expressions. For further information about callouts, see
the pcre2callout documentation.
NON-PRINTING CHARACTERS
When pcre2test is outputting text in the compiled version of a pattern,
- bytes other than 32-126 are always treated as non-printing characters
+ bytes other than 32-126 are always treated as non-printing characters
and are therefore shown as hex escapes.
- When pcre2test is outputting text that is a matched part of a subject
- string, it behaves in the same way, unless a different locale has been
- set for the pattern (using the locale modifier). In this case, the is-
+ When pcre2test is outputting text that is a matched part of a subject
+ string, it behaves in the same way, unless a different locale has been
+ set for the pattern (using the locale modifier). In this case, the is-
print() function is used to distinguish printing and non-printing char-
acters.
SAVING AND RESTORING COMPILED PATTERNS
- It is possible to save compiled patterns on disc or elsewhere, and re-
- load them later, subject to a number of restrictions. JIT data cannot
- be saved. The host on which the patterns are reloaded must be running
+ It is possible to save compiled patterns on disc or elsewhere, and re-
+ load them later, subject to a number of restrictions. JIT data cannot
+ be saved. The host on which the patterns are reloaded must be running
the same version of PCRE2, with the same code unit width, and must also
- have the same endianness, pointer width and PCRE2_SIZE type. Before
- compiled patterns can be saved they must be serialized, that is, con-
- verted to a stream of bytes. A single byte stream may contain any num-
- ber of compiled patterns, but they must all use the same character ta-
- bles. A single copy of the tables is included in the byte stream (its
+ have the same endianness, pointer width and PCRE2_SIZE type. Before
+ compiled patterns can be saved they must be serialized, that is, con-
+ verted to a stream of bytes. A single byte stream may contain any num-
+ ber of compiled patterns, but they must all use the same character ta-
+ bles. A single copy of the tables is included in the byte stream (its
size is 1088 bytes).
- The functions whose names begin with pcre2_serialize_ are used for se-
- rializing and de-serializing. They are described in the pcre2serialize
- documentation. In this section we describe the features of pcre2test
+ The functions whose names begin with pcre2_serialize_ are used for se-
+ rializing and de-serializing. They are described in the pcre2serialize
+ documentation. In this section we describe the features of pcre2test
that can be used to test these functions.
- Note that "serialization" in PCRE2 does not convert compiled patterns
- to an abstract format like Java or .NET. It just makes a reloadable
+ Note that "serialization" in PCRE2 does not convert compiled patterns
+ to an abstract format like Java or .NET. It just makes a reloadable
byte code stream. Hence the restrictions on reloading mentioned above.
- In pcre2test, when a pattern with push modifier is successfully com-
- piled, it is pushed onto a stack of compiled patterns, and pcre2test
- expects the next line to contain a new pattern (or command) instead of
+ In pcre2test, when a pattern with push modifier is successfully com-
+ piled, it is pushed onto a stack of compiled patterns, and pcre2test
+ expects the next line to contain a new pattern (or command) instead of
a subject line. By contrast, the pushcopy modifier causes a copy of the
- compiled pattern to be stacked, leaving the original available for im-
- mediate matching. By using push and/or pushcopy, a number of patterns
- can be compiled and retained. These modifiers are incompatible with
+ compiled pattern to be stacked, leaving the original available for im-
+ mediate matching. By using push and/or pushcopy, a number of patterns
+ can be compiled and retained. These modifiers are incompatible with
posix, and control modifiers that act at match time are ignored (with a
- message) for the stacked patterns. The jitverify modifier applies only
+ message) for the stacked patterns. The jitverify modifier applies only
at compile time.
The command
#save <filename>
causes all the stacked patterns to be serialized and the result written
- to the named file. Afterwards, all the stacked patterns are freed. The
+ to the named file. Afterwards, all the stacked patterns are freed. The
command
#load <filename>
- reads the data in the file, and then arranges for it to be de-serial-
- ized, with the resulting compiled patterns added to the pattern stack.
- The pattern on the top of the stack can be retrieved by the #pop com-
- mand, which must be followed by lines of subjects that are to be
- matched with the pattern, terminated as usual by an empty line or end
- of file. This command may be followed by a modifier list containing
- only control modifiers that act after a pattern has been compiled. In
- particular, hex, posix, posix_nosub, push, and pushcopy are not al-
- lowed, nor are any option-setting modifiers. The JIT modifiers are,
- however permitted. Here is an example that saves and reloads two pat-
+ reads the data in the file, and then arranges for it to be de-serial-
+ ized, with the resulting compiled patterns added to the pattern stack.
+ The pattern on the top of the stack can be retrieved by the #pop com-
+ mand, which must be followed by lines of subjects that are to be
+ matched with the pattern, terminated as usual by an empty line or end
+ of file. This command may be followed by a modifier list containing
+ only control modifiers that act after a pattern has been compiled. In
+ particular, hex, posix, posix_nosub, push, and pushcopy are not al-
+ lowed, nor are any option-setting modifiers. The JIT modifiers are,
+ however permitted. Here is an example that saves and reloads two pat-
terns.
/abc/push
#pop jit,bincode
abc
- If jitverify is used with #pop, it does not automatically imply jit,
+ If jitverify is used with #pop, it does not automatically imply jit,
which is different behaviour from when it is used on a pattern.
- The #popcopy command is analogous to the pushcopy modifier in that it
+ The #popcopy command is analogous to the pushcopy modifier in that it
makes current a copy of the topmost stack pattern, leaving the original
still on the stack.
REVISION
- Last updated: 27 January 2024
+ Last updated: 24 April 2024
Copyright (c) 1997-2024 University of Cambridge.
-PCRE 10.43 27 January 2024 PCRE2TEST(1)
+PCRE 10.44 24 April 2024 PCRE2TEST(1)
## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
## by inline-source v2019-02-19.15
-# libtool (GNU libtool) 2.4.7.4-1ec8f-dirty
+# libtool (GNU libtool) 2.5.0.1-38c1-dirty
# Provide generalized library-building support services.
# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-# Copyright (C) 1996-2019, 2021-2022 Free Software Foundation, Inc.
+# Copyright (C) 1996-2019, 2021-2024 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
PROGRAM=libtool
PACKAGE=libtool
-VERSION=2.4.7.4-1ec8f-dirty
-package_revision=2.4.7.4
+VERSION=2.5.0.1-38c1-dirty
+package_revision=2.5.0.1
## ------ ##
# This is free software. There is NO warranty; not even for
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
-# Copyright (C) 2004-2019, 2021 Bootstrap Authors
+# Copyright (C) 2004-2019, 2021, 2023 Bootstrap Authors
#
# This file is dual licensed under the terms of the MIT license
-# <https://opensource.org/license/MIT>, and GPL version 2 or later
-# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of
+# <https://opensource.org/licenses/MIT>, and GPL version 2 or later
+# <https://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of
# these licenses when using or redistributing this software or any of
# the files within it. See the URLs above, or the file `LICENSE`
# included in the Bootstrap distribution for the full license texts.
'
IFS="$sp $nl"
-# There are apparently some retarded systems that use ';' as a PATH separator!
+# There are apparently some systems that use ';' as a PATH separator!
if test "${PATH_SEPARATOR+set}" != set; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
# This is free software. There is NO warranty; not even for
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
-# Copyright (C) 2010-2019, 2021 Bootstrap Authors
+# Copyright (C) 2010-2019, 2021, 2023 Bootstrap Authors
#
# This file is dual licensed under the terms of the MIT license
-# <https://opensource.org/license/MIT>, and GPL version 2 or later
-# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of
+# <https://opensource.org/licenses/MIT>, and GPL version 2 or later
+# <https://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of
# these licenses when using or redistributing this software or any of
# the files within it. See the URLs above, or the file `LICENSE`
# included in the Bootstrap distribution for the full license texts.
# End:
# Set a version string.
-scriptversion='(GNU libtool) 2.4.7.4-1ec8f-dirty'
+scriptversion='(GNU libtool) 2.5.0.1-38c1-dirty'
# func_echo ARG...
compiler: $LTCC
compiler flags: $LTCFLAGS
linker: $LD (gnu? $with_gnu_ld)
- version: $progname (GNU libtool) 2.4.7.4-1ec8f-dirty
+ version: $progname (GNU libtool) 2.5.0.1-38c1-dirty
automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
Report bugs to <bug-libtool@gnu.org>.
-GNU libtool home page: <http://www.gnu.org/s/libtool/>.
-General help using GNU software: <http://www.gnu.org/gethelp/>."
+GNU libtool home page: <https://www.gnu.org/s/libtool/>.
+General help using GNU software: <https://www.gnu.org/gethelp/>."
exit 0
}
# preserve --debug
test : = "$debug_cmd" || func_append preserve_args " --debug"
- case $host in
+ case $host_os in
# Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
# see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
- *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+ cygwin* | mingw* | windows* | pw32* | cegcc* | solaris2* | os2*)
# don't eliminate duplications in $postdeps and $predeps
opt_duplicate_compiler_generated_deps=:
;;
# func_convert_core_file_wine_to_w32 ARG
# Helper function used by file name conversion functions when $build is *nix,
-# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# and $host is mingw, windows, cygwin, or some other w32 environment. Relies on a
# correctly configured wine environment available, with the winepath program
# in $build's $PATH.
#
# func_convert_core_path_wine_to_w32 ARG
# Helper function used by path conversion functions when $build is *nix, and
-# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
-# configured wine environment available, with the winepath program in $build's
-# $PATH. Assumes ARG has no leading or trailing path separator characters.
+# $host is mingw, windows, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH. Assumes ARG has no leading or trailing path separator
+# characters.
#
# ARG is path to be converted from $build format to win32.
# Result is available in $func_convert_core_path_wine_to_w32_result.
# On Cygwin there's no "real" PIC flag so we must build both object types
case $host_os in
- cygwin* | mingw* | pw32* | os2* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | os2* | cegcc*)
pic_mode=default
;;
esac
'exit $?'
tstripme=$stripme
case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
case $realname in
*.dll.a)
tstripme=
# Do a test to see if this is really a libtool program.
case $host in
- *cygwin* | *mingw*)
+ *cygwin* | *mingw* | *windows*)
if func_ltwrapper_executable_p "$file"; then
func_ltwrapper_scriptname "$file"
wrapper=$func_ltwrapper_scriptname_result
$RM $export_symbols
eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
case $host in
- *cygwin* | *mingw* | *cegcc* )
+ *cygwin* | *mingw* | *windows* | *cegcc* )
eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
;;
eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
eval '$MV "$nlist"T "$nlist"'
case $host in
- *cygwin* | *mingw* | *cegcc* )
+ *cygwin* | *mingw* | *windows* | *cegcc* )
eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
;;
func_basename "$dlprefile"
name=$func_basename_result
case $host in
- *cygwin* | *mingw* | *cegcc* )
+ *cygwin* | *mingw* | *windows* | *cegcc* )
# if an import library, we need to obtain dlname
if func_win32_import_lib_p "$dlprefile"; then
func_tr_sh "$dlprefile"
# Transform the symbol file into the correct name.
symfileobj=$output_objdir/${my_outputname}S.$objext
case $host in
- *cygwin* | *mingw* | *cegcc* )
+ *cygwin* | *mingw* | *windows* | *cegcc* )
if test -f "$output_objdir/$my_outputname.def"; then
compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
#
# Emit a libtool wrapper script on stdout.
# Don't directly open a file because we may want to
-# incorporate the script contents within a cygwin/mingw
+# incorporate the script contents within a cygwin/mingw/windows
# wrapper executable. Must ONLY be called from within
# func_mode_link because it depends on a number of variables
# set therein.
# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
# variable will take. If 'yes', then the emitted script
# will assume that the directory where it is stored is
-# the $objdir directory. This is a cygwin/mingw-specific
+# the $objdir directory. This is a cygwin/mingw/windows-specific
# behavior.
func_emit_wrapper ()
{
"
case $host in
# Backslashes separate directories on plain windows
- *-*-mingw | *-*-os2* | *-cegcc*)
+ *-*-mingw* | *-*-windows* | *-*-os2* | *-cegcc*)
$ECHO "\
if test -n \"\$lt_option_debug\"; then
\$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
done
- # Usually 'no', except on cygwin/mingw when embedded into
+ # Usually 'no', except on cygwin/mingw/windows when embedded into
# the cwrapper.
WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
#endif
#include <stdio.h>
#include <stdlib.h>
-#ifdef _MSC_VER
+#if defined _WIN32 && !defined __GNUC__
# include <direct.h>
# include <process.h>
# include <io.h>
/* declarations of non-ANSI functions */
#if defined __MINGW32__
# ifdef __STRICT_ANSI__
-int _putenv (const char *);
+_CRTIMP int __cdecl _putenv (const char *);
# endif
#elif defined __CYGWIN__
# ifdef __STRICT_ANSI__
{
EOF
case $host in
- *mingw* | *cygwin* )
+ *mingw* | *windows* | *cygwin* )
# make stdout use "unix" line endings
echo " setmode(1,_O_BINARY);"
;;
{
/* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
namespace, but it is not one of the ones we know about and
- have already dealt with, above (inluding dump-script), then
+ have already dealt with, above (including dump-script), then
report an error. Otherwise, targets might begin to believe
they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
namespace. The first time any user complains about this, we'll
EOF
case $host_os in
- mingw*)
+ mingw* | windows*)
cat <<"EOF"
{
char* p;
EOF
case $host_os in
- mingw*)
+ mingw* | windows*)
cat <<"EOF"
/* execv doesn't actually work on mingw as expected on unix */
newargz = prepare_spawn (newargz);
EOF
case $host_os in
- mingw*)
+ mingw* | windows*)
cat <<"EOF"
/* Prepares an argument vector before calling spawn().
$debug_cmd
case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*)
# It is impossible to link a dll without this setting, and
# we shouldn't force the makefile maintainer to figure out
# what system we are compiling for in order to pass an extra
;;
esac
case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*)
testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
case :$dllsearchpath: in
*":$dir:"*) ;;
-l*)
if test X-lc = "X$arg" || test X-lm = "X$arg"; then
case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
# These systems don't actually have a C or math library (as such)
continue
;;
# These systems don't actually have a C library (as such)
test X-lc = "X$arg" && continue
;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*)
# Do not include libc due to us having libc/libc_r.
test X-lc = "X$arg" && continue
;;
esac
elif test X-lc_r = "X$arg"; then
case $host in
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*)
# Do not include libc_r directly, use -pthread flag.
continue
;;
continue
;;
-mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \
- |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ |-threads|-fopenmp|-fopenmp=*|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
func_append compiler_flags " $arg"
func_append compile_command " $arg"
func_append finalize_command " $arg"
-no-install)
case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
# The PATH hackery in wrapper scripts is required on Windows
# and Darwin in order for the loader to find any dlls it needs.
func_warning "'-no-install' is ignored for $host"
# -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
# -specs=* GCC specs files
# -stdlib=* select c++ std lib with clang
+ # -fdiagnostics-color* simply affects output
+ # -frecord-gcc-switches used to verify flags were respected
# -fsanitize=* Clang/GCC memory and address sanitizer
+ # -fno-sanitize* Clang/GCC memory and address sanitizer
+ # -shared-libsan Link with shared sanitizer runtimes (Clang)
+ # -static-libsan Link with static sanitizer runtimes (Clang)
+ # -no-canonical-prefixes Do not expand any symbolic links
# -fuse-ld=* Linker select flags for GCC
+ # -rtlib=* select c runtime lib with clang
+ # --unwindlib=* select unwinder library with clang
+ # -f{file|debug|macro|profile}-prefix-map=* needed for lto linking
# -Wa,* Pass flags directly to the assembler
# -Werror, -Werror=* Report (specified) warnings as errors
-64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
- -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
- -specs=*|-fsanitize=*|-fuse-ld=*|-Wa,*|-Werror|-Werror=*)
+ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-no-canonical-prefixes| \
+ -stdlib=*|-rtlib=*|--unwindlib=*| \
+ -specs=*|-fsanitize=*|-fno-sanitize*|-shared-libsan|-static-libsan| \
+ -ffile-prefix-map=*|-fdebug-prefix-map=*|-fmacro-prefix-map=*|-fprofile-prefix-map=*| \
+ -fdiagnostics-color*|-frecord-gcc-switches| \
+ -fuse-ld=*|-Wa,*|-Werror|-Werror=*)
func_quote_arg pretty "$arg"
arg=$func_quote_arg_result
func_append compile_command " $arg"
found=false
case $deplib in
-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
- |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ |-threads|-fopenmp|-fopenmp=*|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
if test prog,link = "$linkmode,$pass"; then
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
;;
esac
if $valid_a_lib; then
- echo
- $ECHO "*** Warning: Linking the shared library $output against the"
- $ECHO "*** static library $deplib is not portable!"
+ func_warning "Linking the shared library $output against the static library $deplib is not portable!"
deplibs="$deplib $deplibs"
else
- echo
- $ECHO "*** Warning: Trying to link with static lib archive $deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have"
- echo "*** because the file extensions .$libext of this argument makes me believe"
- echo "*** that it is just a static archive that I should not use here."
+ func_warning "Trying to link with static lib archive $deplib."
+ func_warning "I have the capability to make that library automatically link in when"
+ func_warning "you link to this library. But I can only do this if you have a"
+ func_warning "shared version of the library, which you do not appear to have"
+ func_warning "because the file extensions .$libext of this argument makes me believe"
+ func_warning "that it is just a static archive that I should not use here."
fi
;;
esac
fi
case $host in
# special handling for platforms with PE-DLLs.
- *cygwin* | *mingw* | *cegcc* )
+ *cygwin* | *mingw* | *windows* | *cegcc* )
# Linker will automatically link against shared library if both
# static and shared are present. Therefore, ensure we extract
# symbols from the import library if a shared library is present
fi
if test -n "$library_names" &&
{ test no = "$use_static_libs" || test -z "$old_library"; }; then
- case $host in
- *cygwin* | *mingw* | *cegcc* | *os2*)
+ case $host_os in
+ cygwin* | mingw* | windows* | cegcc* | os2*)
# No point in relinking DLLs because paths are not encoded
func_append notinst_deplibs " $lib"
need_relink=no
if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
echo
if test prog = "$linkmode"; then
- $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ func_warning "Linking the executable $output against the loadable module"
else
- $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ func_warning "Linking the shared library $output against the loadable module"
fi
- $ECHO "*** $linklib is not portable!"
+ func_warning "$linklib is not portable!"
fi
if test lib = "$linkmode" &&
test yes = "$hardcode_into_libs"; then
soname=$dlname
elif test -n "$soname_spec"; then
# bleh windows
- case $host in
- *cygwin* | mingw* | *cegcc* | *os2*)
+ case $host_os in
+ cygwin* | mingw* | windows* | cegcc* | os2*)
func_arith $current - $age
major=$func_arith_result
versuffix=-$major
if /usr/bin/file -L $add 2> /dev/null |
$GREP ": [^:]* bundle" >/dev/null; then
if test "X$dlopenmodule" != "X$lib"; then
- $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ func_warning "lib $linklib is a module, not a shared library"
if test -z "$old_library"; then
- echo
- echo "*** And there doesn't seem to be a static archive available"
- echo "*** The link will probably fail, sorry"
+ func_warning "And there doesn't seem to be a static archive available"
+ func_warning "The link will probably fail, sorry"
else
add=$dir/$old_library
fi
# Just print a warning and add the library to dependency_libs so
# that the program can be linked against the static library.
- echo
- $ECHO "*** Warning: This system cannot link to static lib archive $lib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
+ func_warning "This system cannot link to static lib archive $lib."
+ func_warning "I have the capability to make that library automatically link in when"
+ func_warning "you link to this library. But I can only do this if you have a"
+ func_warning "shared version of the library, which you do not appear to have."
if test yes = "$module"; then
- echo "*** But as you try to build a module library, libtool will still create "
- echo "*** a static module, that should work as long as the dlopening application"
- echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ func_warning "But as you try to build a module library, libtool will still create "
+ func_warning "a static module, that should work as long as the dlopening application"
+ func_warning "is linked with the -dlopen flag to resolve symbols at runtime."
if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ func_warning "However, this would only work if libtool was able to extract symbol"
+ func_warning "lists from a program, using 'nm' or equivalent, but libtool could"
+ func_warning "not find such a program. So, this module is probably useless."
+ func_warning "'nm' from GNU binutils and a full rebuild may help."
fi
if test no = "$build_old_libs"; then
build_libtool_libs=module
if test pass_all != "$deplibs_check_method"; then
func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
else
- echo
- $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
- $ECHO "*** objects $objs is not portable!"
+ func_warning "Linking the shared library $output against the non-libtool objects $objs is not portable!"
func_append libobjs " $objs"
fi
fi
#
case $version_type in
# correct linux to gnu/linux during the next big refactor
- darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none)
+ darwin|freebsd-elf|linux|midnightbsd-elf|osf|qnx|windows|none)
func_arith $number_major + $number_minor
current=$func_arith_result
age=$number_minor
revision=$number_revision
;;
- freebsd-aout|qnx|sunos)
+ freebsd-aout|sco|sunos)
current=$number_major
revision=$number_minor
age=0
;;
qnx)
- major=.$current
- versuffix=.$current
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
;;
sco)
if test yes = "$build_libtool_libs"; then
if test -n "$rpath"; then
case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
# these systems don't actually have a c library (as such)!
;;
*-*-rhapsody* | *-*-darwin1.[012])
# implementing what was already the behavior.
newdeplibs=$deplibs
;;
- test_compile)
- # This code stresses the "libraries are programs" paradigm to its
- # limits. Maybe even breaks it. We compile a program, linking it
- # against the deplibs as a proxy for the library. Then we can check
- # whether they linked in statically or dynamically with ldd.
- $opt_dry_run || $RM conftest.c
- cat > conftest.c <<EOF
- int main() { return 0; }
-EOF
- $opt_dry_run || $RM conftest
- if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
- ldd_output=`ldd conftest`
- for i in $deplibs; do
- case $i in
- -l*)
- func_stripname -l '' "$i"
- name=$func_stripname_result
- if test yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $i "*)
- func_append newdeplibs " $i"
- i=
- ;;
- esac
- fi
- if test -n "$i"; then
- libname=`eval "\\$ECHO \"$libname_spec\""`
- deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
- set dummy $deplib_matches; shift
- deplib_match=$1
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
- func_append newdeplibs " $i"
- else
- droppeddeps=yes
- echo
- $ECHO "*** Warning: dynamic linker does not accept needed library $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which I believe you do not have"
- echo "*** because a test_compile did reveal that the linker did not use it for"
- echo "*** its dynamic dependency list that programs get resolved with at runtime."
- fi
- fi
- ;;
- *)
- func_append newdeplibs " $i"
- ;;
- esac
- done
- else
- # Error occurred in the first compile. Let's try to salvage
- # the situation: Compile a separate program for each library.
- for i in $deplibs; do
- case $i in
- -l*)
- func_stripname -l '' "$i"
- name=$func_stripname_result
- $opt_dry_run || $RM conftest
- if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
- ldd_output=`ldd conftest`
- if test yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $i "*)
- func_append newdeplibs " $i"
- i=
- ;;
- esac
- fi
- if test -n "$i"; then
- libname=`eval "\\$ECHO \"$libname_spec\""`
- deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
- set dummy $deplib_matches; shift
- deplib_match=$1
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
- func_append newdeplibs " $i"
- else
- droppeddeps=yes
- echo
- $ECHO "*** Warning: dynamic linker does not accept needed library $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have"
- echo "*** because a test_compile did reveal that the linker did not use this one"
- echo "*** as a dynamic dependency that programs can get resolved with at runtime."
- fi
- fi
- else
- droppeddeps=yes
- echo
- $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
- echo "*** make it link in! You will probably need to install it or some"
- echo "*** library that it depends on before this library will be fully"
- echo "*** functional. Installing it before continuing would be even better."
- fi
- ;;
- *)
- func_append newdeplibs " $i"
- ;;
- esac
- done
- fi
- ;;
file_magic*)
set dummy $deplibs_check_method; shift
file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
fi
if test -n "$a_deplib"; then
droppeddeps=yes
- echo
- $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have"
- echo "*** because I did check the linker path looking for a file starting"
+ func_warning "Linker path does not have real file for library $a_deplib."
+ func_warning "I have the capability to make that library automatically link in when"
+ func_warning "you link to this library. But I can only do this if you have a"
+ func_warning "shared version of the library, which you do not appear to have"
+ func_warning "because I did check the linker path looking for a file starting"
if test -z "$potlib"; then
- $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ func_warning "with $libname but no candidates were found. (...for file magic test)"
else
- $ECHO "*** with $libname and none of the candidates passed a file format test"
- $ECHO "*** using a file magic. Last file checked: $potlib"
+ func_warning "with $libname and none of the candidates passed a file format test"
+ func_warning "using a file magic. Last file checked: $potlib"
fi
fi
;;
fi
if test -n "$a_deplib"; then
droppeddeps=yes
- echo
- $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have"
- echo "*** because I did check the linker path looking for a file starting"
+ func_warning "Linker path does not have real file for library $a_deplib."
+ func_warning "I have the capability to make that library automatically link in when"
+ func_warning "you link to this library. But I can only do this if you have a"
+ func_warning "shared version of the library, which you do not appear to have"
+ func_warning "because I did check the linker path looking for a file starting"
if test -z "$potlib"; then
- $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ func_warning "with $libname but no candidates were found. (...for regex pattern test)"
else
- $ECHO "*** with $libname and none of the candidates passed a file format test"
- $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ func_warning "with $libname and none of the candidates passed a file format test"
+ func_warning "using a regex pattern. Last file checked: $potlib"
fi
fi
;;
*[!\ \ ]*)
echo
if test none = "$deplibs_check_method"; then
- echo "*** Warning: inter-library dependencies are not supported in this platform."
+ func_warning "Inter-library dependencies are not supported in this platform."
else
- echo "*** Warning: inter-library dependencies are not known to be supported."
+ func_warning "Inter-library dependencies are not known to be supported."
fi
- echo "*** All declared inter-library dependencies are being dropped."
+ func_warning "All declared inter-library dependencies are being dropped."
droppeddeps=yes
;;
esac
if test yes = "$droppeddeps"; then
if test yes = "$module"; then
- echo
- echo "*** Warning: libtool could not satisfy all declared inter-library"
- $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
- echo "*** a static module, that should work as long as the dlopening"
- echo "*** application is linked with the -dlopen flag."
+ func_warning "libtool could not satisfy all declared inter-library"
+ func_warning "dependencies of module $libname. Therefore, libtool will create"
+ func_warning "a static module, that should work as long as the dlopening"
+ func_warning "application is linked with the -dlopen flag."
if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ func_warning "However, this would only work if libtool was able to extract symbol"
+ func_warning "lists from a program, using 'nm' or equivalent, but libtool could"
+ func_warning "not find such a program. So, this module is probably useless."
+ func_warning "'nm' from GNU binutils and a full rebuild may help."
fi
if test no = "$build_old_libs"; then
oldlibs=$output_objdir/$libname.$libext
orig_export_symbols=
case $host_os in
- cygwin* | mingw* | cegcc*)
+ cygwin* | mingw* | windows* | cegcc*)
if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
# exporting using user supplied symfile
func_dll_def_p "$export_symbols" || {
esac
fi
case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*)
testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
case :$dllsearchpath: in
*":$libdir:"*) ;;
# Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
wrappers_required=false
;;
- *cygwin* | *mingw* )
+ *cygwin* | *mingw* | *windows* )
test yes = "$build_libtool_libs" || wrappers_required=false
;;
*)
*) exeext= ;;
esac
case $host in
- *cygwin* | *mingw* )
+ *cygwin* | *mingw* | windows* )
func_dirname_and_basename "$output" "" "."
output_name=$func_basename_result
output_path=$func_dirname_result
# tests/bindir.at for full details.
tdlname=$dlname
case $host,$output,$installed,$module,$dlname in
- *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *windows*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
# If a -bindir argument was supplied, place the dll there.
if test -n "$bindir"; then
func_relative_path "$install_libdir" "$bindir"
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
#
-# Copyright (C) 1996-2001, 2003-2019, 2021-2022 Free Software
+# Copyright (C) 1996-2001, 2003-2019, 2021-2024 Free Software
# Foundation, Inc.
# Written by Gordon Matzigkeit, 1996
#
# modifications, as long as this notice is preserved.
m4_define([_LT_COPYING], [dnl
-# Copyright (C) 2014 Free Software Foundation, Inc.
+# Copyright (C) 2024 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# GNU Libtool is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# As a special exception to the GNU General Public License, if you
# along with this program. If not, see <http://www.gnu.org/licenses/>.
])
-# serial 59 LT_INIT
+# serial 61 LT_INIT
# LT_PREREQ(VERSION)
# LT_OUTPUT
# ---------
# This macro allows early generation of the libtool script (before
-# AC_OUTPUT is called), incase it is used in configure for compilation
+# AC_OUTPUT is called), in case it is used in configure for compilation
# tests.
AC_DEFUN([LT_OUTPUT],
[: ${CONFIG_LT=./config.lt}
m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
configured by $[0], generated by m4_PACKAGE_STRING.
-Copyright (C) 2011 Free Software Foundation, Inc.
+Copyright (C) 2024 Free Software Foundation, Inc.
This config.lt script is free software; the Free Software Foundation
-gives unlimited permision to copy, distribute and modify it."
+gives unlimited permission to copy, distribute and modify it."
while test 0 != $[#]
do
case $with_sysroot in #(
yes)
if test yes = "$GCC"; then
- lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ # Trim trailing / since we'll always append absolute paths and we want
+ # to avoid //, if only for less confusing output for the user.
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'`
fi
;; #(
/*)
;;
x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*)
# Find out what ABI is being produced by ac_compile, and set linker
# options accordingly. Note that the listed cases only cover the
# situations where additional linker options are needed (such as when
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_i386_fbsd"
;;
- x86_64-*linux*)
+ x86_64-*linux*|x86_64-gnu*)
case `$FILECMD conftest.o` in
*x86-64*)
LD="${LD-ld} -m elf32_x86_64"
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_x86_64_fbsd"
;;
- x86_64-*linux*)
+ x86_64-*linux*|x86_64-gnu*)
LD="${LD-ld} -m elf_x86_64"
;;
powerpcle-*linux*)
# Use ARFLAGS variable as AR's operation code to sync the variable naming with
# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have
-# higher priority because thats what people were doing historically (setting
+# higher priority because that's what people were doing historically (setting
# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS
# variable obsoleted/removed.
old_postuninstall_cmds=
if test -n "$RANLIB"; then
- case $host_os in
- bitrig* | openbsd*)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
- ;;
- *)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
- ;;
- esac
old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
fi
case $host_os in
lt_cv_sys_max_cmd_len=-1;
;;
- cygwin* | mingw* | cegcc*)
+ cygwin* | mingw* | windows* | cegcc*)
# On Win9x/ME, this test blows up -- it succeeds, but takes
# about 5 minutes as the teststring grows exponentially.
# Worse, since 9x/ME are not pre-emptively multitasking,
lt_cv_sys_max_cmd_len=8192;
;;
- bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*)
+ darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
lt_cv_dlopen_self=yes
;;
- mingw* | pw32* | cegcc*)
+ mingw* | windows* | pw32* | cegcc*)
lt_cv_dlopen=LoadLibrary
lt_cv_dlopen_libs=
;;
*) lt_awk_arg='/^libraries:/' ;;
esac
case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+ mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
*) lt_sed_strip_eq='s|=/|/|g' ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
# AWK program above erroneously prepends '/' to C:/dos/paths
# for these hosts.
case $host_os in
- mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
$SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
esac
sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
# libtool to hard-code these into programs
;;
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
version_type=windows
shrext_cmds=.dll
need_version=no
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
;;
- mingw* | cegcc*)
+ mingw* | windows* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
;;
library_names_spec='$libname.dll.lib'
case $build_os in
- mingw*)
+ mingw* | windows*)
sys_lib_search_path_spec=
lt_save_ifs=$IFS
IFS=';'
version_type=none # Android doesn't support versioned libraries.
need_lib_prefix=no
need_version=no
- library_names_spec='$libname$release$shared_ext'
+ library_names_spec='$libname$release$shared_ext $libname$shared_ext'
soname_spec='$libname$release$shared_ext'
finish_cmds=
shlibpath_var=LD_LIBRARY_PATH
hardcode_into_libs=yes
dynamic_linker='Android linker'
- # Don't embed -rpath directories since the linker doesn't support them.
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ # -rpath works at least for libraries that are not overridden by
+ # libraries installed in system locations.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
;;
# This must be glibc/ELF.
# before this can be enabled.
hardcode_into_libs=yes
- # Ideally, we could use ldconfig to report *all* directores which are
+ # Ideally, we could use ldconfig to report *all* directories which are
# searched for libraries, however this is still not possible. Aside from not
# being certain /sbin/ldconfig is available, command
# 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
dynamic_linker='ldqnx.so'
;;
-openbsd* | bitrig*)
+openbsd*)
version_type=sunos
sys_lib_dlsearch_path_spec=/usr/lib
need_lib_prefix=no
# Check if gcc -print-prog-name=ld gives a path.
AC_MSG_CHECKING([for ld used by $CC])
case $host in
- *-*-mingw*)
+ *-*-mingw* | *-*-windows*)
# gcc leaves a trailing carriage return, which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
if test yes != "$GCC"; then
reload_cmds=false
fi
# 'none' -- dependencies not supported.
# 'unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
# 'file_magic [[regex]]' -- check by looking for files in library path
# that responds to the $file_magic_cmd with a given extended regex.
# If you have 'file' or equivalent on your system and you're not sure
lt_cv_file_magic_cmd='func_win32_libid'
;;
-mingw* | pw32*)
+mingw* | windows* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
# func_win32_libid shell function, so use a weaker test based on 'objdump',
# unless we find 'file', for example because we are cross-compiling.
lt_cv_deplibs_check_method=pass_all
;;
-openbsd* | bitrig*)
+openbsd*)
if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
else
want_nocaseglob=no
if test "$build" = "$host"; then
case $host_os in
- mingw* | pw32*)
+ mingw* | windows* | pw32*)
if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
want_nocaseglob=yes
else
# Tru64's nm complains that /dev/null is an invalid object file
# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
case $build_os in
- mingw*) lt_bad_file=conftest.nm/nofile ;;
+ mingw* | windows*) lt_bad_file=conftest.nm/nofile ;;
*) lt_bad_file=/dev/null ;;
esac
case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in
[lt_cv_sharedlib_from_linklib_cmd='unknown'
case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
# two different shell functions defined in ltmain.sh;
# decide which one to use based on capabilities of $DLLTOOL
case `$DLLTOOL --help 2>&1` in
m4_defun([_LT_PATH_MANIFEST_TOOL],
[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
- [lt_cv_path_mainfest_tool=no
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_manifest_tool],
+ [lt_cv_path_manifest_tool=no
echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
$MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
cat conftest.err >&AS_MESSAGE_LOG_FD
if $GREP 'Manifest Tool' conftest.out > /dev/null; then
- lt_cv_path_mainfest_tool=yes
+ lt_cv_path_manifest_tool=yes
fi
rm -f conftest*])
-if test yes != "$lt_cv_path_mainfest_tool"; then
+if test yes != "$lt_cv_path_manifest_tool"; then
MANIFEST_TOOL=:
fi
_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
LIBM=
case $host in
-*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-mingw* | *-*-pw32* | *-*-darwin*)
# These system don't have libm, or don't need it
;;
*-ncr-sysv4.3*)
aix*)
symcode='[[BCDT]]'
;;
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
symcode='[[ABCDGISTW]]'
;;
hpux*)
symcode='[[BCDEGQRST]]'
;;
solaris*)
- symcode='[[BDRT]]'
+ symcode='[[BCDRT]]'
;;
sco3.2v5*)
symcode='[[DT]]'
# Handle CRLF in mingw tool chain
opt_cr=
case $build_os in
-mingw*)
+mingw* | windows*)
opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
;;
esac
beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
# PIC is the default for these OSes.
;;
- mingw* | cygwin* | os2* | pw32* | cegcc*)
+ mingw* | windows* | cygwin* | os2* | pw32* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
;;
esac
;;
- mingw* | cygwin* | os2* | pw32* | cegcc*)
+ mingw* | windows* | cygwin* | os2* | pw32* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
m4_if([$1], [GCJ], [],
# PIC is the default for these OSes.
;;
- mingw* | cygwin* | pw32* | os2* | cegcc*)
+ mingw* | windows* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
esac
;;
- mingw* | cygwin* | pw32* | os2* | cegcc*)
+ mingw* | windows* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
m4_if([$1], [GCJ], [],
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
+ *flang)
+ # Flang compiler.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
# icc used to be incompatible with GCC.
# ICC 10 doesn't accept -KPIC any more.
icc* | ifort*)
pw32*)
_LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
;;
- cygwin* | mingw* | cegcc*)
+ cygwin* | mingw* | windows* | cegcc*)
case $cc_basename in
cl* | icl*)
_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
extract_expsyms_cmds=
case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
# FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++ or Intel C++ Compiler.
# we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
with_gnu_ld=yes
;;
- openbsd* | bitrig*)
+ openbsd*)
with_gnu_ld=no
;;
esac
fi
;;
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='@'
;;
_LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
;;
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++ or Intel C++ Compiler.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# Tell ltmain to make .dll files, not .so files.
shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_cmds, $1)='$CC -Fe $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
cp "$export_symbols" "$output_objdir/$soname.def";
echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
else
$SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ $CC -Fe $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
*nto* | *qnx*)
;;
- openbsd* | bitrig*)
+ openbsd*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='@'
;;
_LT_TAGDECL([], [hardcode_direct_absolute], [0],
[Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
DIR into the resulting binary and the resulting library dependency is
- "absolute", i.e impossible to change by setting $shlibpath_var if the
+ "absolute", i.e. impossible to change by setting $shlibpath_var if the
library is relocated])
_LT_TAGDECL([], [hardcode_minus_L], [0],
[Set to "yes" if using the -LDIR flag during linking hardcodes DIR
wlarc='$wl'
# ancient GNU ld didn't support --whole-archive et. al.
- if eval "`$CC -print-prog-name=ld` --help 2>&1" |
- $GREP 'no-whole-archive' > /dev/null; then
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
_LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
else
GXX=no
esac
;;
- cygwin* | mingw* | pw32* | cegcc*)
+ cygwin* | mingw* | windows* | pw32* | cegcc*)
case $GXX,$cc_basename in
,cl* | no,cl* | ,icl* | no,icl*)
# Native MSVC or ICC
cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
_LT_TAGVAR(file_list_spec, $1)='@'
;;
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
if test yes = "$GXX"; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
if test yes = "$GXX"; then
_LT_TAGVAR(ld_shlibs, $1)=yes
;;
- openbsd* | bitrig*)
+ openbsd*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
else
# FIXME: insert proper C++ library support
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
else
# g++ 2.7 appears to require '-G' NOT '-shared' on this
# platform.
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
- output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
fi
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
case $prev$p in
-L* | -R* | -l*)
- # Some compilers place space between "-{L,R}" and the path.
+ # Some compilers place space between "-{L,R,l}" and the path.
# Remove the space.
- if test x-L = "$p" ||
- test x-R = "$p"; then
+ if test x-L = x"$p" ||
+ test x-R = x"$p" ||
+ test x-l = x"$p"; then
prev=$p
continue
fi
# ----------------
# Check for a file(cmd) program that can be used to detect file type and magic
m4_defun([_LT_DECL_FILECMD],
-[AC_CHECK_TOOL([FILECMD], [file], [:])
+[AC_CHECK_PROG([FILECMD], [file], [:])
_LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types])
])# _LD_DECL_FILECMD
_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
[Sed that helps us avoid accidentally triggering echo(1) options like -n])
])# _LT_DECL_SED
-
-m4_ifndef([AC_PROG_SED], [
-############################################################
-# NOTE: This macro has been submitted for inclusion into #
-# GNU Autoconf as AC_PROG_SED. When it is available in #
-# a released version of Autoconf we should remove this #
-# macro and use it instead. #
-############################################################
-
-m4_defun([AC_PROG_SED],
-[AC_MSG_CHECKING([for a sed that does not truncate output])
-AC_CACHE_VAL(lt_cv_path_SED,
-[# Loop through the user's path and test for sed and gsed.
-# Then use that list of sed's as ones to test for truncation.
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for lt_ac_prog in sed gsed; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
- lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
- fi
- done
- done
-done
-IFS=$as_save_IFS
-lt_ac_max=0
-lt_ac_count=0
-# Add /usr/xpg4/bin/sed as it is typically found on Solaris
-# along with /bin/sed that truncates output.
-for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
- test ! -f "$lt_ac_sed" && continue
- cat /dev/null > conftest.in
- lt_ac_count=0
- echo $ECHO_N "0123456789$ECHO_C" >conftest.in
- # Check for GNU sed and select it if it is found.
- if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
- lt_cv_path_SED=$lt_ac_sed
- break
- fi
- while true; do
- cat conftest.in conftest.in >conftest.tmp
- mv conftest.tmp conftest.in
- cp conftest.in conftest.nl
- echo >>conftest.nl
- $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
- cmp -s conftest.out conftest.nl || break
- # 10000 chars as input seems more than enough
- test 10 -lt "$lt_ac_count" && break
- lt_ac_count=`expr $lt_ac_count + 1`
- if test "$lt_ac_count" -gt "$lt_ac_max"; then
- lt_ac_max=$lt_ac_count
- lt_cv_path_SED=$lt_ac_sed
- fi
- done
-done
-])
-SED=$lt_cv_path_SED
-AC_SUBST([SED])
-AC_MSG_RESULT([$SED])
-])#AC_PROG_SED
-])#m4_ifndef
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([LT_AC_PROG_SED], [])
[case $host in
*-*-mingw* )
case $build in
- *-*-mingw* ) # actually msys
+ *-*-mingw* | *-*-windows* ) # actually msys
lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
;;
*-*-cygwin* )
;;
*-*-cygwin* )
case $build in
- *-*-mingw* ) # actually msys
+ *-*-mingw* | *-*-windows* ) # actually msys
lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
;;
*-*-cygwin* )
[#assume ordinary cross tools, or native build.
lt_cv_to_tool_file_cmd=func_convert_file_noop
case $host in
- *-*-mingw* )
+ *-*-mingw* | *-*-windows* )
case $build in
- *-*-mingw* ) # actually msys
+ *-*-mingw* | *-*-windows* ) # actually msys
lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
;;
esac
# Helper functions for option handling. -*- Autoconf -*-
#
-# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free
+# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2024 Free
# Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
-# serial 8 ltoptions.m4
+# serial 9 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
[enable_win32_dll=yes
case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
-# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software
+# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2024 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
-# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation,
+# Copyright (C) 2004, 2011-2019, 2021-2024 Free Software Foundation,
# Inc.
# Written by Scott James Remnant, 2004
#
# @configure_input@
-# serial 4249 ltversion.m4
+# serial 4337 ltversion.m4
# This file is part of GNU Libtool
-m4_define([LT_PACKAGE_VERSION], [2.4.7.4-1ec8f-dirty])
-m4_define([LT_PACKAGE_REVISION], [2.4.7.4])
+m4_define([LT_PACKAGE_VERSION], [2.5.0.1-38c1-dirty])
+m4_define([LT_PACKAGE_REVISION], [2.5.0.1])
AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.7.4-1ec8f-dirty'
-macro_revision='2.4.7.4'
+[macro_version='2.5.0.1-38c1-dirty'
+macro_revision='2.5.0.1'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
-# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free
+# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2024 Free
# Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
else
AC_DEFINE(PCRE2_EXPORT, [], [to make a symbol visible])
fi
+ else
+ AC_DEFINE(PCRE2_EXPORT, [], [to make a symbol visible])
fi
AC_SUBST([VISIBILITY_CFLAGS])
AC_SUBST([VISIBILITY_CXXFLAGS])
Care must be taken if it is increased, because it guards against integer
overflow caused by enormously large patterns. */
#ifndef MAX_NAME_SIZE
-#define MAX_NAME_SIZE 32
+#define MAX_NAME_SIZE 128
#endif
/* The value of MAX_VARLOOKBEHIND specifies the default maximum length, in
#define PACKAGE_NAME "PCRE2"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "PCRE2 10.43"
+#define PACKAGE_STRING "PCRE2 10.44"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pcre2"
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "10.43"
+#define PACKAGE_VERSION "10.44"
/* 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
#endif
/* Version number of package */
-#define VERSION "10.43"
+#define VERSION "10.44"
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* The current PCRE version information. */
#define PCRE2_MAJOR 10
-#define PCRE2_MINOR 43
+#define PCRE2_MINOR 44
#define PCRE2_PRERELEASE
-#define PCRE2_DATE 2024-02-16
+#define PCRE2_DATE 2024-06-07
/* 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
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_pattern_compiled_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 \
#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_max_pattern_compiled_length PCRE2_SUFFIX(pcre2_set_max_pattern_compiled_length_)
#define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_)
#define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)
#define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_)
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_pattern_compiled_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 \
#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_max_pattern_compiled_length PCRE2_SUFFIX(pcre2_set_max_pattern_compiled_length_)
#define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_)
#define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)
#define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_)
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-2023 University of Cambridge
+ New API code Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70,
ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80,
ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90,
- ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99, ERR100 };
+ ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99, ERR100,
+ ERR101 };
/* This is a table of start-of-pattern options such as (*UTF) and settings such
as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward
if (lengthptr != NULL)
{
PCRE2_SIZE delta;
- if (PRIV(ckd_smul)(&delta, repeat_min - 1, length_prevgroup) ||
+ if (PRIV(ckd_smul)(&delta, repeat_min - 1,
+ (int)length_prevgroup) ||
OFLOW_MAX - *lengthptr < delta)
{
*errorcodeptr = ERR20;
{
PCRE2_SIZE delta;
if (PRIV(ckd_smul)(&delta, repeat_max,
- length_prevgroup + 1 + 2 + 2*LINK_SIZE) ||
+ (int)length_prevgroup + 1 + 2 + 2*LINK_SIZE) ||
OFLOW_MAX + (2 + 2*LINK_SIZE) - *lengthptr < delta)
{
*errorcodeptr = ERR20;
*bptr |= branchlength; /* branchlength never more than 65535 */
bptr = *pptrptr;
}
-while (*bptr == META_ALT);
+while (META_CODE(*bptr) == META_ALT);
/* If any branch is of variable length, the whole lookbehind is of variable
length. If the maximum length of any branch exceeds the maximum for variable
goto HAD_CB_ERROR;
}
-/* Compute the size of, and then get and initialize, the data block for storing
-the compiled pattern and names table. Integer overflow should no longer be
-possible because nowadays we limit the maximum value of cb.names_found and
-cb.name_entry_size. */
+/* Compute the size of, then, if not too large, get and initialize the data
+block for storing the compiled pattern and names table. Integer overflow should
+no longer be possible because nowadays we limit the maximum value of
+cb.names_found and cb.name_entry_size. */
re_blocksize = sizeof(pcre2_real_code) +
CU2BYTES(length +
(PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size);
+
+if (re_blocksize > ccontext->max_pattern_compiled_length)
+ {
+ errorcode = ERR101;
+ goto HAD_CB_ERROR;
+ }
+
re = (pcre2_real_code *)
ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
if (re == NULL)
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-2023 University of Cambridge
+ New API code Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
NULL, /* Stack guard data */
PRIV(default_tables), /* Character tables */
PCRE2_UNSET, /* Max pattern length */
+ PCRE2_UNSET, /* Max pattern compiled length */
BSR_DEFAULT, /* Backslash R default */
NEWLINE_DEFAULT, /* Newline convention */
PARENS_NEST_LIMIT, /* As it says */
return 0;
}
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_max_pattern_compiled_length(pcre2_compile_context *ccontext, PCRE2_SIZE length)
+{
+ccontext->max_pattern_compiled_length = length;
+return 0;
+}
+
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_set_newline(pcre2_compile_context *ccontext, uint32_t newline)
{
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-2023 University of Cambridge
+ New API code Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
"\\K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)\0"
/* 100 */
"branch too long in variable-length lookbehind assertion\0"
+ "compiled pattern would be longer than the limit set by the application\0"
;
/* Match-time and UTF error texts are in the same format. */
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-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
* Match an extended grapheme sequence *
*************************************************/
-/*
+/* NOTE: The logic contained in this function is replicated in three special-
+purpose functions in the pcre2_jit_compile.c module. If the logic below is
+changed, they must be kept in step so that the interpreter and the JIT have the
+same behaviour.
+
Arguments:
c the first character
eptr pointer to next character
PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
PCRE2_SPTR end_subject, BOOL utf, int *xcount)
{
+BOOL was_ep_ZWJ = FALSE;
int lgb = UCD_GRAPHBREAK(c);
while (eptr < end_subject)
rgb = UCD_GRAPHBREAK(c);
if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
+ /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was
+ preceded by Extended Pictographic. */
+
+ if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ)
+ break;
+
/* Not breaking between Regional Indicators is allowed only if there
are an even number of preceding RIs. */
if ((ricount & 1) != 0) break; /* Grapheme break required */
}
- /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
- allows any number of them before a following Extended_Pictographic. */
+ /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in
+ between; see next statement). */
+
+ was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ);
+
+ /* If Extend follows Extended_Pictographic, do not update lgb; this allows
+ any number of them before a following ZWJ. */
- if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
- lgb != ucp_gbExtended_Pictographic)
- lgb = rgb;
+ if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic) lgb = rgb;
eptr += len;
if (xcount != NULL) *xcount += 1;
Written by Philip Hazel, October 2016
Updated February 2024 (Addison Crump added 16-bit/32-bit and JIT support)
+Further updates March/April/May 2024 by PH
***************************************************************************/
#include <errno.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#define STACK_SIZE_MB 256
+#define JIT_SIZE_LIMIT (200 * 1024)
#ifndef PCRE2_CODE_UNIT_WIDTH
#define PCRE2_CODE_UNIT_WIDTH 8
#include "config.h"
#include "pcre2.h"
+#include "pcre2_internal.h"
#define MAX_MATCH_SIZE 1000
#define DFA_WORKSPACE_COUNT 100
+/* When adding new compile or match options, remember to update the functions
+below that output them. */
+
#define ALLOWED_COMPILE_OPTIONS \
(PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \
PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \
- PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_ENDANCHORED|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \
+ PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_ENDANCHORED|PCRE2_EXTENDED| \
+ PCRE2_EXTENDED_MORE|PCRE2_FIRSTLINE| \
PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \
PCRE2_NO_AUTO_CAPTURE| \
PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \
PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \
PCRE2_PARTIAL_SOFT)
+#define BASE_MATCH_OPTIONS \
+ (PCRE2_NO_JIT|PCRE2_DISABLE_RECURSELOOP_CHECK)
+
+
#if defined(SUPPORT_DIFF_FUZZ) || defined(STANDALONE)
static void print_compile_options(FILE *stream, uint32_t compile_options)
{
-fprintf(stream, "Compile options %.8x never_backslash_c", compile_options);
-fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
- ((compile_options & PCRE2_ALT_BSUX) != 0)? ",alt_bsux" : "",
- ((compile_options & PCRE2_ALT_CIRCUMFLEX) != 0)? ",alt_circumflex" : "",
- ((compile_options & PCRE2_ALT_VERBNAMES) != 0)? ",alt_verbnames" : "",
- ((compile_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? ",allow_empty_class" : "",
- ((compile_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
- ((compile_options & PCRE2_AUTO_CALLOUT) != 0)? ",auto_callout" : "",
- ((compile_options & PCRE2_CASELESS) != 0)? ",caseless" : "",
- ((compile_options & PCRE2_DOLLAR_ENDONLY) != 0)? ",dollar_endonly" : "",
- ((compile_options & PCRE2_DOTALL) != 0)? ",dotall" : "",
- ((compile_options & PCRE2_DUPNAMES) != 0)? ",dupnames" : "",
- ((compile_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
- ((compile_options & PCRE2_EXTENDED) != 0)? ",extended" : "",
- ((compile_options & PCRE2_FIRSTLINE) != 0)? ",firstline" : "",
- ((compile_options & PCRE2_MATCH_UNSET_BACKREF) != 0)? ",match_unset_backref" : "",
- ((compile_options & PCRE2_MULTILINE) != 0)? ",multiline" : "",
- ((compile_options & PCRE2_NEVER_UCP) != 0)? ",never_ucp" : "",
- ((compile_options & PCRE2_NEVER_UTF) != 0)? ",never_utf" : "",
- ((compile_options & PCRE2_NO_AUTO_CAPTURE) != 0)? ",no_auto_capture" : "",
- ((compile_options & PCRE2_NO_AUTO_POSSESS) != 0)? ",no_auto_possess" : "",
- ((compile_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? ",no_dotstar_anchor" : "",
- ((compile_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
- ((compile_options & PCRE2_NO_START_OPTIMIZE) != 0)? ",no_start_optimize" : "",
- ((compile_options & PCRE2_UCP) != 0)? ",ucp" : "",
- ((compile_options & PCRE2_UNGREEDY) != 0)? ",ungreedy" : "",
- ((compile_options & PCRE2_USE_OFFSET_LIMIT) != 0)? ",use_offset_limit" : "",
- ((compile_options & PCRE2_UTF) != 0)? ",utf" : "");
+fprintf(stream, "Compile options %s%.8x =",
+ (compile_options == PCRE2_NEVER_BACKSLASH_C)? "(base) " : "",
+ compile_options);
+
+fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ ((compile_options & PCRE2_ALT_BSUX) != 0)? " alt_bsux" : "",
+ ((compile_options & PCRE2_ALT_CIRCUMFLEX) != 0)? " alt_circumflex" : "",
+ ((compile_options & PCRE2_ALT_VERBNAMES) != 0)? " alt_verbnames" : "",
+ ((compile_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? " allow_empty_class" : "",
+ ((compile_options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+ ((compile_options & PCRE2_AUTO_CALLOUT) != 0)? " auto_callout" : "",
+ ((compile_options & PCRE2_CASELESS) != 0)? " caseless" : "",
+ ((compile_options & PCRE2_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "",
+ ((compile_options & PCRE2_DOTALL) != 0)? " dotall" : "",
+ ((compile_options & PCRE2_DUPNAMES) != 0)? " dupnames" : "",
+ ((compile_options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+ ((compile_options & PCRE2_EXTENDED) != 0)? " extended" : "",
+ ((compile_options & PCRE2_EXTENDED_MORE) != 0)? " extended_more" : "",
+ ((compile_options & PCRE2_FIRSTLINE) != 0)? " firstline" : "",
+ ((compile_options & PCRE2_MATCH_UNSET_BACKREF) != 0)? " match_unset_backref" : "",
+ ((compile_options & PCRE2_MULTILINE) != 0)? " multiline" : "",
+ ((compile_options & PCRE2_NEVER_BACKSLASH_C) != 0)? " never_backslash_c" : "",
+ ((compile_options & PCRE2_NEVER_UCP) != 0)? " never_ucp" : "",
+ ((compile_options & PCRE2_NEVER_UTF) != 0)? " never_utf" : "",
+ ((compile_options & PCRE2_NO_AUTO_CAPTURE) != 0)? " no_auto_capture" : "",
+ ((compile_options & PCRE2_NO_AUTO_POSSESS) != 0)? " no_auto_possess" : "",
+ ((compile_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? " no_dotstar_anchor" : "",
+ ((compile_options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+ ((compile_options & PCRE2_NO_START_OPTIMIZE) != 0)? " no_start_optimize" : "",
+ ((compile_options & PCRE2_UCP) != 0)? " ucp" : "",
+ ((compile_options & PCRE2_UNGREEDY) != 0)? " ungreedy" : "",
+ ((compile_options & PCRE2_USE_OFFSET_LIMIT) != 0)? " use_offset_limit" : "",
+ ((compile_options & PCRE2_UTF) != 0)? " utf" : "");
}
static void print_match_options(FILE *stream, uint32_t match_options)
{
-fprintf(stream, "Match options %.8x", match_options);
-fprintf(stream, "%s%s%s%s%s%s%s%s%s\n",
- ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
- ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
- ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
- ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "",
- ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "",
- ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "",
- ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "",
- ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "",
- ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : "");
+fprintf(stream, "Match options %s%.8x =",
+ (match_options == BASE_MATCH_OPTIONS)? "(base) " : "", match_options);
+
+fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s\n",
+ ((match_options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+ ((match_options & PCRE2_DISABLE_RECURSELOOP_CHECK) != 0)? " disable_recurseloop_check" : "",
+ ((match_options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+ ((match_options & PCRE2_NO_JIT) != 0)? " no_jit" : "",
+ ((match_options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+ ((match_options & PCRE2_NOTBOL) != 0)? " notbol" : "",
+ ((match_options & PCRE2_NOTEMPTY) != 0)? " notempty" : "",
+ ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "",
+ ((match_options & PCRE2_NOTEOL) != 0)? " noteol" : "",
+ ((match_options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "",
+ ((match_options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : "");
+}
+
+
+/* This function can print an error message at all code unit widths. */
+
+static void print_error(FILE *f, int errorcode, const char *text, ...)
+{
+PCRE2_UCHAR buffer[256];
+PCRE2_UCHAR *p = buffer;
+va_list ap;
+va_start(ap, text);
+vfprintf(f, text, ap);
+va_end(ap);
+pcre2_get_error_message(errorcode, buffer, 256);
+while (*p != 0) fprintf(f, "%c", *p++);
+printf("\n");
}
#endif /* defined(SUPPORT_DIFF_FUZZ || defined(STANDALONE) */
+
#ifdef SUPPORT_JIT
#ifdef SUPPORT_DIFF_FUZZ
static void dump_matches(FILE *stream, int count, pcre2_match_data *match_data)
{
-#if PCRE2_CODE_UNIT_WIDTH == 8
-PCRE2_UCHAR error_buf[256];
-#endif
int errorcode;
for (int index = 0; index < count; index++)
PCRE2_UCHAR *bufferptr = NULL;
PCRE2_SIZE bufflen = 0;
- errorcode = pcre2_substring_get_bynumber(match_data, index, &bufferptr, &bufflen);
+ errorcode = pcre2_substring_get_bynumber(match_data, index, &bufferptr,
+ &bufflen);
if (errorcode >= 0)
{
}
else
{
-#if PCRE2_CODE_UNIT_WIDTH == 8
- pcre2_get_error_message(errorcode, error_buf, 256);
- fprintf(stream, "Match %d failed: %s\n", index, error_buf);
-#else
- fprintf(stream, "Match %d failed: %d\n", index, errorcode);
-#endif
+ print_error(stream, errorcode, "Match %d failed: ", index);
}
}
}
pcre2_match_data *match_data,
pcre2_match_data *match_data_jit
) {
-#if PCRE2_CODE_UNIT_WIDTH == 8
-PCRE2_UCHAR buffer[256];
-#endif
fprintf(stderr, "Encountered failure while performing %s; context:\n", task);
if (errorcode < 0)
{
-#if PCRE2_CODE_UNIT_WIDTH == 8
- pcre2_get_error_message(errorcode, buffer, 256);
- fprintf(stderr, "Non-JIT'd operation emitted an error: %s (%d)\n", buffer, errorcode);
-#else
- fprintf(stderr, "Non-JIT'd operation emitted an error: %d\n", errorcode);
-#endif
+ print_error(stderr, errorcode, "Non-JIT'd operation emitted an error: ");
}
+
if (matches >= 0)
{
fprintf(stderr, "Non-JIT'd operation did not emit an error.\n");
if (errorcode_jit < 0)
{
-#if PCRE2_CODE_UNIT_WIDTH == 8
- pcre2_get_error_message(errorcode_jit, buffer, 256);
- fprintf(stderr, "JIT'd operation emitted an error: %s (%d)\n", buffer, errorcode_jit);
-#else
- fprintf(stderr, "JIT'd operation emitted an error: %d\n", errorcode);
-#endif
+ print_error(stderr, errorcode_jit, "JIT'd operation emitted error %d:",
+ errorcode_jit);
}
+
if (matches_jit >= 0)
{
fprintf(stderr, "JIT'd operation did not emit an error.\n");
abort();
}
-#endif /* SUPPORRT_DIFF_FUZZ */
+#endif /* SUPPORT_DIFF_FUZZ */
#endif /* SUPPORT_JIT */
/* This is the callout function. Its only purpose is to halt matching if there
int LLVMFuzzerInitialize(int *, char ***);
-int LLVMFuzzerTestOneInput(const unsigned char *, size_t);
+int LLVMFuzzerTestOneInput(unsigned char *, size_t);
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
rlim.rlim_cur = STACK_SIZE_MB * 1024 * 1024;
if (rlim.rlim_cur > rlim.rlim_max)
{
- fprintf(stderr, "hard stack size limit is too small (needed 8MiB)!\n");
+ fprintf(stderr, "Hard stack size limit is too small (needed 8MiB)!\n");
_exit(1);
}
rc = setrlimit(RLIMIT_STACK, &rlim);
if (rc != 0)
{
- fprintf(stderr, "failed to expand stack size\n");
+ fprintf(stderr, "Failed to expand stack size\n");
_exit(1);
}
/* Here's the driving function. */
-int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size)
+int LLVMFuzzerTestOneInput(unsigned char *data, size_t size)
{
+PCRE2_UCHAR *wdata;
+PCRE2_UCHAR *newwdata = NULL;
uint32_t compile_options;
uint32_t match_options;
uint64_t random_options;
#ifdef SUPPORT_JIT
pcre2_match_data *match_data_jit = NULL;
#endif
+pcre2_compile_context *compile_context = NULL;
pcre2_match_context *match_context = NULL;
size_t match_size;
int dfa_workspace[DFA_WORKSPACE_COUNT];
-int i;
if (size < sizeof(random_options)) return -1;
-/* Limiting the length of the subject for matching stops fruitless searches
-in large trees taking too much time. */
-
random_options = *(uint64_t *)(data);
data += sizeof(random_options);
+wdata = (PCRE2_UCHAR *)data;
size -= sizeof(random_options);
size /= PCRE2_CODE_UNIT_WIDTH / 8;
+/* PCRE2 compiles quantified groups by replicating them. In certain cases of
+very large quantifiers this can lead to unacceptably long JIT compile times. To
+get around this, we scan the data string for large quantifiers that follow a
+closing parenthesis, and reduce the value of the quantifier to 10, assuming
+that this will make minimal difference to the detection of bugs.
+
+Do the same for quantifiers that follow a closing square bracket, because
+classes that contain a number of non-ascii characters can take a lot of time
+when matching.
+
+We have to make a copy of the input because oss-fuzz complains if we overwrite
+the original. Start the scan at the second character so there can be a
+lookbehind for a backslash, and end it before the end so that the next
+character can be checked for an opening brace. */
+
+if (size > 3)
+ {
+ newwdata = malloc(size * sizeof(PCRE2_UCHAR));
+ memcpy(newwdata, wdata, size * sizeof(PCRE2_UCHAR));
+ wdata = newwdata;
+
+ for (size_t i = 1; i < size - 2; i++)
+ {
+ size_t j;
+
+ if ((wdata[i] != ')' && wdata[i] != ']') || wdata[i-1] == '\\' ||
+ wdata[i+1] != '{')
+ continue;
+ i++; /* Points to '{' */
+
+ /* Loop for two values a quantifier. Offset i points to brace or comma at the
+ start of the loop.*/
+
+ for (int ii = 0; ii < 2; ii++)
+ {
+ int q = 0;
+
+ if (i >= size - 1) goto END_QSCAN; /* Can happen for , */
+
+ /* Ignore leading spaces */
+
+ while (wdata[i+1] == ' ' || wdata[i+1] == '\t')
+ {
+ i++;
+ if (i >= size - 1) goto END_QSCAN;
+ }
+
+ /* Scan for a number ending in brace or comma in the first iteration,
+ optionally preceded by space. */
+
+ for (j = i + 1; j < size && j < i + 7; j++)
+ {
+ if (wdata[j] == ' ' || wdata[j] == '\t')
+ {
+ j++;
+ while (j < size && (wdata[j] == ' ' || wdata[j] == '\t')) j++;
+ if (j >= size) goto OUTERLOOP;
+ if (wdata[j] != '}' && wdata[j] != ',') goto OUTERLOOP;
+ }
+ if (wdata[j] == '}' || (ii == 0 && wdata[j] == ',')) break;
+ if (wdata[j] < '0' || wdata[j] > '9')
+ {
+ j--; /* Ensure this character is checked next. The */
+ goto OUTERLOOP; /* string might be (e.g.) "){9){234}" */
+ }
+ q = q * 10 + wdata[j] - '0';
+ }
+
+ if (j >= size) goto END_QSCAN; /* End of data */
+
+ /* Hit ',' or '}' or read 6 digits. Six digits is a number > 65536 which is
+ the maximum quantifier. Leave such numbers alone. */
+
+ if (j >= i + 7 || q > 65535) goto OUTERLOOP;
+
+ /* Limit the quantifier size to 10 */
+
+ if (q > 10)
+ {
+#ifdef STANDALONE
+ printf("Reduced quantifier value %d to 10.\n", q);
+#endif
+ for (size_t k = i + 1; k < j; k++) wdata[k] = '0';
+ wdata[j - 2] = '1';
+ }
+
+ /* Advance to end of number and break if reached closing brace (continue
+ after comma, which is only valid in the first time round this loop). */
+
+ i = j;
+ if (wdata[i] == '}') break;
+ }
+
+ /* Continue along the data string */
+
+ OUTERLOOP:
+ i = j;
+ continue;
+ }
+ }
+END_QSCAN:
+
+/* Limiting the length of the subject for matching stops fruitless searches
+in large trees taking too much time. */
+
match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size;
+/* Create a compile context, and set a limit on the size of the compiled
+pattern. This stops the fuzzer using vast amounts of memory. */
+
+compile_context = pcre2_compile_context_create(NULL);
+if (compile_context == NULL)
+ {
+#ifdef STANDALONE
+ fprintf(stderr, "** Failed to create compile context block\n");
+#endif
+ abort();
+ }
+pcre2_set_max_pattern_compiled_length(compile_context, 10*1024*1024);
+
/* Ensure that all undefined option bits are zero (waste of time trying them)
and also that PCRE2_NO_UTF_CHECK is unset, as there is no guarantee that the
-input is UTF-8. Also unset PCRE2_NEVER_UTF and PCRE2_NEVER_UCP as there is no
-reason to disallow UTF and UCP. Force PCRE2_NEVER_BACKSLASH_C to be set because
-\C in random patterns is highly likely to cause a crash. */
+input is valid UTF. Also unset PCRE2_NEVER_UTF and PCRE2_NEVER_UCP as there is
+no reason to disallow UTF and UCP. Force PCRE2_NEVER_BACKSLASH_C to be set
+because \C in random patterns is highly likely to cause a crash. */
compile_options = ((random_options >> 32) & ALLOWED_COMPILE_OPTIONS) |
PCRE2_NEVER_BACKSLASH_C;
match_options = (((uint32_t)random_options) & ALLOWED_MATCH_OPTIONS) |
- PCRE2_NO_JIT |
- PCRE2_DISABLE_RECURSELOOP_CHECK;
+ BASE_MATCH_OPTIONS;
/* Discard partial matching if PCRE2_ENDANCHORED is set, because they are not
allowed together and just give an immediate error return. */
/* Do the compile with and without the options, and after a successful compile,
likewise do the match with and without the options. */
-for (i = 0; i < 2; i++)
+for (int i = 0; i < 2; i++)
{
uint32_t callout_count;
int errorcode;
#ifdef SUPPORT_JIT
int errorcode_jit;
-#ifdef SUPPORT_JIT_FUZZ
+#ifdef SUPPORT_DIFF_FUZZ
int matches = 0;
int matches_jit = 0;
#endif
pcre2_code *code;
#ifdef STANDALONE
+ printf("\n");
print_compile_options(stdout, compile_options);
#endif
- code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options,
- &errorcode, &erroroffset, NULL);
+ code = pcre2_compile((PCRE2_SPTR)wdata, (PCRE2_SIZE)size, compile_options,
+ &errorcode, &erroroffset, compile_context);
/* Compilation succeeded */
int j;
uint32_t save_match_options = match_options;
+ /* Call JIT compile only if the compiled pattern is not too big. */
+
#ifdef SUPPORT_JIT
- int jit_ret = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE);
+ int jit_ret = -1;
+ if (((struct pcre2_real_code *)code)->blocksize <= JIT_SIZE_LIMIT)
+ {
+#ifdef STANDALONE
+ printf("Compile succeeded; calling JIT compile\n");
+#endif
+ jit_ret = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE);
+#ifdef STANDALONE
+ if (jit_ret < 0) printf("JIT compile error %d\n", jit_ret);
#endif
+ }
+ else
+ {
+#ifdef STANDALONE
+ printf("Not calling JIT: compiled pattern is too long "
+ "(%ld bytes; limit=%d)\n",
+ ((struct pcre2_real_code *)code)->blocksize, JIT_SIZE_LIMIT);
+#endif
+ }
+#endif /* SUPPORT_JIT */
/* Create match data and context blocks only when we first need them. Set
low match and depth limits to avoid wasting too much searching large
/* Match twice, with and without options. */
+#ifdef STANDALONE
+ printf("\n");
+#endif
for (j = 0; j < 2; j++)
{
#ifdef STANDALONE
#endif
callout_count = 0;
- errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0,
+ errorcode = pcre2_match(code, (PCRE2_SPTR)wdata, (PCRE2_SIZE)match_size, 0,
match_options, match_data, match_context);
#ifdef STANDALONE
if (errorcode >= 0) printf("Match returned %d\n", errorcode); else
- {
-#if PCRE2_CODE_UNIT_WIDTH == 8
- unsigned char buffer[256];
- pcre2_get_error_message(errorcode, buffer, 256);
- printf("Match failed: error %d: %s\n", errorcode, buffer);
-#else
- printf("Match failed: error %d\n", errorcode);
-#endif
- }
+ print_error(stdout, errorcode, "Match failed: error %d: ", errorcode);
#endif
+/* If JIT is enabled, do a JIT match and, if appropriately compiled, compare
+with the interpreter. */
+
#ifdef SUPPORT_JIT
if (jit_ret >= 0)
{
+#ifdef STANDALONE
+ printf("Matching with JIT\n");
+#endif
callout_count = 0;
- errorcode_jit = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0,
+ errorcode_jit = pcre2_match(code, (PCRE2_SPTR)wdata, (PCRE2_SIZE)match_size, 0,
match_options & ~PCRE2_NO_JIT, match_data_jit, match_context);
-#ifndef SUPPORT_DIFF_FUZZ
- (void)errorcode_jit; /* Avoid compiler warning */
+#ifdef STANDALONE
+ if (errorcode_jit >= 0)
+ printf("Match returned %d\n", errorcode_jit);
+ else
+ print_error(stdout, errorcode_jit, "JIT match failed: error %d: ",
+ errorcode_jit);
#else
+ (void)errorcode_jit; /* Avoid compiler warning */
+#endif /* STANDALONE */
+
+/* With differential matching enabled, compare with interpreter. */
+#ifdef SUPPORT_DIFF_FUZZ
matches = errorcode;
matches_jit = errorcode_jit;
errorcode != PCRE2_ERROR_MATCHLIMIT && errorcode != PCRE2_ERROR_CALLOUT &&
errorcode_jit != PCRE2_ERROR_MATCHLIMIT && errorcode_jit != PCRE2_ERROR_JIT_STACKLIMIT && errorcode_jit != PCRE2_ERROR_CALLOUT)
{
- describe_failure("match errorcode comparison", data, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit);
+ describe_failure("match errorcode comparison", wdata, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit);
}
}
else
if (errorcode != errorcode_jit)
{
- describe_failure("match entry errorcode comparison", data, size,
+ describe_failure("match entry errorcode comparison", wdata, size,
compile_options, match_options, errorcode, errorcode_jit,
matches, matches_jit, match_data, match_data_jit);
}
{
if (bufflen != bufflen_jit)
{
- describe_failure("match entry length comparison", data, size,
+ describe_failure("match entry length comparison", wdata, size,
compile_options, match_options, errorcode, errorcode_jit,
matches, matches_jit, match_data, match_data_jit);
}
if (memcmp(bufferptr, bufferptr_jit, bufflen) != 0)
{
- describe_failure("match entry content comparison", data, size,
+ describe_failure("match entry content comparison", wdata, size,
compile_options, match_options, errorcode, errorcode_jit,
matches, matches_jit, match_data, match_data_jit);
}
pcre2_substring_free(bufferptr_jit);
}
}
-#endif /* SUPPORT_JIT_FUZZ */
+#endif /* SUPPORT_DIFF_FUZZ */
}
#endif /* SUPPORT_JIT */
- match_options = PCRE2_NO_JIT; /* For second time */
+ if (match_options == BASE_MATCH_OPTIONS) break; /* Don't do same twice */
+ match_options = BASE_MATCH_OPTIONS; /* For second time */
}
- /* Match with DFA twice, with and without options. */
+ /* Match with DFA twice, with and without options, but remove options that
+ are not allowed with DFA. */
- match_options = save_match_options & ~PCRE2_NO_JIT; /* Not valid for DFA */
+ match_options = save_match_options & ~BASE_MATCH_OPTIONS;
+
+#ifdef STANDALONE
+ printf("\n");
+#endif
for (j = 0; j < 2; j++)
{
#ifdef STANDALONE
- printf("DFA match options %.8x", match_options);
+ printf("DFA match options %.8x =", match_options);
printf("%s%s%s%s%s%s%s%s%s\n",
- ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
- ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
- ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
- ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "",
- ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "",
- ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "",
- ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "",
- ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "",
- ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : "");
+ ((match_options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+ ((match_options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+ ((match_options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+ ((match_options & PCRE2_NOTBOL) != 0)? " notbol" : "",
+ ((match_options & PCRE2_NOTEMPTY) != 0)? " notempty" : "",
+ ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "",
+ ((match_options & PCRE2_NOTEOL) != 0)? " noteol" : "",
+ ((match_options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "",
+ ((match_options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : "");
#endif
callout_count = 0;
- errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)data,
- (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context,
- dfa_workspace, DFA_WORKSPACE_COUNT);
+ errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)wdata,
+ (PCRE2_SIZE)match_size, 0, match_options, match_data,
+ match_context, dfa_workspace, DFA_WORKSPACE_COUNT);
#ifdef STANDALONE
- if (errorcode >= 0) printf("Match returned %d\n", errorcode); else
- {
-#if PCRE2_CODE_UNIT_WIDTH == 8
- unsigned char buffer[256];
- pcre2_get_error_message(errorcode, buffer, 256);
- printf("Match failed: error %d: %s\n", errorcode, buffer);
-#else
- printf("Match failed: error %d\n", errorcode);
-#endif
- }
+ if (errorcode >= 0)
+ printf("Match returned %d\n", errorcode);
+ else
+ print_error(stdout, errorcode, "DFA match failed: error %d: ", errorcode);
#endif
- match_options = 0; /* For second time */
+ if (match_options == 0) break; /* No point doing same twice */
+ match_options = 0; /* For second time */
}
match_options = save_match_options; /* Reset for the second compile */
else
{
#ifdef STANDALONE
-#if PCRE2_CODE_UNIT_WIDTH == 8
- unsigned char buffer[256];
- pcre2_get_error_message(errorcode, buffer, 256);
- printf("Error %d at offset %lu: %s\n", errorcode, erroroffset, buffer);
-#else
- printf("Error %d at offset %lu\n", errorcode, erroroffset);
-#endif
-
+ print_error(stdout, errorcode, "Error %d at offset %lu: ", errorcode,
+ erroroffset);
#else
if (errorcode == PCRE2_ERROR_INTERNAL) abort();
#endif
}
- compile_options = PCRE2_NEVER_BACKSLASH_C; /* For second time */
+ if (compile_options == PCRE2_NEVER_BACKSLASH_C) break; /* Avoid same twice */
+ compile_options = PCRE2_NEVER_BACKSLASH_C; /* For second time */
}
+/* Tidy up before exiting */
+
if (match_data != NULL) pcre2_match_data_free(match_data);
#ifdef SUPPORT_JIT
if (match_data_jit != NULL) pcre2_match_data_free(match_data_jit);
+free(newwdata);
#endif
if (match_context != NULL) pcre2_match_context_free(match_context);
-
+if (compile_context != NULL) pcre2_compile_context_free(compile_context);
return 0;
}
#ifdef STANDALONE
int main(int argc, char **argv)
{
-int i;
-
LLVMFuzzerInitialize(&argc, &argv);
if (argc < 2)
return 0;
}
-for (i = 1; i < argc; i++)
+for (int i = 1; i < argc; i++)
{
size_t filelen;
size_t readsize;
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-2023 University of Cambridge
+ New API code Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
void *stack_guard_data;
const uint8_t *tables;
PCRE2_SIZE max_pattern_length;
+ PCRE2_SIZE max_pattern_compiled_length;
uint16_t bsr_convention;
uint16_t newline_convention;
uint32_t parens_nest_limit;
Written by Philip Hazel
This module by Zoltan Herczeg
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-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
/* For OP_ONCE. Less than 0 if not needed. */
int framesize;
/* For brackets with >3 alternatives. */
- struct sljit_put_label *matching_put_label;
+ struct sljit_jump *matching_mov_addr;
} u;
/* Points to our private memory word on the stack. */
int private_data_ptr;
chr++;
}
while (byte != 0);
- chr = (chr + 7) & ~7;
+ chr = (chr + 7) & (sljit_u32)(~7);
}
}
while (chars->count != 255 && bytes < bytes_end);
chr = *cc;
#ifdef SUPPORT_UNICODE
if (common->ucp && chr > 127)
- othercase[0] = UCD_OTHERCASE(chr);
+ {
+ chr = UCD_OTHERCASE(chr);
+ othercase[0] = (chr == (PCRE2_UCHAR)chr) ? chr : *cc;
+ }
else
#endif
othercase[0] = TABLE_GET(chr, common->fcc, chr);
/* Convert last_count to priority. */
for (i = 0; i < max; i++)
{
- SLJIT_ASSERT(chars[i].count > 0 && chars[i].last_count <= chars[i].count);
+ SLJIT_ASSERT(chars[i].last_count <= chars[i].count);
- if (chars[i].count == 1)
+ switch (chars[i].count)
{
+ case 0:
+ chars[i].count = 255;
+ chars[i].last_count = 0;
+ break;
+
+ case 1:
chars[i].last_count = (chars[i].last_count == 1) ? 7 : 5;
/* Simplifies algorithms later. */
chars[i].chars[1] = chars[i].chars[0];
- }
- else if (chars[i].count == 2)
- {
+ break;
+
+ case 2:
SLJIT_ASSERT(chars[i].chars[0] != chars[i].chars[1]);
if (is_powerof2(chars[i].chars[0] ^ chars[i].chars[1]))
chars[i].last_count = (chars[i].last_count == 2) ? 6 : 4;
else
chars[i].last_count = (chars[i].last_count == 2) ? 3 : 2;
- }
- else
+ break;
+
+ default:
chars[i].last_count = (chars[i].count == 255) ? 0 : 1;
+ break;
+ }
}
#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD
bit = bits[0] & 0x1;
/* All bits will be zero or one (since bit is zero or one). */
-all = -bit;
+all = (sljit_u8)-bit;
for (i = 0; i < 256; )
{
ranges[length] = i;
length++;
bit = cbit;
- all = -cbit;
+ all = (sljit_u8)-cbit; /* sign extend bit into byte */
}
i++;
}
byte = bits[i];
if (nclass)
- byte = ~byte;
+ byte = (sljit_u8)~byte;
j = 0;
while (byte != 0)
if (cc[-1] == XCL_NOTPROP)
invertcmp ^= 0x1;
- OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_boolprop_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)1 << (cc[1] & 0x1f));
+ OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_boolprop_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)(1u << (cc[1] & 0x1f)));
add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp));
}
cc += 2;
invertcmp ^= 0x1;
}
- OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_script_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)1 << (cc[1] & 0x1f));
+ OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_script_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)(1u << (cc[1] & 0x1f)));
add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp));
if (jump != NULL)
#if PCRE2_CODE_UNIT_WIDTH != 32
+/* The code in this function copies the logic of the interpreter function that
+is defined in the pcre2_extuni.c source. If that code is updated, this
+function, and those below it, must be kept in step (note by PH, June 2024). */
+
static PCRE2_SPTR SLJIT_FUNC do_extuni_utf(jit_arguments *args, PCRE2_SPTR cc)
{
PCRE2_SPTR start_subject = args->begin;
int lgb, rgb, ricount;
PCRE2_SPTR prevcc, endcc, bptr;
BOOL first = TRUE;
+BOOL was_ep_ZWJ = FALSE;
uint32_t c;
prevcc = cc;
if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0)
break;
+ /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was
+ preceded by Extended Pictographic. */
+
+ if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ)
+ break;
+
/* Not breaking between Regional Indicators is allowed only if there
are an even number of preceding RIs. */
if ((ricount & 1) != 0) break; /* Grapheme break required */
}
- /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
- allows any number of them before a following Extended_Pictographic. */
+ /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in
+ between; see next statement). */
+
+ was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ);
- if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
- lgb != ucp_gbExtended_Pictographic)
+ /* If Extend follows Extended_Pictographic, do not update lgb; this allows
+ any number of them before a following ZWJ. */
+
+ if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic)
lgb = rgb;
prevcc = endcc;
#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+/* The code in this function copies the logic of the interpreter function that
+is defined in the pcre2_extuni.c source. If that code is updated, this
+function, and the one below it, must be kept in step (note by PH, June 2024). */
+
static PCRE2_SPTR SLJIT_FUNC do_extuni_utf_invalid(jit_arguments *args, PCRE2_SPTR cc)
{
PCRE2_SPTR start_subject = args->begin;
int lgb, rgb, ricount;
PCRE2_SPTR prevcc, endcc, bptr;
BOOL first = TRUE;
+BOOL was_ep_ZWJ = FALSE;
uint32_t c;
prevcc = cc;
if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0)
break;
+ /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was
+ preceded by Extended Pictographic. */
+
+ if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ)
+ break;
+
/* Not breaking between Regional Indicators is allowed only if there
are an even number of preceding RIs. */
break; /* Grapheme break required */
}
- /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
- allows any number of them before a following Extended_Pictographic. */
+ /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in
+ between; see next statement). */
+
+ was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ);
- if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
- lgb != ucp_gbExtended_Pictographic)
+ /* If Extend follows Extended_Pictographic, do not update lgb; this allows
+ any number of them before a following ZWJ. */
+
+ if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic)
lgb = rgb;
prevcc = endcc;
return endcc;
}
+/* The code in this function copies the logic of the interpreter function that
+is defined in the pcre2_extuni.c source. If that code is updated, this
+function must be kept in step (note by PH, June 2024). */
+
static PCRE2_SPTR SLJIT_FUNC do_extuni_no_utf(jit_arguments *args, PCRE2_SPTR cc)
{
PCRE2_SPTR start_subject = args->begin;
int lgb, rgb, ricount;
PCRE2_SPTR bptr;
uint32_t c;
+BOOL was_ep_ZWJ = FALSE;
/* Patch by PH */
/* GETCHARINC(c, cc); */
if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0)
break;
+ /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was
+ preceded by Extended Pictographic. */
+
+ if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ)
+ break;
+
/* Not breaking between Regional Indicators is allowed only if there
are an even number of preceding RIs. */
break; /* Grapheme break required */
}
- /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
- allows any number of them before a following Extended_Pictographic. */
+ /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in
+ between; see next statement). */
+
+ was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ);
- if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
- lgb != ucp_gbExtended_Pictographic)
+ /* If Extend follows Extended_Pictographic, do not update lgb; this allows
+ any number of them before a following ZWJ. */
+
+ if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic)
lgb = rgb;
cc++;
return cc + 1 + LINK_SIZE;
}
-static sljit_s32 SLJIT_FUNC SLJIT_FUNC_ATTRIBUTE do_callout_jit(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
+static sljit_s32 SLJIT_FUNC do_callout_jit(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
{
PCRE2_SPTR begin;
PCRE2_SIZE *ovector;
if (i <= 3)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
else
- BACKTRACK_AS(bracket_backtrack)->u.matching_put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
+ BACKTRACK_AS(bracket_backtrack)->u.matching_mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
}
if (ket != OP_KETRMAX)
BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
/* Continue to the normal backtrack. */
}
-if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO)
+if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO || (has_alternatives && repeat_type != OP_EXACT))
count_match(common);
cc += 1 + LINK_SIZE;
if (opcode == OP_ONCE)
{
+ int data;
+ int framesize = BACKTRACK_AS(bracket_backtrack)->u.framesize;
+
+ SLJIT_ASSERT(SHRT_MIN <= framesize && framesize < SHRT_MAX/2);
/* We temporarily encode the needs_control_head in the lowest bit.
- Note: on the target architectures of SLJIT the ((x << 1) >> 1) returns
- the same value for small signed numbers (including negative numbers). */
- BACKTRACK_AS(bracket_backtrack)->u.framesize = (int)((unsigned)BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0);
+ The real value should be short enough for this operation to work
+ without triggering Undefined Behaviour. */
+ data = (int)((short)((unsigned short)framesize << 1) | (needs_control_head ? 1 : 0));
+ BACKTRACK_AS(bracket_backtrack)->u.framesize = data;
}
return cc + repeat_length;
}
struct sljit_jump *cond = NULL;
struct sljit_label *rmin_label = NULL;
struct sljit_label *exact_label = NULL;
-struct sljit_put_label *put_label = NULL;
+struct sljit_jump *mov_addr = NULL;
if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
{
{
sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0);
- SLJIT_ASSERT(CURRENT_AS(bracket_backtrack)->u.matching_put_label);
- sljit_set_put_label(CURRENT_AS(bracket_backtrack)->u.matching_put_label, LABEL());
+ SLJIT_ASSERT(CURRENT_AS(bracket_backtrack)->u.matching_mov_addr);
+ sljit_set_label(CURRENT_AS(bracket_backtrack)->u.matching_mov_addr, LABEL());
sljit_emit_op0(compiler, SLJIT_ENDBR);
}
else
if (alt_max <= 3)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, alt_count);
else
- put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
+ mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
}
if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0)
}
else
{
- sljit_set_put_label(put_label, LABEL());
+ sljit_set_label(mov_addr, LABEL());
sljit_emit_op0(compiler, SLJIT_ENDBR);
}
}
struct sljit_jump *next_alt = NULL;
struct sljit_jump *accept_exit = NULL;
struct sljit_label *quit;
-struct sljit_put_label *put_label = NULL;
+struct sljit_jump *mov_addr = NULL;
/* Recurse captures then. */
common->then_trap = NULL;
if (alt_max > 1 || (recurse_flags & recurse_flag_accept_found))
{
if (alt_max > 3)
- put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(1));
+ mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(1));
else
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count);
}
if (alt_max > 3)
{
sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0);
- sljit_set_put_label(put_label, LABEL());
+ sljit_set_label(mov_addr, LABEL());
sljit_emit_op0(compiler, SLJIT_ENDBR);
}
else
}
else if (alt_max > 3)
{
- sljit_set_put_label(put_label, LABEL());
+ sljit_set_label(mov_addr, LABEL());
sljit_emit_op0(compiler, SLJIT_ENDBR);
}
else
set_then_offsets(common, common->start, NULL);
}
-compiler = sljit_create_compiler(allocator_data, NULL);
+compiler = sljit_create_compiler(allocator_data);
if (!compiler)
{
SLJIT_FREE(common->optimized_cbracket, allocator_data);
SLJIT_FREE(common->optimized_cbracket, allocator_data);
SLJIT_FREE(common->private_data_ptrs, allocator_data);
-executable_func = sljit_generate_code(compiler);
+executable_func = sljit_generate_code(compiler, 0, NULL);
executable_size = sljit_get_generated_code_size(compiler);
sljit_free_compiler(compiler);
return NULL;
if (startsize > maxsize)
startsize = maxsize;
-startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
-maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+startsize = (startsize + STACK_GROWTH_RATE - 1) & (size_t)(~(STACK_GROWTH_RATE - 1));
+maxsize = (maxsize + STACK_GROWTH_RATE - 1) & (size_t)(~(STACK_GROWTH_RATE - 1));
jit_stack = PRIV(memctl_malloc)(sizeof(pcre2_real_jit_stack), (pcre2_memctl *)gcontext);
if (jit_stack == NULL) return NULL;
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()));
+SLJIT_ASSERT(diff <= (unsigned)IN_UCHARS(max_fast_forward_char_pair_offset()));
/* Initialize. */
if (common->match_end_ptr != 0)
#define F_PROPERTY 0x200000
struct regression_test_case {
- int compile_options;
+ uint32_t compile_options;
int newline;
int match_options;
int start_offset;
{ CM, A, 0, 0, "a1277|a1377|bX487", "bx487" },
{ CM, A, 0, 0, "a1277|a1377|bx487", "bX487" },
{ 0, A, 0, 0, "(a|)b*+a", "a" },
+ { 0, A, 0, 0 | F_NOMATCH, "(.|.|.|.|.)(|.|.|.|.)(.||.|.|.)(.|.||.|.)(.|.|.||.)(.|.|.|.|)(A|.|.|.|.)(.|A|.|.|.)(.|.|A|.|.)(.|.|.|A|.)(.|.|.|.|A)(B|.|.|.|.)(.|B|.|.|.)(.|.|B|.|.)(.|.|.|B|.)(.|.|.|.|B)xa", "1234567890123456ax" },
/* Greedy and non-greedy ? operators. */
{ MU, A, 0, 0, "(?:a)?a", "laab" },
{ MU, A, 0, 0, "[\\x{10001}-\\x{10fffe}]+", "#\xc3\xa9\xe2\xb1\xa5\xf0\x90\x80\x80\xf0\x90\x80\x81\xf4\x8f\xbf\xbe\xf4\x8f\xbf\xbf" },
{ MU, A, 0, 0, "[^\\x{10001}-\\x{10fffe}]+", "\xf0\x90\x80\x81#\xc3\xa9\xe2\xb1\xa5\xf0\x90\x80\x80\xf4\x8f\xbf\xbf\xf4\x8f\xbf\xbe" },
{ CMU, A, 0, 0 | F_NOMATCH | F_PROPERTY, "^[\\x{100}-\\x{17f}]", " " },
+ { M, A, 0, 0 | F_NOMATCH, "[^\\S\\W]{6}", "abcdefghijk" },
/* Unicode properties. */
{ MUP, A, 0, 0, "[1-5\xc3\xa9\\w]", "\xc3\xa1_" },
int counter = 0;
int jit_compile_mode;
int utf = 0;
- int disabled_options = 0;
+ uint32_t disabled_options = 0;
int i;
#ifdef SUPPORT_PCRE2_8
pcre2_code_8 *re8;
ovector8_1 = pcre2_get_ovector_pointer_8(mdata8_1);
ovector8_2 = pcre2_get_ovector_pointer_8(mdata8_2);
for (i = 0; i < OVECTOR_SIZE * 2; ++i)
- ovector8_1[i] = -2;
+ ovector8_1[i] = (PCRE2_SIZE)(-2);
for (i = 0; i < OVECTOR_SIZE * 2; ++i)
- ovector8_2[i] = -2;
+ ovector8_2[i] = (PCRE2_SIZE)(-2);
pcre2_set_match_limit_8(mcontext8, 10000000);
}
if (re8) {
ovector16_1 = pcre2_get_ovector_pointer_16(mdata16_1);
ovector16_2 = pcre2_get_ovector_pointer_16(mdata16_2);
for (i = 0; i < OVECTOR_SIZE * 2; ++i)
- ovector16_1[i] = -2;
+ ovector16_1[i] = (PCRE2_SIZE)(-2);
for (i = 0; i < OVECTOR_SIZE * 2; ++i)
- ovector16_2[i] = -2;
+ ovector16_2[i] = (PCRE2_SIZE)(-2);
pcre2_set_match_limit_16(mcontext16, 10000000);
}
if (re16) {
ovector32_1 = pcre2_get_ovector_pointer_32(mdata32_1);
ovector32_2 = pcre2_get_ovector_pointer_32(mdata32_2);
for (i = 0; i < OVECTOR_SIZE * 2; ++i)
- ovector32_1[i] = -2;
+ ovector32_1[i] = (PCRE2_SIZE)(-2);
for (i = 0; i < OVECTOR_SIZE * 2; ++i)
- ovector32_2[i] = -2;
+ ovector32_2[i] = (PCRE2_SIZE)(-2);
pcre2_set_match_limit_32(mcontext32, 10000000);
}
if (re32) {
#define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF)
struct invalid_utf8_regression_test_case {
- int compile_options;
+ uint32_t compile_options;
int jit_compile_options;
int start_offset;
int skip_left;
#define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF)
struct invalid_utf16_regression_test_case {
- int compile_options;
+ uint32_t compile_options;
int jit_compile_options;
int start_offset;
int skip_left;
#define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF)
struct invalid_utf32_regression_test_case {
- int compile_options;
+ uint32_t compile_options;
int jit_compile_options;
int start_offset;
int skip_left;
{
ptrdiff_t diff = Feptr - mb->start_subject;
- uint32_t available = (diff > 65535)? 65535 : ((diff > 0)? diff : 0);
+ uint32_t available = (diff > 65535)? 65535 : ((diff > 0)? (int)diff : 0);
if (Lmin > available) RRETURN(MATCH_NOMATCH);
if (Lmax > available) Lmax = available;
Feptr -= Lmax;
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-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
6. Do not break after Prepend characters.
7. Do not break within emoji modifier sequences or emoji zwj sequences. That
- is, do not break between characters with the Extended_Pictographic property.
- Extend and ZWJ characters are allowed between the characters; this cannot be
- represented in this table, the code has to deal with it.
+ is, do not break between characters with the Extended_Pictographic property
+ if a ZWJ intervenes. Extend characters are allowed between the characters;
+ this cannot be represented in this table, the code has to deal with it.
8. Do not break within emoji flag sequences. That is, do not break between
regional indicator (RI) symbols if there are an odd number of RI characters
ESZ|(1u<<ucp_gbT), /* 10 LVT */
(1u<<ucp_gbRegional_Indicator), /* 11 Regional Indicator */
ESZ, /* 12 Other */
- ESZ, /* 13 ZWJ */
- ESZ|(1u<<ucp_gbExtended_Pictographic) /* 14 Extended Pictographic */
+ ESZ|(1u<<ucp_gbExtended_Pictographic), /* 13 ZWJ */
+ ESZ /* 14 Extended Pictographic */
};
#undef ESZ
{ "match_line", MOD_CTC, MOD_OPT, PCRE2_EXTRA_MATCH_LINE, CO(extra_options) },
{ "match_unset_backref", MOD_PAT, MOD_OPT, PCRE2_MATCH_UNSET_BACKREF, PO(options) },
{ "match_word", MOD_CTC, MOD_OPT, PCRE2_EXTRA_MATCH_WORD, CO(extra_options) },
+ { "max_pattern_compiled_length", MOD_CTC, MOD_SIZ, 0, CO(max_pattern_compiled_length) },
{ "max_pattern_length", MOD_CTC, MOD_SIZ, 0, CO(max_pattern_length) },
{ "max_varlookbehind", MOD_CTC, MOD_INT, 0, CO(max_varlookbehind) },
{ "memory", MOD_PD, MOD_CTL, CTL_MEMORY, PD(control) },
else \
pcre2_set_match_limit_32(G(a,32),b)
+#define PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_max_pattern_compiled_length_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_max_pattern_compiled_length_16(G(a,16),b); \
+ else \
+ pcre2_set_max_pattern_compiled_length_32(G(a,32),b)
+
#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \
if (test_mode == PCRE8_MODE) \
pcre2_set_max_pattern_length_8(G(a,8),b); \
else \
G(pcre2_set_match_limit_,BITTWO)(G(a,BITTWO),b)
+#define PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_max_pattern_compiled_length_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_max_pattern_compiled_length_,BITTWO)(G(a,BITTWO),b)
+
#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \
if (test_mode == G(G(PCRE,BITONE),_MODE)) \
G(pcre2_set_max_pattern_length_,BITONE)(G(a,BITONE),b); \
#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_8(G(a,8),b)
#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_8(G(a,8),b)
#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_8(G(a,8),b)
+#define PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH(a,b) pcre2_set_max_pattern_compiled_length_8(G(a,8),b)
#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_8(G(a,8),b)
#define PCRE2_SET_MAX_VARLOOKBEHIND(a,b) pcre2_set_max_varlookbehind_8(G(a,8),b)
#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_8(G(a,8),b)
/* The uint32_t variables are cast before multiplying to stop code analyzers
grumbling about potential overflow. */
-fprintf(outfile, "Memory allocation (code space): %" SIZ_FORM "\n", size -
+fprintf(outfile, "Memory allocation - compiled block : %" SIZ_FORM "\n", size);
+fprintf(outfile, "Memory allocation - code portion : %" SIZ_FORM "\n", size -
(PCRE2_SIZE)name_count * (PCRE2_SIZE)name_entry_size * (PCRE2_SIZE)code_unit_size -
cblock_size);
if (pat_patctl.jit != 0)
{
(void)pattern_info(PCRE2_INFO_JITSIZE, &size, FALSE);
- fprintf(outfile, "Memory allocation (JIT code): %" SIZ_FORM "\n", size);
+ fprintf(outfile, "Memory allocation - JIT code : %" SIZ_FORM "\n", size);
}
}
if (local_newline_default != 0) prmsg(&msg, "#newline_default");
if (FLD(pat_context, max_pattern_length) != PCRE2_UNSET)
prmsg(&msg, "max_pattern_length");
+ if (FLD(pat_context, max_pattern_compiled_length) != PCRE2_UNSET)
+ prmsg(&msg, "max_pattern_compiled_length");
if (FLD(pat_context, parens_nest_limit) != PARENS_NEST_DEFAULT)
prmsg(&msg, "parens_nest_limit");
PCRE2_COMPILE(compiled_code, use_pbuffer, patlen,
pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset, use_pat_context);
+/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit
+and 32-bit buffers can be marked completely undefined, but we must leave the
+pattern in the 8-bit buffer defined because it may be read from a callout
+during matching. */
+
+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length,
+ pbuffer8_size - valgrind_access_length);
+ }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size);
+ }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size);
+ }
+#endif
+#endif
+
/* Call the JIT compiler if requested. When timing, we must free and recompile
the pattern each time because that is the only way to free the JIT compiled
code. We know that compilation will always succeed. */
start_time = clock();
PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
time_taken += clock() - start_time;
+ if (jitrc != 0)
+ {
+ fprintf(outfile, "JIT compilation was not successful");
+ if (!print_error_message(jitrc, " (", ")\n")) return PR_ABEND;
+ break;
+ }
}
total_jit_compile_time += time_taken;
- fprintf(outfile, "JIT compile %8.4f microseconds\n",
- ((1000000 / CLOCKS_PER_SEC) * (double)time_taken) / timeit);
+ if (jitrc == 0)
+ fprintf(outfile, "JIT compile %8.4f microseconds\n",
+ ((1000000 / CLOCKS_PER_SEC) * (double)time_taken) / timeit);
}
else
{
PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+ if (jitrc != 0 && (pat_patctl.control & CTL_JITVERIFY) != 0)
+ {
+ fprintf(outfile, "JIT compilation was not successful");
+ if (!print_error_message(jitrc, " (", ")\n")) return PR_ABEND;
+ }
}
}
-/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit
-and 32-bit buffers can be marked completely undefined, but we must leave the
-pattern in the 8-bit buffer defined because it may be read from a callout
-during matching. */
-
-#ifdef SUPPORT_VALGRIND
-#ifdef SUPPORT_PCRE2_8
-if (test_mode == PCRE8_MODE)
- {
- VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length,
- pbuffer8_size - valgrind_access_length);
- }
-#endif
-#ifdef SUPPORT_PCRE2_16
-if (test_mode == PCRE16_MODE)
- {
- VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size);
- }
-#endif
-#ifdef SUPPORT_PCRE2_32
-if (test_mode == PCRE32_MODE)
- {
- VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size);
- }
-#endif
-#endif
-
/* Compilation failed; go back for another re, skipping to blank line
if non-interactive. */
#define CONTEXTTESTS \
(void)G(pcre2_set_compile_extra_options_,BITS)(G(pat_context,BITS), 0); \
(void)G(pcre2_set_max_pattern_length_,BITS)(G(pat_context,BITS), 0); \
+ (void)G(pcre2_set_max_pattern_compiled_length_,BITS)(G(pat_context,BITS), 0); \
(void)G(pcre2_set_max_varlookbehind_,BITS)(G(pat_context,BITS), 0); \
(void)G(pcre2_set_offset_limit_,BITS)(G(dat_context,BITS), 0); \
(void)G(pcre2_get_match_data_size_,BITS)(G(match_data,BITS))
-
/* Call the appropriate functions for the current mode, and exercise some
functions that are not otherwise called. */
#include <sys/utsname.h>
#include <stdlib.h>
-#define SLJIT_MAP_JIT (get_map_jit_flag())
#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+#ifdef MAP_JIT
+#define SLJIT_MAP_JIT (get_map_jit_flag())
static SLJIT_INLINE int get_map_jit_flag(void)
{
size_t page_size;
}
return map_jit_flag;
}
+#else /* !defined(MAP_JIT) */
+#define SLJIT_MAP_JIT (0)
+#endif
#elif defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM
header->executable_offset = free_block->header.executable_offset;
#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
AS_BLOCK_HEADER(header, size)->prev_size = size;
- }
- else {
+ } else {
sljit_remove_free_block(free_block);
header = (struct block_header*)free_block;
size = chunk_size;
#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
sljit_insert_free_block(free_block, chunk_size);
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
- }
- else {
+ } 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 */
+ SLJIT_ALLOCATOR_UNLOCK();
return MEM_START(header);
}
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void *ptr)
{
struct block_header *header;
- struct free_block* free_block;
+ struct free_block *free_block;
SLJIT_ALLOCATOR_LOCK();
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
free_block->size += header->size;
header = AS_BLOCK_HEADER(free_block, free_block->size);
header->prev_size = free_block->size;
- }
- else {
+ } else {
free_block = (struct free_block*)header;
sljit_insert_free_block(free_block, header->size);
}
free_block = free_blocks;
while (free_block) {
next_free_block = free_block->next;
- if (!free_block->header.prev_size &&
+ 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_block = next_free_block;
}
- SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
+ SLJIT_ASSERT(total_size || (!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)
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code)
{
- return ((struct block_header *)(ptr))[-1].executable_offset;
+ return ((struct block_header*)SLJIT_CODE_TO_PTR(code))[-1].executable_offset;
}
#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type
sljit_s32, sljit_u32 : signed and unsigned 32 bit integer type
sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
- sljit_p : unsgined pointer value (usually the same as sljit_uw, but
- some 64 bit ABIs may use 32 bit pointers)
+ sljit_sp, sljit_up : signed and unsigned pointer value (usually the same as
+ sljit_uw, but some 64 bit ABIs may use 32 bit pointers)
sljit_f32 : 32 bit single precision floating point value
sljit_f64 : 64 bit double precision floating point value
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_TMP_DEST_REG : a temporary register for results
+ SLJIT_TMP_MEM_REG : a temporary base register for accessing memory
+ (can be the same as SLJIT_TMP_DEST_REG)
+ SLJIT_TMP_DEST_FREG : a temporary register for float results
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
*/
#ifndef SLJIT_MALLOC
-#define SLJIT_MALLOC(size, allocator_data) malloc(size)
+#define SLJIT_MALLOC(size, allocator_data) (malloc(size))
#endif
#ifndef SLJIT_FREE
-#define SLJIT_FREE(ptr, allocator_data) free(ptr)
+#define SLJIT_FREE(ptr, allocator_data) (free(ptr))
#endif
#ifndef SLJIT_MEMCPY
-#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
+#define SLJIT_MEMCPY(dest, src, len) (memcpy(dest, src, len))
#endif
#ifndef SLJIT_MEMMOVE
-#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len)
+#define SLJIT_MEMMOVE(dest, src, len) (memmove(dest, src, len))
#endif
#ifndef SLJIT_ZEROMEM
-#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len)
+#define SLJIT_ZEROMEM(dest, len) (memset(dest, 0, len))
#endif
/***************************/
/* Type of public API functions. */
/*********************************/
-#ifndef SLJIT_API_FUNC_ATTRIBUTE
+#ifndef SLJIT_API_FUNC_ATTRIBUTE
#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC)
/* Static ABI functions. For all-in-one programs. */
#endif /* _WIN32 */
#endif
-typedef sljit_uw sljit_p;
+typedef sljit_sw sljit_sp;
+typedef sljit_uw sljit_up;
/* Floating point types. */
typedef float sljit_f32;
#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_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+#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
#else
#error "Result for float to integer conversion is not defined"
#endif
#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)
#endif /* SLJIT_FREE_EXEC */
#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)
-#endif
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
+#define SLJIT_EXEC_OFFSET(code) sljit_exec_offset(code)
+#endif /* SLJIT_PROT_EXECUTABLE_ALLOCATOR */
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
#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_TMP_DEST_REG SLJIT_TMP_R0
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_LOCALS_OFFSET_BASE (8 * SSIZE_OF(sw))
#define SLJIT_PREF_SHIFT_REG SLJIT_R2
#define SLJIT_MASKED_SHIFT 1
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 10
#define SLJIT_LOCALS_OFFSET_BASE (4 * SSIZE_OF(sw))
#endif /* !_WIN64 */
+#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_PREF_SHIFT_REG SLJIT_R3
#define SLJIT_MASKED_SHIFT 1
#define SLJIT_MASKED_SHIFT32 1
#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_TMP_DEST_REG SLJIT_TMP_R1
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_LOCALS_OFFSET_BASE 0
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
#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_TMP_DEST_REG SLJIT_TMP_R0
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_LOCALS_OFFSET_BASE (2 * (sljit_s32)sizeof(sljit_sw))
#define SLJIT_MASKED_SHIFT 1
#define SLJIT_MASKED_SHIFT32 1
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 18
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
+#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#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)
#endif
#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 3
+#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_MASKED_SHIFT 1
#define SLJIT_MASKED_SHIFT32 1
#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_TMP_DEST_REG SLJIT_TMP_R1
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_LOCALS_OFFSET_BASE 0
#define SLJIT_MASKED_SHIFT 1
#define SLJIT_MASKED_SHIFT32 1
#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_TMP_DEST_REG SLJIT_TMP_R0
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R2
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_LOCALS_OFFSET_BASE SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE
#define SLJIT_MASKED_SHIFT 1
#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_TMP_DEST_REG SLJIT_TMP_R1
+#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
+#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
#define SLJIT_LOCALS_OFFSET_BASE 0
#define SLJIT_MASKED_SHIFT 1
#define SLJIT_MASKED_SHIFT32 1
#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_TMP_DEST_REG 0
+#define SLJIT_TMP_MEM_REG 0
+#define SLJIT_TMP_DEST_FREG 0
#define SLJIT_LOCALS_OFFSET_BASE 0
#endif
#define SLJIT_SIMD_TYPE_MASK2(m) ((sljit_s32)0xc0000fff & ~(SLJIT_SIMD_FLOAT | SLJIT_SIMD_TEST | (m)))
/* Jump flags. */
-#define JUMP_LABEL 0x1
-#define JUMP_ADDR 0x2
+#define JUMP_ADDR 0x1
+#define JUMP_MOV_ADDR 0x2
/* SLJIT_REWRITABLE_JUMP is 0x1000. */
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
-# define PATCH_MB 0x4
-# define PATCH_MW 0x8
+# define PATCH_MB 0x04
+# define PATCH_MW 0x08
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
# define PATCH_MD 0x10
-#endif
+# define MOV_ADDR_HI 0x20
+# define JUMP_MAX_SIZE ((sljit_uw)(10 + 3))
+# define CJUMP_MAX_SIZE ((sljit_uw)(2 + 10 + 3))
+#else /* !SLJIT_CONFIG_X86_64 */
+# define JUMP_MAX_SIZE ((sljit_uw)5)
+# define CJUMP_MAX_SIZE ((sljit_uw)6)
+#endif /* SLJIT_CONFIG_X86_64 */
# define TYPE_SHIFT 13
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+/* Bits 7..12 is for debug jump size, SLJIT_REWRITABLE_JUMP is 0x1000 */
+# define JUMP_SIZE_SHIFT 7
+#endif /* SLJIT_DEBUG */
#endif /* SLJIT_CONFIG_X86 */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
-# define IS_BL 0x4
-# define PATCH_B 0x8
-#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V6 */
+# define IS_BL 0x04
+# define PATCH_B 0x08
+#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V7 */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
# define CPOOL_SIZE 512
#endif /* SLJIT_CONFIG_ARM_V6 */
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+# define JUMP_SIZE_SHIFT 26
+# define JUMP_MAX_SIZE ((sljit_uw)3)
+#endif /* SLJIT_CONFIG_ARM_V7 */
+
#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
# define IS_COND 0x04
# define IS_BL 0x08
# define PATCH_TYPE1 0x10
/* conditional + imm20 */
# define PATCH_TYPE2 0x20
- /* IT + imm24 */
-# define PATCH_TYPE3 0x30
/* imm11 */
-# define PATCH_TYPE4 0x40
+# define PATCH_TYPE3 0x30
/* imm24 */
-# define PATCH_TYPE5 0x50
+# define PATCH_TYPE4 0x40
/* BL + imm24 */
-# define PATCH_BL 0x60
+# define PATCH_TYPE5 0x50
+ /* addwi/subwi */
+# define PATCH_TYPE6 0x60
/* 0xf00 cc code for branches */
+# define JUMP_SIZE_SHIFT 26
+# define JUMP_MAX_SIZE ((sljit_uw)5)
#endif /* SLJIT_CONFIG_ARM_THUMB2 */
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
# define IS_COND 0x004
# define IS_CBZ 0x008
# define IS_BL 0x010
-# define PATCH_B 0x020
-# define PATCH_COND 0x040
-# define PATCH_ABS48 0x080
-# define PATCH_ABS64 0x100
+# define PATCH_COND 0x020
+# define PATCH_B 0x040
+# define PATCH_B32 0x080
+# define PATCH_ABS48 0x100
+# define PATCH_ABS64 0x200
+# define JUMP_SIZE_SHIFT 58
+# define JUMP_MAX_SIZE ((sljit_uw)5)
#endif /* SLJIT_CONFIG_ARM_64 */
#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
# define PATCH_ABS32 0x040
# define PATCH_ABS48 0x080
+# define JUMP_SIZE_SHIFT 58
+# define JUMP_MAX_SIZE ((sljit_uw)7)
+#else /* !SLJIT_CONFIG_PPC_64 */
+# define JUMP_SIZE_SHIFT 26
+# define JUMP_MAX_SIZE ((sljit_uw)4)
#endif /* SLJIT_CONFIG_PPC_64 */
-# define REMOVE_COND 0x100
#endif /* SLJIT_CONFIG_PPC */
#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
# define PATCH_ABS32 0x080
# define PATCH_ABS44 0x100
# define PATCH_ABS52 0x200
+# define JUMP_SIZE_SHIFT 58
+# define JUMP_MAX_SIZE ((sljit_uw)6)
#else /* !SLJIT_CONFIG_RISCV_64 */
-# define PATCH_REL32 0x0
+# define JUMP_SIZE_SHIFT 26
+# define JUMP_MAX_SIZE ((sljit_uw)2)
#endif /* SLJIT_CONFIG_RISCV_64 */
#endif /* SLJIT_CONFIG_RISCV */
# define PATCH_REL32 0x040
# define PATCH_ABS32 0x080
# define PATCH_ABS52 0x100
+# define JUMP_SIZE_SHIFT 58
+# define JUMP_MAX_SIZE ((sljit_uw)4)
#endif /* SLJIT_CONFIG_LOONGARCH */
/* Stack management. */
/* Utils can still be used even if SLJIT_CONFIG_UNSUPPORTED is set. */
#include "sljitUtils.c"
+#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#define SLJIT_CODE_TO_PTR(code) ((void*)((sljit_up)(code) & ~(sljit_up)0x1))
+#elif (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+#define SLJIT_CODE_TO_PTR(code) ((void*)(*(sljit_up*)code))
+#else /* !SLJIT_CONFIG_ARM_THUMB2 && !SLJIT_INDIRECT_CALL */
+#define SLJIT_CODE_TO_PTR(code) ((void*)(code))
+#endif /* SLJIT_CONFIG_ARM_THUMB2 || SLJIT_INDIRECT_CALL */
+
#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
static void init_compiler(void);
#endif
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data)
{
struct sljit_compiler *compiler = (struct sljit_compiler*)SLJIT_MALLOC(sizeof(struct sljit_compiler), allocator_data);
if (!compiler)
sizeof(sljit_s8) == 1 && sizeof(sljit_u8) == 1
&& sizeof(sljit_s16) == 2 && sizeof(sljit_u16) == 2
&& sizeof(sljit_s32) == 4 && sizeof(sljit_u32) == 4
- && (sizeof(sljit_p) == 4 || sizeof(sljit_p) == 8)
- && sizeof(sljit_p) <= sizeof(sljit_sw)
+ && (sizeof(sljit_up) == 4 || sizeof(sljit_up) == 8)
+ && sizeof(sljit_up) <= sizeof(sljit_sw)
+ && sizeof(sljit_up) == sizeof(sljit_sp)
&& (sizeof(sljit_sw) == 4 || sizeof(sljit_sw) == 8)
- && (sizeof(sljit_uw) == 4 || sizeof(sljit_uw) == 8),
+ && (sizeof(sljit_uw) == sizeof(sljit_sw)),
invalid_integer_types);
SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_32,
rewritable_jump_and_single_op_must_not_be_the_same);
compiler->error = SLJIT_SUCCESS;
compiler->allocator_data = allocator_data;
- compiler->exec_allocator_data = exec_allocator_data;
compiler->buf = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, allocator_data);
compiler->abuf = (struct sljit_memory_fragment*)SLJIT_MALLOC(ABUF_SIZE, allocator_data);
compiler->error = SLJIT_ERR_ALLOC_FAILED;
}
-#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
{
SLJIT_UNUSED_ARG(exec_allocator_data);
- /* Remove thumb mode flag. */
- SLJIT_FREE_EXEC((void*)((sljit_uw)code & ~(sljit_uw)0x1), exec_allocator_data);
+ SLJIT_FREE_EXEC(SLJIT_CODE_TO_PTR(code), exec_allocator_data);
}
-#elif (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
-{
- SLJIT_UNUSED_ARG(exec_allocator_data);
-
- /* Resolve indirection. */
- code = (void*)(*(sljit_uw*)code);
- SLJIT_FREE_EXEC(code, exec_allocator_data);
-}
-#else
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
-{
- SLJIT_UNUSED_ARG(exec_allocator_data);
-
- SLJIT_FREE_EXEC(code, exec_allocator_data);
-}
-#endif
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label)
{
if (SLJIT_LIKELY(!!jump) && SLJIT_LIKELY(!!label)) {
jump->flags &= (sljit_uw)~JUMP_ADDR;
- jump->flags |= JUMP_LABEL;
jump->u.label = label;
}
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target)
{
if (SLJIT_LIKELY(!!jump)) {
- jump->flags &= (sljit_uw)~JUMP_LABEL;
jump->flags |= JUMP_ADDR;
jump->u.target = target;
}
}
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label)
-{
- if (SLJIT_LIKELY(!!put_label))
- put_label->label = label;
-}
-
#define SLJIT_CURRENT_FLAGS_ALL \
(SLJIT_CURRENT_FLAGS_32 | SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB | SLJIT_CURRENT_FLAGS_COMPARE)
compiler->buf = prev;
}
-/* Only used in RISC architectures where the instruction size is constant */
-#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
- && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
-
-static SLJIT_INLINE sljit_uw compute_next_addr(struct sljit_label *label, struct sljit_jump *jump,
- struct sljit_const *const_, struct sljit_put_label *put_label)
+static SLJIT_INLINE void* allocate_executable_memory(sljit_uw size, sljit_s32 options,
+ void *exec_allocator_data, sljit_sw *executable_offset)
{
- sljit_uw result = ~(sljit_uw)0;
+ void *code;
+ struct sljit_generate_code_buffer *buffer;
+
+ if (SLJIT_LIKELY(!(options & SLJIT_GENERATE_CODE_BUFFER))) {
+ code = SLJIT_MALLOC_EXEC(size, exec_allocator_data);
+ *executable_offset = SLJIT_EXEC_OFFSET(code);
+ return code;
+ }
+
+ buffer = (struct sljit_generate_code_buffer*)exec_allocator_data;
+
+ if (size <= buffer->size) {
+ *executable_offset = buffer->executable_offset;
+ return buffer->buffer;
+ }
+
+ return NULL;
+}
+
+#define SLJIT_MAX_ADDRESS ~(sljit_uw)0
+
+#define SLJIT_GET_NEXT_SIZE(ptr) (ptr != NULL) ? ((ptr)->size) : SLJIT_MAX_ADDRESS
+#define SLJIT_GET_NEXT_ADDRESS(ptr) (ptr != NULL) ? ((ptr)->addr) : SLJIT_MAX_ADDRESS
+
+#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+
+#define SLJIT_NEXT_DEFINE_TYPES \
+ sljit_uw next_label_size; \
+ sljit_uw next_jump_addr; \
+ sljit_uw next_const_addr; \
+ sljit_uw next_min_addr
+
+#define SLJIT_NEXT_INIT_TYPES() \
+ next_label_size = SLJIT_GET_NEXT_SIZE(label); \
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); \
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
- if (label)
- result = label->size;
+#define SLJIT_GET_NEXT_MIN() \
+ next_min_addr = sljit_get_next_min(next_label_size, next_jump_addr, next_const_addr);
- if (jump && jump->addr < result)
- result = jump->addr;
+static SLJIT_INLINE sljit_uw sljit_get_next_min(sljit_uw next_label_size,
+ sljit_uw next_jump_addr, sljit_uw next_const_addr)
+{
+ sljit_uw result = next_jump_addr;
+
+ SLJIT_ASSERT(result == SLJIT_MAX_ADDRESS || result != next_const_addr);
- if (const_ && const_->addr < result)
- result = const_->addr;
+ if (next_const_addr < result)
+ result = next_const_addr;
- if (put_label && put_label->addr < result)
- result = put_label->addr;
+ if (next_label_size < result)
+ result = next_label_size;
return result;
}
-#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_S390X */
+#endif /* !SLJIT_CONFIG_X86 */
static SLJIT_INLINE void set_emit_enter(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
static SLJIT_INLINE void set_label(struct sljit_label *label, struct sljit_compiler *compiler)
{
label->next = NULL;
+ label->u.index = compiler->label_count++;
label->size = compiler->size;
- if (compiler->last_label)
+ if (compiler->last_label != NULL)
compiler->last_label->next = label;
else
compiler->labels = label;
{
jump->next = NULL;
jump->flags = flags;
- if (compiler->last_jump)
+ jump->u.label = NULL;
+ if (compiler->last_jump != NULL)
+ compiler->last_jump->next = jump;
+ else
+ compiler->jumps = jump;
+ compiler->last_jump = jump;
+}
+
+static SLJIT_INLINE void set_mov_addr(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_uw offset)
+{
+ jump->next = NULL;
+ jump->addr = compiler->size - offset;
+ jump->flags = JUMP_MOV_ADDR;
+ jump->u.label = NULL;
+ if (compiler->last_jump != NULL)
compiler->last_jump->next = jump;
else
compiler->jumps = jump;
{
const_->next = NULL;
const_->addr = compiler->size;
- if (compiler->last_const)
+ if (compiler->last_const != NULL)
compiler->last_const->next = const_;
else
compiler->consts = const_;
compiler->last_const = const_;
}
-static SLJIT_INLINE void set_put_label(struct sljit_put_label *put_label, struct sljit_compiler *compiler, sljit_uw offset)
-{
- put_label->next = NULL;
- put_label->label = NULL;
- put_label->addr = compiler->size - offset;
- put_label->flags = 0;
- if (compiler->last_put_label)
- compiler->last_put_label->next = put_label;
- else
- compiler->put_labels = put_label;
- compiler->last_put_label = put_label;
-}
-
#define ADDRESSING_DEPENDS_ON(exp, reg) \
(((exp) & SLJIT_MEM) && (((exp) & REG_MASK) == reg || OFFS_REG(exp) == reg))
"ashr", "mashr", "rotl", "rotr"
};
+static const char* op2r_names[] = {
+ "muladd"
+};
+
static const char* op_src_dst_names[] = {
"fast_return", "skip_frames_before_fast_return",
"prefetch_l1", "prefetch_l2",
jump = compiler->jumps;
while (jump) {
/* All jumps have target. */
- CHECK_ARGUMENT(jump->flags & (JUMP_LABEL | JUMP_ADDR));
+ CHECK_ARGUMENT((jump->flags & JUMP_ADDR) || jump->u.label != NULL);
jump = jump->next;
}
#endif
CHECK_RETURN_OK;
}
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#define SLJIT_ENTER_CPU_SPECIFIC_OPTIONS (SLJIT_ENTER_USE_VEX)
+#else /* !SLJIT_CONFIG_X86 */
+#define SLJIT_ENTER_CPU_SPECIFIC_OPTIONS (0)
+#endif /* !SLJIT_CONFIG_X86 */
+
static SLJIT_INLINE CHECK_RETURN_TYPE check_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)
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
if (options & SLJIT_ENTER_REG_ARG) {
- CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG)));
+ CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG | SLJIT_ENTER_CPU_SPECIFIC_OPTIONS)));
} else {
- CHECK_ARGUMENT(options == 0);
+ CHECK_ARGUMENT((options & ~SLJIT_ENTER_CPU_SPECIFIC_OPTIONS) == 0);
}
CHECK_ARGUMENT(SLJIT_KEPT_SAVEDS_COUNT(options) <= 3 && SLJIT_KEPT_SAVEDS_COUNT(options) <= saveds);
CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS);
fprintf(compiler->verbose, "],");
if (options & SLJIT_ENTER_REG_ARG) {
- fprintf(compiler->verbose, " enter:reg_arg,");
-
if (SLJIT_KEPT_SAVEDS_COUNT(options) > 0)
- fprintf(compiler->verbose, " keep:%d,", SLJIT_KEPT_SAVEDS_COUNT(options));
+ fprintf(compiler->verbose, " opt:reg_arg(%d),", SLJIT_KEPT_SAVEDS_COUNT(options));
+ else
+ fprintf(compiler->verbose, " opt:reg_arg,");
+ }
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+ if (options & SLJIT_ENTER_USE_VEX) {
+ fprintf(compiler->verbose, " opt:use_vex,");
}
+#endif /* !SLJIT_CONFIG_X86 */
fprintf(compiler->verbose, " scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n",
scratches, saveds, fscratches, fsaveds, local_size);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
if (options & SLJIT_ENTER_REG_ARG) {
- CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG)));
+ CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG | SLJIT_ENTER_CPU_SPECIFIC_OPTIONS)));
} else {
- CHECK_ARGUMENT(options == 0);
+ CHECK_ARGUMENT((options & ~SLJIT_ENTER_CPU_SPECIFIC_OPTIONS) == 0);
}
CHECK_ARGUMENT(SLJIT_KEPT_SAVEDS_COUNT(options) <= 3 && SLJIT_KEPT_SAVEDS_COUNT(options) <= saveds);
CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS);
fprintf(compiler->verbose, "],");
if (options & SLJIT_ENTER_REG_ARG) {
- fprintf(compiler->verbose, " enter:reg_arg,");
-
if (SLJIT_KEPT_SAVEDS_COUNT(options) > 0)
- fprintf(compiler->verbose, " keep:%d,", SLJIT_KEPT_SAVEDS_COUNT(options));
+ fprintf(compiler->verbose, " opt:reg_arg(%d),", SLJIT_KEPT_SAVEDS_COUNT(options));
+ else
+ fprintf(compiler->verbose, " opt:reg_arg,");
+ }
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+ if (options & SLJIT_ENTER_USE_VEX) {
+ fprintf(compiler->verbose, " opt:use_vex,");
}
+#endif /* !SLJIT_CONFIG_X86 */
fprintf(compiler->verbose, " scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n",
scratches, saveds, fscratches, fsaveds, local_size);
CHECK_RETURN_OK;
}
+#undef SLJIT_ENTER_CPU_SPECIFIC_OPTIONS
+
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return_void(struct sljit_compiler *compiler)
{
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
CHECK_RETURN_OK;
}
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT((op | SLJIT_32) == SLJIT_MULADD32);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg));
+ FUNCTION_CHECK_SRC(src1, src1w);
+ FUNCTION_CHECK_SRC(src2, src2w);
+ compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " %s%s ", op2r_names[GET_OPCODE(op) - SLJIT_OP2R_BASE], !(op & SLJIT_32) ? "" : "32");
+
+ sljit_verbose_reg(compiler, dst_reg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_param(compiler, src1, src1w);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_param(compiler, src2, src2w);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst_reg,
sljit_s32 src1_reg,
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
if (type == SLJIT_GP_REGISTER) {
CHECK_ARGUMENT((reg > 0 && reg <= SLJIT_NUMBER_OF_REGISTERS)
- || (reg >= SLJIT_TMP_REGISTER_BASE && reg <= (SLJIT_TMP_REGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_REGISTERS)));
+ || (reg >= SLJIT_TMP_REGISTER_BASE && reg < (SLJIT_TMP_REGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_REGISTERS)));
} else {
CHECK_ARGUMENT(type == SLJIT_FLOAT_REGISTER || ((type >> 12) == 0 || ((type >> 12) >= 3 && (type >> 12) <= 6)));
CHECK_ARGUMENT((reg > 0 && reg <= SLJIT_NUMBER_OF_FLOAT_REGISTERS)
- || (reg >= SLJIT_TMP_FREGISTER_BASE && reg <= (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS)));
+ || (reg >= SLJIT_TMP_FREGISTER_BASE && reg < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS)));
}
#endif
CHECK_RETURN_OK;
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
FUNCTION_CHECK_DST(dst, dstw);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " put_label ");
+ fprintf(compiler->verbose, " mov_addr ");
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, "\n");
}
# include "sljitNativeLOONGARCH_64.c"
#endif
+#include "sljitSerialize.c"
+
static SLJIT_INLINE sljit_s32 emit_mov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
&& !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \
- && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+ && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ && !(defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 freg,
struct sljit_label {
struct sljit_label *next;
- sljit_uw addr;
+ union {
+ sljit_uw index;
+ sljit_uw addr;
+ } u;
/* The maximum size difference. */
sljit_uw size;
};
} u;
};
-struct sljit_put_label {
- struct sljit_put_label *next;
- struct sljit_label *label;
- sljit_uw addr;
- sljit_uw flags;
-};
-
struct sljit_const {
struct sljit_const *next;
sljit_uw addr;
};
+struct sljit_generate_code_buffer {
+ void *buffer;
+ sljit_uw size;
+ sljit_sw executable_offset;
+};
+
struct sljit_compiler {
sljit_s32 error;
sljit_s32 options;
struct sljit_label *labels;
struct sljit_jump *jumps;
- struct sljit_put_label *put_labels;
struct sljit_const *consts;
struct sljit_label *last_label;
struct sljit_jump *last_jump;
struct sljit_const *last_const;
- struct sljit_put_label *last_put_label;
void *allocator_data;
- void *exec_allocator_data;
+ void *user_data;
struct sljit_memory_fragment *buf;
struct sljit_memory_fragment *abuf;
+ /* Number of labels created by the compiler. */
+ sljit_uw label_count;
/* Available scratch registers. */
sljit_s32 scratches;
/* Available saved registers. */
#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
sljit_s32 status_flags_state;
-#endif
+#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
sljit_s32 args_size;
-#endif
+#endif /* SLJIT_CONFIG_X86_32 */
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ /* Temporary fields. */
sljit_s32 mode32;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
/* Constant pool handling. */
/* Other members. */
/* Contains pointer, "ldr pc, [...]" pairs. */
sljit_uw patches;
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
/* Temporary fields. */
#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)
sljit_uw args_size;
-#endif
+#endif /* SLJIT_CONFIG_ARM_32 && __SOFTFP__ */
#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+ /* Temporary fields. */
sljit_u32 imm;
-#endif
+#endif /* SLJIT_CONFIG_PPC */
#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
sljit_s32 delay_slot;
+ /* Temporary fields. */
sljit_s32 cache_arg;
sljit_sw cache_argw;
-#endif
+#endif /* SLJIT_CONFIG_MIPS */
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
sljit_uw args_size;
-#endif
+#endif /* SLJIT_CONFIG_MIPS_32 */
#if (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
+ /* Temporary fields. */
sljit_s32 cache_arg;
sljit_sw cache_argw;
-#endif
+#endif /* SLJIT_CONFIG_RISCV */
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
/* Need to allocate register save area to make calls. */
+ /* Temporary fields. */
sljit_s32 mode;
-#endif
+#endif /* SLJIT_CONFIG_S390X */
#if (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+ /* Temporary fields. */
sljit_s32 cache_arg;
sljit_sw cache_argw;
-#endif
+#endif /* SLJIT_CONFIG_LOONGARCH */
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
FILE* verbose;
-#endif
+#endif /* SLJIT_VERBOSE */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG)
sljit_s32 last_return;
/* Local size passed to entry functions. */
sljit_s32 logical_local_size;
-#endif
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG) \
/* Trust arguments when an API function is called.
Used internally for calling API functions. */
sljit_s32 skip_checks;
-#endif
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG || SLJIT_VERBOSE */
};
/* --------------------------------------------------------------------- */
custom memory managers. This pointer is passed to SLJIT_MALLOC
and SLJIT_FREE macros. Most allocators (including the default
one) ignores this value, and it is recommended to pass NULL
- as a dummy value for allocator_data. The exec_allocator_data
- has the same purpose but this one is passed to SLJIT_MALLOC_EXEC /
- SLJIT_MALLOC_FREE functions.
+ as a dummy value for allocator_data.
Returns NULL if failed. */
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data);
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data);
/* Frees everything except the compiled machine code. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler);
of the compiler to out-of-memory status). */
SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size);
-/* Returns the allocator data passed to sljit_create_compiler. These pointers
- may contain context data even if the normal/exec allocator ignores it. */
-static SLJIT_INLINE void* sljit_get_allocator_data(struct sljit_compiler *compiler) { return compiler->allocator_data; }
-static SLJIT_INLINE void* sljit_get_exec_allocator_data(struct sljit_compiler *compiler) { return compiler->exec_allocator_data; }
+/* Returns the allocator data passed to sljit_create_compiler. */
+static SLJIT_INLINE void* sljit_compiler_get_allocator_data(struct sljit_compiler *compiler) { return compiler->allocator_data; }
+/* Sets/get the user data for a compiler. */
+static SLJIT_INLINE void sljit_compiler_set_user_data(struct sljit_compiler *compiler, void *user_data) { compiler->user_data = user_data; }
+static SLJIT_INLINE void* sljit_compiler_get_user_data(struct sljit_compiler *compiler) { return compiler->user_data; }
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
/* Passing NULL disables verbose. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose);
#endif
+/* Option bits for sljit_generate_code. */
+
+/* The exec_allocator_data points to a pre-allocated
+ buffer which type is sljit_generate_code_buffer. */
+#define SLJIT_GENERATE_CODE_BUFFER 0x1
+
/* Create executable code from the instruction stream. This is the final step
- of the code generation so no more instructions can be emitted after this call. */
+ of the code generation, and no more instructions can be emitted after this call.
+
+ options is the combination of SLJIT_GENERATE_CODE_* bits
+ exec_allocator_data is passed to SLJIT_MALLOC_EXEC and
+ SLJIT_MALLOC_FREE functions */
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler);
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data);
/* Free executable code. */
#define SLJIT_HAS_AVX2 101
#endif
+#if (defined SLJIT_CONFIG_LOONGARCH)
+/* [Not emulated] LASX support is available on LoongArch */
+#define SLJIT_HAS_LASX 201
+#endif
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type);
/* If type is between SLJIT_ORDERED_EQUAL and SLJIT_ORDERED_LESS_EQUAL,
global / local context pointers) across function calls. The
value of n must be between 1 and 3. This option is only
supported by SLJIT_ENTER_REG_ARG calling convention. */
-#define SLJIT_ENTER_KEEP(n) (n)
+#define SLJIT_ENTER_KEEP(n) (n)
/* The compiled function uses an SLJIT specific register argument
calling convention. This is a lightweight function call type where
both the caller and the called functions must be compiled by
SLJIT. The type argument of the call must be SLJIT_CALL_REG_ARG
and all arguments must be stored in scratch registers. */
-#define SLJIT_ENTER_REG_ARG 0x00000004
+#define SLJIT_ENTER_REG_ARG 0x00000004
/* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */
-#define SLJIT_MAX_LOCAL_SIZE 1048576
+#define SLJIT_MAX_LOCAL_SIZE 1048576
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+/* Use VEX prefix for all SIMD operations on x86. */
+#define SLJIT_ENTER_USE_VEX 0x00010000
+#endif /* !SLJIT_CONFIG_X86 */
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,
int | 4 byte (physical_address & 0x3 == 0)
word | 4 byte if SLJIT_32BIT_ARCHITECTURE is defined and its value is 1
| 8 byte if SLJIT_64BIT_ARCHITECTURE is defined and its value is 1
- pointer | size of sljit_p type (4 byte on 32 bit machines, 4 or 8 byte
+ pointer | size of sljit_up type (4 byte on 32 bit machines, 4 or 8 byte
| on 64 bit machines)
Note: Different architectures have different addressing limitations.
#define SLJIT_IS_IMM(arg) ((arg) == SLJIT_IMM)
#define SLJIT_IS_REG_PAIR(arg) (!((arg) & SLJIT_MEM) && (arg) >= (SLJIT_MEM << 1))
+/* Macros for extracting registers from operands. */
+/* Support operands which contains a single register or
+ constructed using SLJIT_MEM1, SLJIT_MEM2, or SLJIT_REG_PAIR. */
+#define SLJIT_EXTRACT_REG(arg) ((arg) & 0x7f)
+/* Support operands which constructed using SLJIT_MEM2, or SLJIT_REG_PAIR. */
+#define SLJIT_EXTRACT_SECOND_REG(arg) ((arg) >> 8)
+
/* Sets 32 bit operation mode on 64 bit CPUs. This option is ignored on
32 bit CPUs. When this option is set for an arithmetic operation, only
the lower 32 bits of the input registers are used, and the CPU status
S16 - signed 16 bit data transfer
U32 - unsigned int (32 bit) data transfer
S32 - signed int (32 bit) data transfer
- P - pointer (sljit_p) data transfer
+ P - pointer (sljit_up) data transfer
*/
/* Flags: - (does not modify flags) */
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w);
+/* Starting index of opcodes for sljit_emit_op2r. */
+#define SLJIT_OP2R_BASE 96
+
+/* Flags: - (may destroy flags) */
+#define SLJIT_MULADD (SLJIT_OP2R_BASE + 0)
+#define SLJIT_MULADD32 (SLJIT_MULADD | SLJIT_32)
+
+/* Similar to sljit_emit_fop2, except the destination is always a register. */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w);
+
/* Emit a left or right shift operation, where the bits shifted
in comes from a separate source operand. All operands are
interpreted as unsigned integers.
/* Starting index of opcodes for sljit_emit_op_src
and sljit_emit_op_dst. */
-#define SLJIT_OP_SRC_DST_BASE 96
+#define SLJIT_OP_SRC_DST_BASE 112
/* Fast return, see SLJIT_FAST_CALL for more details.
Note: src cannot be an immedate value
sljit_s32 dst, sljit_sw dstw);
/* Starting index of opcodes for sljit_emit_fop1. */
-#define SLJIT_FOP1_BASE 128
+#define SLJIT_FOP1_BASE 144
/* Flags: - (does not modify flags) */
#define SLJIT_MOV_F64 (SLJIT_FOP1_BASE + 0)
sljit_s32 src, sljit_sw srcw);
/* Starting index of opcodes for sljit_emit_fop2. */
-#define SLJIT_FOP2_BASE 160
+#define SLJIT_FOP2_BASE 176
/* Flags: - (may destroy flags) */
#define SLJIT_ADD_F64 (SLJIT_FOP2_BASE + 0)
sljit_s32 src2, sljit_sw src2w);
/* Starting index of opcodes for sljit_emit_fop2r. */
-#define SLJIT_FOP2R_BASE 168
+#define SLJIT_FOP2R_BASE 192
/* Flags: - (may destroy flags) */
#define SLJIT_COPYSIGN_F64 (SLJIT_FOP2R_BASE + 0)
Flags: - (does not modify flags) */
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value);
-/* Store the value of a label (see: sljit_set_put_label)
+/* Store the value of a label (see: sljit_set_label / sljit_set_target)
Flags: - (does not modify flags) */
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
-
-/* Set the value stored by put_label to this label. */
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label);
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
-/* After the code generation the address for label, jump and const instructions
- are computed. Since these structures are freed by sljit_free_compiler, the
- addresses must be preserved by the user program elsewere. */
-static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { return label->addr; }
+/* Provides the address of label, jump and const instructions after sljit_generate_code
+ is called. The returned value is unspecified before the sljit_generate_code call.
+ Since these structures are freed by sljit_free_compiler, the addresses must be
+ preserved by the user program elsewere. */
+static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { return label->u.addr; }
static SLJIT_INLINE sljit_uw sljit_get_jump_addr(struct sljit_jump *jump) { return jump->addr; }
static SLJIT_INLINE sljit_uw sljit_get_const_addr(struct sljit_const *const_) { return const_->addr; }
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler,
sljit_s32 current_flags);
+/* --------------------------------------------------------------------- */
+/* Serialization functions */
+/* --------------------------------------------------------------------- */
+
+/* Label/jump/const enumeration functions. The items in each group
+ are enumerated in creation order. Serialization / deserialization
+ preserves this order for each group. For example the fifth label
+ after deserialization refers to the same machine code location as
+ the fifth label before the serialization. */
+static SLJIT_INLINE struct sljit_label *sljit_get_first_label(struct sljit_compiler *compiler) { return compiler->labels; }
+static SLJIT_INLINE struct sljit_jump *sljit_get_first_jump(struct sljit_compiler *compiler) { return compiler->jumps; }
+static SLJIT_INLINE struct sljit_const *sljit_get_first_const(struct sljit_compiler *compiler) { return compiler->consts; }
+
+static SLJIT_INLINE struct sljit_label *sljit_get_next_label(struct sljit_label *label) { return label->next; }
+static SLJIT_INLINE struct sljit_jump *sljit_get_next_jump(struct sljit_jump *jump) { return jump->next; }
+static SLJIT_INLINE struct sljit_const *sljit_get_next_const(struct sljit_const *const_) { return const_->next; }
+
+/* A number starting from 0 is assigned to each label, which
+represents its creation index. The first label created by the
+compiler has index 0, the second has index 1, the third has
+index 2, and so on. The returned value is unspecified after
+sljit_generate_code() is called. */
+static SLJIT_INLINE sljit_uw sljit_get_label_index(struct sljit_label *label) { return label->u.index; }
+
+/* The sljit_jump_has_label() and sljit_jump_has_target() functions
+returns non-zero value if a label or target is set for the jump
+respectively. Both may return with a zero value. The other two
+functions return the value assigned to the jump. */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_label(struct sljit_jump *jump);
+static SLJIT_INLINE struct sljit_label *sljit_jump_get_label(struct sljit_jump *jump) { return jump->u.label; }
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_target(struct sljit_jump *jump);
+static SLJIT_INLINE sljit_uw sljit_jump_get_target(struct sljit_jump *jump) { return jump->u.target; }
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_is_mov_addr(struct sljit_jump *jump);
+
+/* Option bits for sljit_serialize_compiler. */
+
+/* When debugging is enabled, the serialized buffer contains
+debugging information unless this option is specified. */
+#define SLJIT_SERIALIZE_IGNORE_DEBUG 0x1
+
+/* Serialize the internal structure of the compiler into a buffer.
+If the serialization is successful, the returned value is a newly
+allocated buffer which is allocated by the memory allocator assigned
+to the compiler. Otherwise the returned value is NULL. Unlike
+sljit_generate_code(), serialization does not modify the internal
+state of the compiler, so the code generation can be continued.
+
+ options must be the combination of SLJIT_SERIALIZE_* option bits
+ size is an output argument, which is set to the byte size of
+ the result buffer if the operation is successful
+
+Notes:
+ - This function is useful for ahead-of-time compilation (AOT).
+ - The returned buffer must be freed later by the caller.
+ The SLJIT_FREE() macro is suitable for this purpose:
+ SLJIT_FREE(returned_buffer, sljit_get_allocator_data(compiler))
+ - Memory allocated by sljit_alloc_memory() is not serialized.
+ - The type of the returned buffer is sljit_uw* to emphasize that
+ the buffer is word aligned. However, the 'size' output argument
+ contains the byte size, so this value is always divisible by
+ sizeof(sljit_uw).
+*/
+SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_uw *size);
+
+/* Construct a new compiler instance from a buffer produced by
+sljit_serialize_compiler(). If the operation is successful, the new
+compiler instance is returned. Otherwise the returned value is NULL.
+
+ buffer points to a word aligned memory data which was
+ created by sljit_serialize_compiler()
+ size is the byte size of the buffer
+ options must be 0
+ allocator_data specify an allocator specific data, see
+ sljit_create_compiler() for further details
+
+Notes:
+ - Labels assigned to jumps are restored with their
+ corresponding label in the label set created by
+ the deserializer. Target addresses assigned to
+ jumps are also restored. Uninitialized jumps
+ remain uninitialized.
+ - After the deserialization, sljit_generate_code() does
+ not need to be the next operation on the returned
+ compiler, the code generation can be continued.
+ Even sljit_serialize_compiler() can be called again.
+ - When debugging is enabled, a buffers without debug
+ information cannot be deserialized.
+*/
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit_uw* buffer, sljit_uw size,
+ sljit_s32 options, void *allocator_data);
+
/* --------------------------------------------------------------------- */
/* Miscellaneous utility functions */
/* --------------------------------------------------------------------- */
#define LDREX 0xe1900f9f
#define LDREXB 0xe1d00f9f
#define LDREXH 0xe1f00f9f
+#define MLA 0xe0200090
#define MOV 0xe1a00000
#define MUL 0xe0000090
#define MVN 0xe1e00000
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (jump->flags & IS_BL)
code_ptr--;
+#endif /* SLJIT_CONFIG_ARM_V6 */
if (jump->flags & JUMP_ADDR)
diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset);
else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+ SLJIT_ASSERT(jump->u.label != NULL);
diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2));
}
if (diff & 0x3)
return 0;
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (jump->flags & IS_BL) {
if (diff <= 0x01ffffff && diff >= -0x02000000) {
*code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK);
}
}
#else /* !SLJIT_CONFIG_ARM_V6 */
- if (jump->flags & JUMP_ADDR)
- diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr - executable_offset);
- else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
- diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)code_ptr);
- }
-
- /* Branch to Thumb code has not been optimized yet. */
- if (diff & 0x3)
- return 0;
-
if (diff <= 0x01ffffff && diff >= -0x02000000) {
- code_ptr -= 2;
- *code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (code_ptr[2] & COND_MASK);
+ *code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (*code_ptr & COND_MASK);
jump->flags |= PATCH_B;
return 1;
}
return 0;
}
-static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache)
+static void set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache)
{
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
sljit_ins *ptr = (sljit_ins*)jump_ptr;
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm);
static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg);
-static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_offset, sljit_uw new_constant, sljit_s32 flush_cache)
+static void set_const_value(sljit_uw addr, sljit_sw executable_offset, sljit_uw new_constant, sljit_s32 flush_cache)
{
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
sljit_ins *ptr = (sljit_ins*)addr;
#endif /* SLJIT_CONFIG_ARM_V6 */
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+{
+ sljit_uw addr;
+ sljit_sw diff;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ /* The pc+8 offset is represented by the 2 * SSIZE_OF(ins) below. */
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ if ((diff & 0x3) == 0 && diff <= (0x3fc + 2 * SSIZE_OF(ins)) && diff >= (-0x3fc + 2 * SSIZE_OF(ins))) {
+ jump->flags |= PATCH_B;
+ return 0;
+ }
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ return 0;
+#else /* !SLJIT_CONFIG_ARM_V6 */
+ return 1;
+#endif /* SLJIT_CONFIG_ARM_V6 */
+}
+
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_uw total_size;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+ SLJIT_NEXT_INIT_TYPES();
+
+ while (1) {
+ SLJIT_GET_NEXT_MIN();
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr == next_const_addr) {
+ const_->addr -= size_reduce;
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ continue;
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ jump->addr -= size_reduce;
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ total_size = JUMP_MAX_SIZE - 1;
+
+ if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2;
+
+ if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins)))
+ total_size = 1 - 1;
+ }
+
+ size_reduce += JUMP_MAX_SIZE - 1 - total_size;
+ } else {
+ /* Real size minus 1. Unit size: instruction. */
+ total_size = 1;
+
+ if (!(jump->flags & JUMP_ADDR)) {
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+ if (diff <= 0xff + 2 && diff >= -0xff + 2)
+ total_size = 0;
+ }
+
+ size_reduce += 1 - total_size;
+ }
+
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
+}
+
+#endif /* SLJIT_CONFIG_ARM_V7 */
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_ins *code;
sljit_ins *code_ptr;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
- sljit_uw size;
sljit_uw word_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
sljit_sw executable_offset;
sljit_uw addr;
+ sljit_sw diff;
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
sljit_uw cpool_size;
sljit_uw cpool_skip_alignment;
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);
/* Second code generation pass. */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
- size = compiler->size + (compiler->patches << 1);
+ compiler->size += (compiler->patches << 1);
if (compiler->cpool_fill > 0)
- size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1;
+ compiler->size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1;
#else /* !SLJIT_CONFIG_ARM_V6 */
- size = compiler->size;
+ reduce_code_size(compiler);
#endif /* SLJIT_CONFIG_ARM_V6 */
- code = (sljit_ins*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_ins), compiler->exec_allocator_data);
+ code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
buf = compiler->buf;
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
code_ptr = code;
word_count = 0;
- next_addr = 1;
- executable_offset = SLJIT_EXEC_OFFSET(code);
-
label = compiler->labels;
jump = compiler->jumps;
const_ = compiler->consts;
- put_label = compiler->put_labels;
-
- if (label && label->size == 0) {
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
- label = label->next;
- }
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
do {
buf_ptr = (sljit_ins*)buf->memory;
buf_end = buf_ptr + (buf->used_size >> 2);
do {
- word_count++;
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (cpool_size > 0) {
if (cpool_skip_alignment > 0) {
buf_ptr++;
cpool_skip_alignment--;
- }
- else {
+ } else {
if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {
- SLJIT_FREE_EXEC(code, compiler->exec_allocator_data);
+ SLJIT_FREE_EXEC(code, exec_allocator_data);
compiler->error = SLJIT_ERR_ALLOC_FAILED;
return NULL;
}
if (++cpool_current_index >= cpool_size) {
SLJIT_ASSERT(!first_patch);
cpool_size = 0;
- if (label && label->size == word_count) {
- /* Points after the current instruction. */
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
- label->size = (sljit_uw)(code_ptr - code);
- label = label->next;
-
- next_addr = compute_next_addr(label, jump, const_, put_label);
- }
}
}
- }
- else if ((*buf_ptr & 0xff000000) != PUSH_POOL) {
+ } else if ((*buf_ptr & 0xff000000) != PUSH_POOL) {
#endif /* SLJIT_CONFIG_ARM_V6 */
*code_ptr = *buf_ptr++;
- if (next_addr == word_count) {
+ if (next_min_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 (jump && jump->addr == word_count) {
-#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
- if (detect_jump_type(jump, code_ptr, code, executable_offset))
- code_ptr--;
- jump->addr = (sljit_uw)code_ptr;
-#else /* !SLJIT_CONFIG_ARM_V6 */
- jump->addr = (sljit_uw)(code_ptr - 2);
- if (detect_jump_type(jump, code_ptr, code, executable_offset))
- code_ptr -= 2;
-#endif /* SLJIT_CONFIG_ARM_V6 */
- jump = jump->next;
- }
- if (label && label->size == word_count) {
- /* code_ptr can be affected above. */
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr + 1, executable_offset);
- label->size = (sljit_uw)((code_ptr + 1) - code);
+ if (next_min_addr == next_label_size) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (const_ && const_->addr == word_count) {
+
+ /* These structures are ordered by their address. */
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
- const_->addr = (sljit_uw)code_ptr;
+ if (detect_jump_type(jump, code_ptr, code, executable_offset))
+ code_ptr--;
+ jump->addr = (sljit_uw)code_ptr;
#else /* !SLJIT_CONFIG_ARM_V6 */
- const_->addr = (sljit_uw)(code_ptr - 1);
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+ jump->addr = (sljit_uw)code_ptr;
+ if (!detect_jump_type(jump, code_ptr, code, executable_offset)) {
+ code_ptr[2] = code_ptr[0];
+ addr = ((code_ptr[0] & 0xf) << 12);
+ code_ptr[0] = MOVW | addr;
+ code_ptr[1] = MOVT | addr;
+ code_ptr += 2;
+ }
+ SLJIT_ASSERT((sljit_uw)code_ptr - jump->addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins));
#endif /* SLJIT_CONFIG_ARM_V6 */
+ } else {
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+#endif /* SLJIT_CONFIG_ARM_V7 */
+ addr = (sljit_uw)code_ptr;
+ code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset);
+ jump->addr = addr;
+ }
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
+ const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- if (put_label && put_label->addr == word_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
+
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
last_pc_patch = code_ptr;
}
#endif /* SLJIT_CONFIG_ARM_V6 */
+ word_count++;
} while (buf_ptr < buf_end);
buf = buf->next;
} while (buf);
+ if (label && label->size == word_count) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label->size = (sljit_uw)(code_ptr - code);
+ label = label->next;
+ }
+
SLJIT_ASSERT(!label);
SLJIT_ASSERT(!jump);
SLJIT_ASSERT(!const_);
- SLJIT_ASSERT(!put_label);
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
SLJIT_ASSERT(cpool_size == 0);
cpool_current_index = 0;
while (buf_ptr < buf_end) {
if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {
- SLJIT_FREE_EXEC(code, compiler->exec_allocator_data);
+ SLJIT_FREE_EXEC(code, exec_allocator_data);
compiler->error = SLJIT_ERR_ALLOC_FAILED;
return NULL;
}
jump = compiler->jumps;
while (jump) {
+ addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
buf_ptr = (sljit_ins*)jump->addr;
- if (jump->flags & PATCH_B) {
- addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset);
- if (!(jump->flags & JUMP_ADDR)) {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
- SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - addr) <= 0x01ffffff && (sljit_sw)(jump->u.label->addr - addr) >= -0x02000000);
- *buf_ptr |= ((jump->u.label->addr - addr) >> 2) & 0x00ffffff;
- }
- else {
- SLJIT_ASSERT((sljit_sw)(jump->u.target - addr) <= 0x01ffffff && (sljit_sw)(jump->u.target - addr) >= -0x02000000);
- *buf_ptr |= ((jump->u.target - addr) >> 2) & 0x00ffffff;
- }
- }
- else if (jump->flags & SLJIT_REWRITABLE_JUMP) {
+ if (jump->flags & JUMP_MOV_ADDR) {
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
- jump->addr = (sljit_uw)code_ptr;
- code_ptr[0] = (sljit_ins)buf_ptr;
- code_ptr[1] = *buf_ptr;
- inline_set_jump_addr((sljit_uw)code_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
- code_ptr += 2;
+ SLJIT_ASSERT((buf_ptr[0] & (sljit_ins)0xffff0000) == 0xe59f0000);
#else /* !SLJIT_CONFIG_ARM_V6 */
- inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+ SLJIT_ASSERT((buf_ptr[0] & ~(sljit_ins)0xf000) == 0);
#endif /* SLJIT_CONFIG_ARM_V6 */
+
+ if (jump->flags & PATCH_B) {
+ SLJIT_ASSERT((((sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset)) & 0x3) == 0);
+ diff = ((sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset)) >> 2;
+
+ SLJIT_ASSERT(diff <= 0xff && diff >= -0xff);
+
+ addr = ADD;
+ if (diff < 0) {
+ diff = -diff;
+ addr = SUB;
+ }
+
+ buf_ptr[0] = addr | (buf_ptr[0] & 0xf000) | RN(TMP_PC) | (1 << 25) | (0xf << 8) | (sljit_ins)(diff & 0xff);
+ } else {
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr;
+#else /* !SLJIT_CONFIG_ARM_V6 */
+ buf_ptr[1] = MOVT | buf_ptr[0] | ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff);
+ buf_ptr[0] = MOVW | buf_ptr[0] | ((addr << 4) & 0xf0000) | (addr & 0xfff);
+#endif /* SLJIT_CONFIG_ARM_V6 */
+ }
+ } else if (jump->flags & PATCH_B) {
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset);
+ SLJIT_ASSERT(diff <= 0x01ffffff && diff >= -0x02000000);
+ *buf_ptr |= (diff >> 2) & 0x00ffffff;
} else {
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (jump->flags & IS_BL)
buf_ptr--;
- if (*buf_ptr & (1 << 23))
- buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
- else
- buf_ptr += 1;
- *buf_ptr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+
+ if (jump->flags & SLJIT_REWRITABLE_JUMP) {
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr[0] = (sljit_ins)buf_ptr;
+ code_ptr[1] = *buf_ptr;
+ set_jump_addr((sljit_uw)code_ptr, executable_offset, addr, 0);
+ code_ptr += 2;
+ } else {
+ if (*buf_ptr & (1 << 23))
+ buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
+ else
+ buf_ptr += 1;
+ *buf_ptr = addr;
+ }
#else /* !SLJIT_CONFIG_ARM_V6 */
- inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+ set_jump_addr((sljit_uw)buf_ptr, executable_offset, addr, 0);
#endif /* SLJIT_CONFIG_ARM_V6 */
}
+
jump = jump->next;
}
else
buf_ptr += 1;
/* Set the value again (can be a simple constant). */
- inline_set_const((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
+ set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
code_ptr += 2;
const_ = const_->next;
}
#endif /* SLJIT_CONFIG_ARM_V6 */
- put_label = compiler->put_labels;
- while (put_label) {
- addr = put_label->label->addr;
- buf_ptr = (sljit_ins*)put_label->addr;
-
-#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
- SLJIT_ASSERT((buf_ptr[0] & 0xffff0000) == 0xe59f0000);
- buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr;
-#else /* !SLJIT_CONFIG_ARM_V6 */
- SLJIT_ASSERT((buf_ptr[-1] & 0xfff00000) == MOVW && (buf_ptr[0] & 0xfff00000) == MOVT);
- buf_ptr[-1] |= ((addr << 4) & 0xf0000) | (addr & 0xfff);
- buf_ptr[0] |= ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff);
-#endif /* SLJIT_CONFIG_ARM_V6 */
- put_label = put_label->next;
- }
-
- SLJIT_ASSERT(code_ptr - code <= (sljit_s32)size);
+ SLJIT_ASSERT(code_ptr - code <= (sljit_s32)compiler->size);
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
/* Inverted immediate. */
#define INV_IMM 0x02
/* Source and destination is register. */
-#define MOVE_REG_CONV 0x04
+#define REGISTER_OP 0x04
/* Unused return value. */
#define UNUSED_RETURN 0x08
/* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
sljit_uw dst, sljit_uw src1, sljit_uw src2)
{
- sljit_s32 is_masked;
+ sljit_s32 reg, is_masked;
sljit_uw shift_type;
switch (op) {
case SLJIT_MOV_U8:
case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
- if (flags & MOVE_REG_CONV)
+ if (flags & REGISTER_OP)
return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2));
if (dst != src2) {
case SLJIT_MOV_U16:
case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
- if (flags & MOVE_REG_CONV)
+ if (flags & REGISTER_OP)
return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2));
if (dst != src2) {
case SLJIT_CTZ:
SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM));
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
+ SLJIT_ASSERT(src1 == TMP_REG1 && src2 != TMP_REG2 && !(flags & ARGS_SWAPPED));
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
- FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG1) | RN(src2) | 0));
- FAIL_IF(push_inst(compiler, AND | RD(TMP_REG2) | RN(src2) | RM(TMP_REG1)));
- FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0));
+ FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RN(src2) | RM(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(TMP_REG1)));
FAIL_IF(push_inst(compiler, CMP | SET_FLAGS | SRC2_IMM | RN(dst) | 32));
return push_inst(compiler, (EOR ^ 0xf0000000) | SRC2_IMM | RD(dst) | RN(dst) | 0x1f);
#else /* !SLJIT_CONFIG_ARM_V6 */
case SLJIT_REV_U16:
case SLJIT_REV_S16:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED) && src2 != TMP_REG1 && dst != TMP_REG1);
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
FAIL_IF(push_inst(compiler, REV16 | RD(dst) | RM(src2)));
- if (dst == TMP_REG2 || (src2 == TMP_REG2 && op == SLJIT_REV_U16))
+ if (!(flags & REGISTER_OP))
return SLJIT_SUCCESS;
return push_inst(compiler, (op == SLJIT_REV_U16 ? UXTH : SXTH) | RD(dst) | RM(dst));
case SLJIT_ADD:
if (!(flags & SET_FLAGS))
return push_inst(compiler, MUL | RN(dst) | RM8(src2) | RM(src1));
- FAIL_IF(push_inst(compiler, SMULL | RN(TMP_REG1) | RD(dst) | RM8(src2) | RM(src1)));
+ reg = dst == TMP_REG1 ? TMP_REG2 : TMP_REG1;
+ FAIL_IF(push_inst(compiler, SMULL | RN(reg) | RD(dst) | RM8(src2) | RM(src1)));
/* cmp TMP_REG1, dst asr #31. */
- return push_inst(compiler, CMP | SET_FLAGS | RN(TMP_REG1) | RM(dst) | 0xfc0);
+ return push_inst(compiler, CMP | SET_FLAGS | RN(reg) | RM(dst) | 0xfc0);
case SLJIT_AND:
if ((flags & (UNUSED_RETURN | INV_IMM)) == UNUSED_RETURN)
is_masked = 0;
break;
+ case SLJIT_MULADD:
+ return push_inst(compiler, MLA | RN(dst) | RD(dst) | RM8(src2) | RM(src1));
+
default:
SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
sljit_s32 dst_reg;
sljit_s32 src1_reg = 0;
sljit_s32 src2_reg = 0;
+ sljit_s32 src2_tmp_reg = 0;
sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
sljit_s32 neg_op = 0;
sljit_u32 imm2;
if (flags & SET_FLAGS)
inp_flags &= ~ALLOW_DOUBLE_IMM;
- if (dst == TMP_REG2)
+ if (dst == TMP_REG1)
flags |= UNUSED_RETURN;
SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM));
}
} while(0);
- /* Source 1. */
- if (FAST_IS_REG(src1))
- src1_reg = src1;
- else if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
- src1_reg = TMP_REG1;
- } else if (!(inp_flags & ALLOW_DOUBLE_IMM) || src2_reg != 0 || op == SLJIT_SUB || op == SLJIT_SUBC) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
- src1_reg = TMP_REG1;
- }
-
/* Destination. */
dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
inp_flags &= ~SIGNED;
if (FAST_IS_REG(src2))
- return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG2);
+ return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG1);
}
if (FAST_IS_REG(src2) && dst_reg != TMP_REG2)
- flags |= MOVE_REG_CONV;
+ flags |= REGISTER_OP;
+
+ src2_tmp_reg = dst_reg;
+ } else {
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {
+ if (!(dst & SLJIT_MEM) && (!(src2 & SLJIT_MEM) || op == SLJIT_REV_S16))
+ flags |= REGISTER_OP;
+ }
+
+ src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2;
+ }
+
+ if (src2_reg == 0 && (src2 & SLJIT_MEM)) {
+ src2_reg = src2_tmp_reg;
+ FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG1));
+ }
+
+ /* Source 1. */
+ if (FAST_IS_REG(src1))
+ src1_reg = src1;
+ else if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
+ src1_reg = TMP_REG1;
+ } else if (!(inp_flags & ALLOW_DOUBLE_IMM) || src2_reg != 0 || op == SLJIT_SUB || op == SLJIT_SUBC) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
+ src1_reg = TMP_REG1;
}
/* Source 2. */
if (src2_reg == 0) {
- src2_reg = (op <= SLJIT_MOV_P) ? dst_reg : TMP_REG2;
+ src2_reg = src2_tmp_reg;
if (FAST_IS_REG(src2))
src2_reg = src2;
- else if (src2 & SLJIT_MEM)
- FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG2));
else if (!(inp_flags & ALLOW_DOUBLE_IMM))
FAIL_IF(load_immediate(compiler, src2_reg, (sljit_uw)src2w));
else {
}
if (src2_reg == 0) {
- FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)src2w));
- src2_reg = TMP_REG2;
+ FAIL_IF(load_immediate(compiler, src2_tmp_reg, (sljit_uw)src2w));
+ src2_reg = src2_tmp_reg;
} else {
FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg));
src1_reg = dst_reg;
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, TMP_REG1, 0, src1, src1w, src2, src2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ return emit_op(compiler, op, 0, dst_reg, 0, src1, src1w, src2, src2w);
+ }
+
+ return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
arg &= ~SLJIT_MEM;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
- FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_ins)argw & 0x3) << 7)));
- arg = TMP_REG2;
+ FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_ins)argw & 0x3) << 7)));
+ arg = TMP_REG1;
argw = 0;
}
imm = get_imm((sljit_uw)argw & ~(sljit_uw)0x3fc);
if (imm) {
- FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | imm));
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, (argw & 0x3fc) >> 2));
+ FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | imm));
+ return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, (argw & 0x3fc) >> 2));
}
imm = get_imm((sljit_uw)-argw & ~(sljit_uw)0x3fc);
if (imm) {
argw = -argw;
- FAIL_IF(push_inst(compiler, SUB | RD(TMP_REG2) | RN(arg & REG_MASK) | imm));
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG2, reg, (argw & 0x3fc) >> 2));
+ FAIL_IF(push_inst(compiler, SUB | RD(TMP_REG1) | RN(arg & REG_MASK) | imm));
+ return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG1, reg, (argw & 0x3fc) >> 2));
}
}
if (arg) {
- FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)argw));
- FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(TMP_REG2)));
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw));
+ FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(TMP_REG1)));
}
else
- FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)argw));
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw));
- return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, 0));
+ return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, 0));
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
switch (GET_OPCODE(op)) {
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_32, dst_r, src, 0)));
else
dst_r = src;
return push_inst(compiler, EMIT_FPU_OPERATION((VNEG_F32 & ~COND_MASK) | 0xb0000000, op & SLJIT_32, dst_r, dst_r, 0));
}
- if (dst_r == TMP_FREG1)
+ if (dst_r != dst)
FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw));
return SLJIT_SUCCESS;
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (type >= SLJIT_FAST_CALL)
PTR_FAIL_IF(prepare_blx(compiler));
+
+ jump->addr = compiler->size;
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,
type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(compiler, type), 0));
- if (jump->flags & SLJIT_REWRITABLE_JUMP) {
- jump->addr = compiler->size;
+ if (jump->flags & SLJIT_REWRITABLE_JUMP)
compiler->patches++;
- }
if (type >= SLJIT_FAST_CALL) {
jump->flags |= IS_BL;
+ jump->addr = compiler->size;
PTR_FAIL_IF(emit_blx(compiler));
}
-
- if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
- jump->addr = compiler->size;
#else /* !SLJIT_CONFIG_ARM_V6 */
+ jump->addr = compiler->size;
if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL;
- PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(compiler, type)));
- jump->addr = compiler->size;
+ compiler->size += JUMP_MAX_SIZE - 1;
#endif /* SLJIT_CONFIG_ARM_V6 */
return jump;
}
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (type >= SLJIT_FAST_CALL)
FAIL_IF(prepare_blx(compiler));
+ jump->addr = compiler->size;
FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0));
- if (type >= SLJIT_FAST_CALL)
+ if (type >= SLJIT_FAST_CALL) {
+ jump->addr = compiler->size;
FAIL_IF(emit_blx(compiler));
+ }
#else /* !SLJIT_CONFIG_ARM_V6 */
- FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
+ jump->addr = compiler->size;
FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));
+ compiler->size += JUMP_MAX_SIZE - 1;
#endif /* SLJIT_CONFIG_ARM_V6 */
- jump->addr = compiler->size;
return SLJIT_SUCCESS;
}
}
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG2));
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG1));
if (src2_reg != dst_reg) {
src1 = src2_reg;
}
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));
- src1 = TMP_FREG1;
+ FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG2, src1, src1w));
+ src1 = TMP_FREG2;
}
cc = get_cc(compiler, type & ~SLJIT_32);
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;
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
#endif /* SLJIT_CONFIG_ARM_V6 */
- const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
- PTR_FAIL_IF(!const_);
- set_const(const_, compiler);
-
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), 0));
compiler->patches++;
#else /* !SLJIT_CONFIG_ARM_V6 */
- PTR_FAIL_IF(emit_imm(compiler, dst_r, 0));
+ PTR_FAIL_IF(push_inst(compiler, RD(dst_r)));
#endif /* SLJIT_CONFIG_ARM_V6 */
- 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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 1);
+
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+ compiler->size += 1;
+#endif /* SLJIT_CONFIG_ARM_V7 */
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
{
- inline_set_jump_addr(addr, executable_offset, new_target, 1);
+ set_jump_addr(addr, executable_offset, new_target, 1);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
{
- inline_set_const(addr, executable_offset, (sljit_uw)new_constant, 1);
+ set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1);
}
#define ADD 0x8b000000
#define ADDE 0x8b200000
#define ADDI 0x91000000
+#define ADR 0x10000000
+#define ADRP 0x90000000
#define AND 0x8a000000
#define ANDI 0x92000000
#define AND_v 0x0e201c00
return push_inst(compiler, MOVK | RD(dst) | ((sljit_ins)(imm >> 48) << 5) | (3 << 21));
}
-static SLJIT_INLINE sljit_sw detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
{
sljit_sw diff;
sljit_uw target_addr;
- if (jump->flags & SLJIT_REWRITABLE_JUMP) {
- jump->flags |= PATCH_ABS64;
- return 0;
- }
+ 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);
+ SLJIT_ASSERT(jump->u.label != NULL);
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
}
- diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr - 4) - executable_offset;
+ diff = (sljit_sw)target_addr - (sljit_sw)code_ptr - executable_offset;
if (jump->flags & IS_COND) {
diff += SSIZE_OF(ins);
if (diff <= 0xfffff && diff >= -0x100000) {
- code_ptr[-5] ^= (jump->flags & IS_CBZ) ? (0x1 << 24) : 0x1;
- jump->addr -= sizeof(sljit_ins);
+ *(--code_ptr) ^= (jump->flags & IS_CBZ) ? (0x1 << 24) : 0x1;
jump->flags |= PATCH_COND;
- return 5;
+ jump->addr -= sizeof(sljit_ins);
+ return code_ptr;
}
diff -= SSIZE_OF(ins);
}
if (diff <= 0x7ffffff && diff >= -0x8000000) {
+ if (jump->flags & IS_COND)
+ code_ptr[-1] -= (4 << 5);
jump->flags |= PATCH_B;
- return 4;
+ return code_ptr;
}
if (target_addr < 0x100000000l) {
if (jump->flags & IS_COND)
- code_ptr[-5] -= (2 << 5);
- code_ptr[-2] = code_ptr[0];
- return 2;
+ code_ptr[-1] -= (2 << 5);
+ code_ptr[2] = code_ptr[0];
+ return code_ptr + 2;
+ }
+
+ if (diff <= 0xfffff000l && diff >= -0x100000000l) {
+ if (jump->flags & IS_COND)
+ code_ptr[-1] -= (2 << 5);
+ jump->flags |= PATCH_B32;
+ code_ptr[2] = code_ptr[0];
+ return code_ptr + 2;
}
if (target_addr < 0x1000000000000l) {
if (jump->flags & IS_COND)
- code_ptr[-5] -= (1 << 5);
+ code_ptr[-1] -= (1 << 5);
jump->flags |= PATCH_ABS48;
- code_ptr[-1] = code_ptr[0];
- return 1;
+ code_ptr[3] = code_ptr[0];
+ return code_ptr + 3;
}
+exit:
jump->flags |= PATCH_ABS64;
- return 0;
+ code_ptr[4] = code_ptr[0];
+ return code_ptr + 4;
}
-static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
{
- if (max_label < 0x100000000l) {
- put_label->flags = 0;
- return 2;
+ sljit_uw addr;
+ sljit_sw diff;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ SLJIT_ASSERT(jump->flags < ((sljit_uw)4 << JUMP_SIZE_SHIFT));
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ if (diff <= 0xfffff && diff >= -0x100000) {
+ jump->flags |= PATCH_B;
+ return 0;
}
- if (max_label < 0x1000000000000l) {
- put_label->flags = 1;
+ if (diff <= 0xfffff000l && diff >= -0x100000000l) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_B32;
return 1;
}
- put_label->flags = 2;
- return 0;
+ if (addr < 0x100000000l) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ return 1;
+ }
+
+ if (addr < 0x1000000000000l) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)2 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS48;
+ return 2;
+ }
+
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS64;
+ return 3;
+}
+
+static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset)
+{
+ sljit_sw addr = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr);
+ sljit_ins* buf_ptr = (sljit_ins*)jump->addr;
+ sljit_u32 dst;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ if (jump->flags & PATCH_COND) {
+ addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
+ SLJIT_ASSERT(addr <= 0x3ffff && addr >= -0x40000);
+ buf_ptr[0] = (buf_ptr[0] & ~(sljit_ins)0xffffe0) | (sljit_ins)((addr & 0x7ffff) << 5);
+ return;
+ }
+
+ if (jump->flags & PATCH_B) {
+ addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
+ SLJIT_ASSERT(addr <= 0x1ffffff && addr >= -0x2000000);
+ buf_ptr[0] = ((jump->flags & IS_BL) ? BL : B) | (sljit_ins)(addr & 0x3ffffff);
+ return;
+ }
+
+ dst = (buf_ptr[0] >> 5) & 0x1f;
+
+ if (jump->flags & PATCH_B32) {
+ addr -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) & ~(sljit_sw)0xfff;
+ SLJIT_ASSERT(addr <= 0xfffff000l && addr >= -0x100000000l);
+ buf_ptr[0] = ADRP | (((sljit_ins)(addr >> 12) & 0x3) << 29) | (((sljit_ins)(addr >> 14) & 0x7ffff) << 5) | dst;
+ buf_ptr[1] = ADDI | dst | (dst << 5) | ((sljit_ins)(addr & 0xfff) << 10);
+ return;
+ }
+ } else {
+ dst = *buf_ptr;
+
+ if (jump->flags & PATCH_B) {
+ addr -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
+ SLJIT_ASSERT(addr <= 0xfffff && addr >= -0x100000);
+ buf_ptr[0] = ADR | (((sljit_ins)addr & 0x3) << 29) | (((sljit_ins)(addr >> 2) & 0x7ffff) << 5) | dst;
+ return;
+ }
+
+ if (jump->flags & PATCH_B32) {
+ addr -= ((sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) & ~(sljit_sw)0xfff;
+ SLJIT_ASSERT(addr <= 0xffffffffl && addr >= -0x100000000l);
+ buf_ptr[0] = ADRP | (((sljit_ins)(addr >> 12) & 0x3) << 29) | (((sljit_ins)(addr >> 14) & 0x7ffff) << 5) | dst;
+ buf_ptr[1] = ADDI | dst | (dst << 5) | ((sljit_ins)(addr & 0xfff) << 10);
+ return;
+ }
+ }
+
+ SLJIT_ASSERT((jump->flags & (PATCH_ABS48 | PATCH_ABS64)) || (sljit_uw)addr <= (sljit_uw)0xffffffff);
+ SLJIT_ASSERT((jump->flags & PATCH_ABS64) || (sljit_uw)addr <= (sljit_uw)0xffffffffffff);
+
+ buf_ptr[0] = MOVZ | (((sljit_ins)addr & 0xffff) << 5) | dst;
+ buf_ptr[1] = MOVK | (((sljit_ins)(addr >> 16) & 0xffff) << 5) | (1 << 21) | dst;
+ if (jump->flags & (PATCH_ABS48 | PATCH_ABS64))
+ buf_ptr[2] = MOVK | (((sljit_ins)(addr >> 32) & 0xffff) << 5) | (2 << 21) | dst;
+
+ if (jump->flags & PATCH_ABS64)
+ buf_ptr[3] = MOVK | ((sljit_ins)((sljit_uw)addr >> 48) << 5) | (3 << 21) | dst;
+}
+
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_uw total_size;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+ SLJIT_NEXT_INIT_TYPES();
+
+ while (1) {
+ SLJIT_GET_NEXT_MIN();
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr == next_const_addr) {
+ const_->addr -= size_reduce;
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ continue;
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ jump->addr -= size_reduce;
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ total_size = JUMP_MAX_SIZE;
+
+ if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {
+ if (jump->flags & JUMP_ADDR) {
+ if (jump->u.target < 0x100000000l)
+ total_size = 3;
+ else if (jump->u.target < 0x1000000000000l)
+ total_size = 4;
+ } else {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if ((jump->flags & IS_COND) && (diff + 1) <= (0xfffff / SSIZE_OF(ins)) && (diff + 1) >= (-0x100000 / SSIZE_OF(ins)))
+ total_size = 0;
+ else if (diff <= (0x7ffffff / SSIZE_OF(ins)) && diff >= (-0x8000000 / SSIZE_OF(ins)))
+ total_size = 1;
+ else if (diff <= (0xfffff000l / SSIZE_OF(ins)) && diff >= (-0x100000000l / SSIZE_OF(ins)))
+ total_size = 3;
+ }
+ }
+
+ size_reduce += JUMP_MAX_SIZE - total_size;
+ } else {
+ /* Real size minus 1. Unit size: instruction. */
+ total_size = 3;
+
+ if (!(jump->flags & JUMP_ADDR)) {
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if (diff <= (0xfffff / SSIZE_OF(ins)) && diff >= (-0x100000 / SSIZE_OF(ins)))
+ total_size = 0;
+ else if (diff <= (0xfffff000l / SSIZE_OF(ins)) && diff >= (-0x100000000l / SSIZE_OF(ins)))
+ total_size = 1;
+ } else if (jump->u.target < 0x100000000l)
+ total_size = 1;
+ else if (jump->u.target < 0x1000000000000l)
+ total_size = 2;
+
+ size_reduce += 3 - total_size;
+ }
+
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_ins *code;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
sljit_sw executable_offset;
sljit_sw addr;
- sljit_u32 dst;
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);
+ reduce_code_size(compiler);
+
+ code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
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;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
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) {
+ if (next_min_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);
+ if (next_min_addr == next_label_size) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (jump && jump->addr == word_count) {
- jump->addr = (sljit_uw)(code_ptr - 4);
- code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset);
- jump = jump->next;
- }
- if (const_ && const_->addr == word_count) {
+
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT);
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
+ SLJIT_ASSERT((jump->flags & PATCH_COND) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins)));
+ } else {
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+ addr = (sljit_sw)code_ptr;
+ code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset);
+ jump->addr = (sljit_uw)addr;
+ }
+
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- if (put_label && put_label->addr == word_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)(code_ptr - 3);
- code_ptr -= put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
+
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
word_count++;
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
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 {
- addr = (sljit_sw)((jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
- buf_ptr = (sljit_ins *)jump->addr;
-
- if (jump->flags & PATCH_B) {
- addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
- SLJIT_ASSERT(addr <= 0x1ffffff && addr >= -0x2000000);
- buf_ptr[0] = ((jump->flags & IS_BL) ? BL : B) | (sljit_ins)(addr & 0x3ffffff);
- if (jump->flags & IS_COND)
- buf_ptr[-1] -= (4 << 5);
- break;
- }
- if (jump->flags & PATCH_COND) {
- addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
- SLJIT_ASSERT(addr <= 0x3ffff && addr >= -0x40000);
- buf_ptr[0] = (buf_ptr[0] & ~(sljit_ins)0xffffe0) | (sljit_ins)((addr & 0x7ffff) << 5);
- break;
- }
-
- SLJIT_ASSERT((jump->flags & (PATCH_ABS48 | PATCH_ABS64)) || (sljit_uw)addr <= (sljit_uw)0xffffffff);
- SLJIT_ASSERT((jump->flags & PATCH_ABS64) || (sljit_uw)addr <= (sljit_uw)0xffffffffffff);
-
- dst = buf_ptr[0] & 0x1f;
- buf_ptr[0] = MOVZ | dst | (((sljit_ins)addr & 0xffff) << 5);
- buf_ptr[1] = MOVK | dst | (((sljit_ins)(addr >> 16) & 0xffff) << 5) | (1 << 21);
- if (jump->flags & (PATCH_ABS48 | PATCH_ABS64))
- buf_ptr[2] = MOVK | dst | (((sljit_ins)(addr >> 32) & 0xffff) << 5) | (2 << 21);
- if (jump->flags & PATCH_ABS64)
- buf_ptr[3] = MOVK | dst | ((sljit_ins)(addr >> 48) << 5) | (3 << 21);
- } while (0);
+ generate_jump_or_mov_addr(jump, executable_offset);
jump = jump->next;
}
- put_label = compiler->put_labels;
- while (put_label) {
- addr = (sljit_sw)put_label->label->addr;
- buf_ptr = (sljit_ins*)put_label->addr;
-
- buf_ptr[0] |= ((sljit_ins)addr & 0xffff) << 5;
- buf_ptr[1] |= ((sljit_ins)(addr >> 16) & 0xffff) << 5;
-
- if (put_label->flags >= 1)
- buf_ptr[2] |= ((sljit_ins)(addr >> 32) & 0xffff) << 5;
-
- if (put_label->flags >= 2)
- buf_ptr[3] |= (sljit_ins)(addr >> 48) << 5;
-
- 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);
imm = (flags & ARG2_IMM) ? arg2 : arg1;
switch (op) {
- case SLJIT_MUL:
case SLJIT_CLZ:
case SLJIT_CTZ:
case SLJIT_REV:
case SLJIT_REV_S32:
case SLJIT_ADDC:
case SLJIT_SUBC:
+ case SLJIT_MUL:
+ case SLJIT_MULADD:
/* No form with immediate operand (except imm 0, which
is represented by a ZERO register). */
break;
/* fallthrough */
case SLJIT_ROTR:
return push_inst(compiler, (RORV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
+ case SLJIT_MULADD:
+ compiler->status_flags_state = 0;
+ return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(dst));
default:
SLJIT_UNREACHABLE();
return SLJIT_SUCCESS;
if (argw <= 0xff && argw >= -0x100)
return push_inst(compiler, STURBI | type | RT(reg) | RN(arg) | (((sljit_ins)argw & 0x1ff) << 12));
- if (argw >= 0) {
- if (argw <= 0xfff0ff && ((argw + 0x100) & 0xfff) <= 0x1ff) {
+ if (((argw + 0x100) & 0xfff) <= 0x1ff && argw <= 0xfff0ff && argw >= -0xfff100) {
+ if (argw >= 0) {
+ if (argw & 0x100)
+ argw += 0x1000;
+
FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)argw >> 12) << 10)));
return push_inst(compiler, STURBI | type | RT(reg) | RN(tmp_reg) | (((sljit_ins)argw & 0x1ff) << 12));
+ } else {
+ if (!(argw & 0x100))
+ argw -= 0x1000;
+
+ FAIL_IF(push_inst(compiler, SUBI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)-argw >> 12) << 10)));
+ return push_inst(compiler, STURBI | type | RT(reg) | RN(tmp_reg) | (((sljit_ins)argw & 0x1ff) << 12));
}
- } else if (argw >= -0xfff100 && ((-argw + 0xff) & 0xfff) <= 0x1ff) {
- FAIL_IF(push_inst(compiler, SUBI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)-argw >> 12) << 10)));
- return push_inst(compiler, STURBI | type | RT(reg) | RN(tmp_reg) | (((sljit_ins)argw & 0x1ff) << 12));
}
FAIL_IF(load_immediate(compiler, tmp_reg, argw));
op = GET_OPCODE(op);
if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) {
/* Both operands are registers. */
- if (dst_r != TMP_REG1 && FAST_IS_REG(src))
+ if (FAST_IS_REG(dst) && FAST_IS_REG(src))
return emit_op_imm(compiler, op | ((op_flags & SLJIT_32) ? INT_OP : 0), dst_r, TMP_REG1, src);
switch (op) {
else if (!(src & SLJIT_MEM))
dst_r = src;
else
- FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, src, srcw, TMP_REG1));
+ FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, src, srcw, TMP_REG2));
if (dst & SLJIT_MEM)
return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2);
mem_flags = INT_SIZE;
}
- if (dst == TMP_REG1)
+ if (dst == TMP_REG2)
flags |= UNUSED_RETURN;
if (src1 & SLJIT_MEM) {
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_REG1, 0, src1, src1w, src2, src2w);
+ return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op2(compiler, op, dst_reg, 0, src1, src1w, src2, src2w);
+ }
+
+ return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
return push_inst(compiler, STR_FR | type | VT(reg)
| RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw ? (1 << 12) : 0));
- FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)argw << 10)));
- return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1));
+ FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)argw << 10)));
+ return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG2));
}
arg &= REG_MASK;
if (!arg) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, argw & ~(0xfff << shift)));
+ FAIL_IF(load_immediate(compiler, TMP_REG2, argw & ~(0xfff << shift)));
argw = (argw >> shift) & 0xfff;
- return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | ((sljit_ins)argw << 10));
+ return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG2) | ((sljit_ins)argw << 10));
}
if (argw >= 0 && (argw & ((1 << shift) - 1)) == 0) {
return push_inst(compiler, STR_FI | type | VT(reg) | RN(arg) | ((sljit_ins)argw << (10 - shift)));
if (argw <= 0xffffff) {
- FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(TMP_REG1) | RN(arg) | (((sljit_ins)argw >> 12) << 10)));
+ FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(TMP_REG2) | RN(arg) | (((sljit_ins)argw >> 12) << 10)));
argw = ((argw & 0xfff) >> shift);
- return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | ((sljit_ins)argw << 10));
+ return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG2) | ((sljit_ins)argw << 10));
}
}
if (argw <= 255 && argw >= -256)
return push_inst(compiler, STUR_FI | type | VT(reg) | RN(arg) | (((sljit_ins)argw & 0x1ff) << 12));
- FAIL_IF(load_immediate(compiler, TMP_REG1, argw));
- return push_inst(compiler, STR_FR | type | VT(reg) | RN(arg) | RM(TMP_REG1));
+ FAIL_IF(load_immediate(compiler, TMP_REG2, argw));
+ return push_inst(compiler, STR_FR | type | VT(reg) | RN(arg) | RM(TMP_REG2));
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
switch (GET_OPCODE(op)) {
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst(compiler, (FMOV ^ inv_bits) | VD(dst_r) | VN(src)));
else
dst_r = src;
if (type < SLJIT_JUMP) {
jump->flags |= IS_COND;
PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(compiler, type)));
- }
- else if (type >= SLJIT_FAST_CALL)
+ } else if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL;
- PTR_FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0));
jump->addr = compiler->size;
- PTR_FAIL_IF(push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1)));
+ PTR_FAIL_IF(push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG2)));
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
inv_bits |= 1 << 24;
PTR_FAIL_IF(push_inst(compiler, (CBZ ^ inv_bits) | (6 << 5) | RT(src)));
- PTR_FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0));
jump->addr = compiler->size;
- PTR_FAIL_IF(push_inst(compiler, BR | RN(TMP_REG1)));
+ PTR_FAIL_IF(push_inst(compiler, BR | RN(TMP_REG2)));
+
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
if (src != SLJIT_IMM) {
if (src & SLJIT_MEM) {
ADJUST_LOCAL_OFFSET(src, srcw);
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
- src = TMP_REG1;
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2));
+ src = TMP_REG2;
}
return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(src));
}
set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
jump->u.target = (sljit_uw)srcw;
- FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0));
jump->addr = compiler->size;
- return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1));
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
+ return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG2));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
if (GET_OPCODE(op) < SLJIT_ADD) {
FAIL_IF(push_inst(compiler, CSINC | (cc << 12) | RD(dst_r) | RN(TMP_ZERO) | RM(TMP_ZERO)));
- if (dst_r == TMP_REG1) {
+ if (dst & SLJIT_MEM) {
mem_flags = (GET_OPCODE(op) == SLJIT_MOV ? WORD_SIZE : INT_SIZE) | STORE;
return emit_op_mem(compiler, mem_flags, TMP_REG1, dst, dstw, TMP_REG2);
}
if (src1 == SLJIT_IMM) {
if (type & SLJIT_32)
src1w = (sljit_s32)src1w;
- FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
- src1 = TMP_REG1;
+ FAIL_IF(load_immediate(compiler, TMP_REG2, src1w));
+ src1 = TMP_REG2;
} else if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG2));
- src1 = TMP_REG1;
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src1, src1w, TMP_REG2));
+ src1 = TMP_REG2;
}
cc = get_cc(compiler, type & ~SLJIT_32);
ADJUST_LOCAL_OFFSET(src1, src1w);
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src1, src1w));
- src1 = TMP_FREG1;
+ FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG2, src1, src1w));
+ src1 = TMP_FREG2;
}
cc = get_cc(compiler, type & ~SLJIT_32);
sljit_s32 mem = *mem_ptr;
if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
- *mem_ptr = TMP_REG1;
- return push_inst(compiler, ADD | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 10));
+ *mem_ptr = TMP_REG2;
+ return push_inst(compiler, ADD | RD(TMP_REG2) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 10));
}
if (!(mem & REG_MASK)) {
- *mem_ptr = TMP_REG1;
- return load_immediate(compiler, TMP_REG1, memw);
+ *mem_ptr = TMP_REG2;
+ return load_immediate(compiler, TMP_REG2, memw);
}
mem &= REG_MASK;
return SLJIT_SUCCESS;
}
- *mem_ptr = TMP_REG1;
+ *mem_ptr = TMP_REG2;
if (memw < -0xffffff || memw > 0xffffff) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, memw));
- return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(mem));
+ FAIL_IF(load_immediate(compiler, TMP_REG2, memw));
+ return push_inst(compiler, ADD | RD(TMP_REG2) | RN(TMP_REG2) | RM(mem));
}
ins = ADDI;
}
if (memw > 0xfff) {
- FAIL_IF(push_inst(compiler, ins | (1 << 22) | RD(TMP_REG1) | RN(mem) | ((sljit_ins)(memw >> 12) << 10)));
+ FAIL_IF(push_inst(compiler, ins | (1 << 22) | RD(TMP_REG2) | RN(mem) | ((sljit_ins)(memw >> 12) << 10)));
memw &= 0xfff;
if (memw == 0)
return SLJIT_SUCCESS;
- mem = TMP_REG1;
+ mem = TMP_REG2;
}
- return push_inst(compiler, ins | RD(TMP_REG1) | RN(mem) | ((sljit_ins)memw << 10));
+ return push_inst(compiler, ins | RD(TMP_REG2) | RN(mem) | ((sljit_ins)memw << 10));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
return push_inst(compiler, MOVI | imm | VD(freg));
}
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
- src = TMP_REG1;
+ FAIL_IF(load_immediate(compiler, TMP_REG2, srcw));
+ src = TMP_REG2;
}
return push_inst(compiler, DUP_g | ins | VD(freg) | RN(src));
if (elem_size < 3)
srcdstw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcdstw));
- srcdst = TMP_REG1;
+ FAIL_IF(load_immediate(compiler, TMP_REG2, srcdstw));
+ srcdst = TMP_REG2;
}
if (type & SLJIT_SIMD_STORE) {
FAIL_IF(push_inst(compiler, USRA | (1 << 30) | (imms << 16) | VD(TMP_FREG1) | VN(TMP_FREG1)));
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
ins = (0x1 << 16);
if (reg_size == 4 && elem_size == 0) {
FAIL_IF(push_inst(compiler, UMOV | ins | RD(dst_r) | VN(TMP_FREG1)));
- if (dst_r == TMP_REG1)
- return emit_op_mem(compiler, STORE | ((type & SLJIT_32) ? INT_SIZE : WORD_SIZE), TMP_REG1, dst, dstw, TMP_REG2);
+ if (dst_r == TMP_REG2)
+ return emit_op_mem(compiler, STORE | ((type & SLJIT_32) ? INT_SIZE : WORD_SIZE), TMP_REG2, dst, dstw, TMP_REG1);
return SLJIT_SUCCESS;
}
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
- PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, 0));
+ PTR_FAIL_IF(push_inst(compiler, RD(dst_r)));
- 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, 1);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 1);
+
+ compiler->size += 3;
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
#define LSRSI 0x0800
#define LSR_W 0xfa20f000
#define LSR_WI 0xea4f0010
+#define MLA 0xfb000000
#define MOV 0x4600
#define MOVS 0x0000
#define MOVSI 0x2000
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
+static sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
{
FAIL_IF(push_inst32(compiler, MOVW | RD4(dst)
| COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff)));
| COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16));
}
-static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm)
+/* Dst must be in bits[11-8] */
+static void set_imm32_const(sljit_u16 *inst, sljit_ins dst, sljit_uw new_imm)
{
- sljit_ins dst = inst[1] & 0x0f00;
- SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00));
inst[0] = (sljit_u16)((MOVW >> 16) | COPY_BITS(new_imm, 12, 0, 4) | COPY_BITS(new_imm, 11, 10, 1));
inst[1] = (sljit_u16)(dst | COPY_BITS(new_imm, 8, 12, 3) | (new_imm & 0xff));
inst[2] = (sljit_u16)((MOVT >> 16) | COPY_BITS(new_imm, 12 + 16, 0, 4) | COPY_BITS(new_imm, 11 + 16, 10, 1));
inst[3] = (sljit_u16)(dst | COPY_BITS(new_imm, 8 + 16, 12, 3) | ((new_imm & 0xff0000) >> 16));
}
-static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset)
+static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm)
+{
+ sljit_ins dst = inst[1] & 0x0f00;
+ SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00));
+ set_imm32_const(inst, dst, new_imm);
+}
+
+static SLJIT_INLINE sljit_u16* detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset)
{
sljit_sw diff;
if (jump->flags & SLJIT_REWRITABLE_JUMP)
- return 0;
+ goto exit;
if (jump->flags & JUMP_ADDR) {
/* Branch to ARM code is not optimized yet. */
if (!(jump->u.target & 0x1))
- return 0;
- diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset) >> 1;
- }
- else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
- diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)) >> 1;
+ goto exit;
+ diff = (sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset;
+ } else {
+ SLJIT_ASSERT(jump->u.label != NULL);
+ diff = (sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2);
}
if (jump->flags & IS_COND) {
SLJIT_ASSERT(!(jump->flags & IS_BL));
- if (diff <= 127 && diff >= -128) {
+ /* Size of the prefix IT instruction. */
+ diff += SSIZE_OF(u16);
+ if (diff <= 0xff && diff >= -0x100) {
jump->flags |= PATCH_TYPE1;
- return 5;
+ jump->addr = (sljit_uw)(code_ptr - 1);
+ return code_ptr - 1;
}
- if (diff <= 524287 && diff >= -524288) {
+ if (diff <= 0xfffff && diff >= -0x100000) {
jump->flags |= PATCH_TYPE2;
- return 4;
+ jump->addr = (sljit_uw)(code_ptr - 1);
+ return code_ptr;
}
- /* +1 comes from the prefix IT instruction. */
- diff--;
- if (diff <= 8388607 && diff >= -8388608) {
- jump->flags |= PATCH_TYPE3;
- return 3;
+ diff -= SSIZE_OF(u16);
+ } else if (jump->flags & IS_BL) {
+ /* Branch and link. */
+ if (diff <= 0xffffff && diff >= -0x1000000) {
+ jump->flags |= PATCH_TYPE5;
+ return code_ptr + 1;
}
+ goto exit;
+ } else if (diff <= 0x7ff && diff >= -0x800) {
+ jump->flags |= PATCH_TYPE3;
+ return code_ptr;
}
- else if (jump->flags & IS_BL) {
- if (diff <= 8388607 && diff >= -8388608) {
- jump->flags |= PATCH_BL;
- return 3;
- }
+
+ if (diff <= 0xffffff && diff >= -0x1000000) {
+ jump->flags |= PATCH_TYPE4;
+ return code_ptr + 1;
}
- else {
- if (diff <= 1023 && diff >= -1024) {
- jump->flags |= PATCH_TYPE4;
- return 4;
- }
- if (diff <= 8388607 && diff >= -8388608) {
- jump->flags |= PATCH_TYPE5;
- return 3;
- }
+
+exit:
+ code_ptr[4] = code_ptr[0];
+
+ if (jump->flags & IS_COND) {
+ code_ptr[3] = code_ptr[-1];
+ jump->addr = (sljit_uw)(code_ptr - 1);
+ }
+
+ return code_ptr + 4;
+}
+
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset)
+{
+ sljit_uw addr;
+ sljit_sw diff;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ /* The pc+4 offset is represented by the 2 * SSIZE_OF(sljit_u16) below. */
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ /* Note: ADR with imm8 does not set the last bit (Thumb2 flag). */
+
+ if (diff <= 0xffd + 2 * SSIZE_OF(u16) && diff >= -0xfff + 2 * SSIZE_OF(u16)) {
+ jump->flags |= PATCH_TYPE6;
+ return 1;
}
- return 0;
+ return 3;
}
-static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset)
+static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset)
{
sljit_s32 type = (jump->flags >> 4) & 0xf;
+ sljit_u16 *jump_inst = (sljit_u16*)jump->addr;
sljit_sw diff;
- sljit_u16 *jump_inst;
- sljit_s32 s, j1, j2;
+ sljit_ins ins;
+
+ diff = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr);
if (SLJIT_UNLIKELY(type == 0)) {
- modify_imm32_const((sljit_u16*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
+ ins = (jump->flags & JUMP_MOV_ADDR) ? *jump_inst : RDN3(TMP_REG1);
+ set_imm32_const((sljit_u16*)jump->addr, ins, (sljit_uw)diff);
return;
}
- if (jump->flags & JUMP_ADDR) {
- SLJIT_ASSERT(jump->u.target & 0x1);
- diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
- }
- else {
- SLJIT_ASSERT(jump->u.label->addr & 0x1);
- diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
+ if (SLJIT_UNLIKELY(type == 6)) {
+ SLJIT_ASSERT(jump->flags & JUMP_MOV_ADDR);
+ diff -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_inst + 2, executable_offset) & ~(sljit_sw)0x3;
+
+ SLJIT_ASSERT(diff <= 0xfff && diff >= -0xfff);
+
+ ins = ADDWI >> 16;
+ if (diff <= 0) {
+ diff = -diff;
+ ins = SUBWI >> 16;
+ }
+
+ jump_inst[1] = (sljit_u16)(jump_inst[0] | COPY_BITS(diff, 8, 12, 3) | (diff & 0xff));
+ jump_inst[0] = (sljit_u16)(ins | 0xf | COPY_BITS(diff, 11, 10, 1));
+ return;
}
- jump_inst = (sljit_u16*)jump->addr;
+
+ SLJIT_ASSERT((diff & 0x1) != 0 && !(jump->flags & JUMP_MOV_ADDR));
+ diff = (diff - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
switch (type) {
case 1:
/* Encoding T1 of 'B' instruction */
- SLJIT_ASSERT(diff <= 127 && diff >= -128 && (jump->flags & IS_COND));
+ SLJIT_ASSERT(diff <= 0x7f && diff >= -0x80 && (jump->flags & IS_COND));
jump_inst[0] = (sljit_u16)(0xd000 | (jump->flags & 0xf00) | ((sljit_ins)diff & 0xff));
return;
case 2:
/* Encoding T3 of 'B' instruction */
- SLJIT_ASSERT(diff <= 524287 && diff >= -524288 && (jump->flags & IS_COND));
+ SLJIT_ASSERT(diff <= 0x7ffff && diff >= -0x80000 && (jump->flags & IS_COND));
jump_inst[0] = (sljit_u16)(0xf000 | COPY_BITS(jump->flags, 8, 6, 4) | COPY_BITS(diff, 11, 0, 6) | COPY_BITS(diff, 19, 10, 1));
jump_inst[1] = (sljit_u16)(0x8000 | COPY_BITS(diff, 17, 13, 1) | COPY_BITS(diff, 18, 11, 1) | ((sljit_ins)diff & 0x7ff));
return;
case 3:
- SLJIT_ASSERT(jump->flags & IS_COND);
- *jump_inst++ = (sljit_u16)(IT | ((jump->flags >> 4) & 0xf0) | 0x8);
- diff--;
- type = 5;
- break;
- case 4:
/* Encoding T2 of 'B' instruction */
- SLJIT_ASSERT(diff <= 1023 && diff >= -1024 && !(jump->flags & IS_COND));
+ SLJIT_ASSERT(diff <= 0x3ff && diff >= -0x400 && !(jump->flags & IS_COND));
jump_inst[0] = (sljit_u16)(0xe000 | (diff & 0x7ff));
return;
}
- SLJIT_ASSERT(diff <= 8388607 && diff >= -8388608);
+ SLJIT_ASSERT(diff <= 0x7fffff && diff >= -0x800000);
+
+ /* Really complex instruction form for branches. Negate with sign bit. */
+ diff ^= ((diff >> 2) & 0x600000) ^ 0x600000;
- /* Really complex instruction form for branches. */
- s = (diff >> 23) & 0x1;
- j1 = (~(diff >> 22) ^ s) & 0x1;
- j2 = (~(diff >> 21) ^ s) & 0x1;
- jump_inst[0] = (sljit_u16)(0xf000 | ((sljit_ins)s << 10) | COPY_BITS(diff, 11, 0, 10));
- jump_inst[1] = (sljit_u16)((j1 << 13) | (j2 << 11) | (diff & 0x7ff));
+ jump_inst[0] = (sljit_u16)(0xf000 | COPY_BITS(diff, 11, 0, 10) | COPY_BITS(diff, 23, 10, 1));
+ jump_inst[1] = (sljit_u16)((diff & 0x7ff) | COPY_BITS(diff, 22, 13, 1) | COPY_BITS(diff, 21, 11, 1));
+
+ SLJIT_ASSERT(type == 4 || type == 5);
/* The others have a common form. */
- if (type == 5) /* Encoding T4 of 'B' instruction */
+ if (type == 4) /* Encoding T4 of 'B' instruction */
jump_inst[1] |= 0x9000;
- else if (type == 6) /* Encoding T1 of 'BL' instruction */
+ else /* Encoding T1 of 'BL' instruction */
jump_inst[1] |= 0xd000;
- else
- SLJIT_UNREACHABLE();
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_uw total_size;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+ SLJIT_NEXT_INIT_TYPES();
+
+ while (1) {
+ SLJIT_GET_NEXT_MIN();
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr == next_const_addr) {
+ const_->addr -= size_reduce;
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ continue;
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ jump->addr -= size_reduce;
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ total_size = JUMP_MAX_SIZE;
+
+ if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2;
+
+ if (jump->flags & IS_COND) {
+ diff++;
+
+ if (diff <= (0xff / SSIZE_OF(u16)) && diff >= (-0x100 / SSIZE_OF(u16)))
+ total_size = 0;
+ else if (diff <= (0xfffff / SSIZE_OF(u16)) && diff >= (-0x100000 / SSIZE_OF(u16)))
+ total_size = 1;
+ diff--;
+ } else if (!(jump->flags & IS_BL) && diff <= (0x7ff / SSIZE_OF(u16)) && diff >= (-0x800 / SSIZE_OF(u16)))
+ total_size = 1;
+
+ if (total_size == JUMP_MAX_SIZE && diff <= (0xffffff / SSIZE_OF(u16)) && diff >= (-0x1000000 / SSIZE_OF(u16)))
+ total_size = 2;
+ }
+
+ size_reduce += JUMP_MAX_SIZE - total_size;
+ } else {
+ /* Real size minus 1. Unit size: instruction. */
+ total_size = 3;
+
+ if (!(jump->flags & JUMP_ADDR)) {
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if (diff <= (0xffd / SSIZE_OF(u16)) && diff >= (-0xfff / SSIZE_OF(u16)))
+ total_size = 1;
+ }
+
+ size_reduce += 3 - total_size;
+ }
+
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_u16 *code;
sljit_u16 *buf_ptr;
sljit_u16 *buf_end;
sljit_uw half_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_sw addr;
sljit_sw executable_offset;
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_u16*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_u16), compiler->exec_allocator_data);
+ reduce_code_size(compiler);
+
+ code = (sljit_u16*)allocate_executable_memory(compiler->size * sizeof(sljit_u16), options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
buf = compiler->buf;
code_ptr = code;
half_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;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
do {
buf_ptr = (sljit_u16*)buf->memory;
buf_end = buf_ptr + (buf->used_size >> 1);
do {
*code_ptr = *buf_ptr++;
- if (next_addr == half_count) {
+ if (next_min_addr == half_count) {
SLJIT_ASSERT(!label || label->size >= half_count);
SLJIT_ASSERT(!jump || jump->addr >= half_count);
SLJIT_ASSERT(!const_ || const_->addr >= half_count);
- SLJIT_ASSERT(!put_label || put_label->addr >= half_count);
/* These structures are ordered by their address. */
- if (label && label->size == half_count) {
- label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
+ if (next_min_addr == next_label_size) {
+ label->u.addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (jump && jump->addr == half_count) {
- jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_COND) ? 10 : 8);
- code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset);
- jump = jump->next;
- }
- if (const_ && const_->addr == half_count) {
+
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ half_count = half_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT);
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
+ SLJIT_ASSERT((sljit_uw)code_ptr - jump->addr <
+ ((jump->flags >> JUMP_SIZE_SHIFT) + ((jump->flags & 0xf0) <= PATCH_TYPE2)) * sizeof(sljit_u16));
+ } else {
+ half_count += jump->flags >> JUMP_SIZE_SHIFT;
+ addr = (sljit_sw)code_ptr;
+ code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset);
+ jump->addr = (sljit_uw)addr;
+ }
+
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- if (put_label && put_label->addr == half_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
+
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
half_count++;
} while (buf);
if (label && label->size == half_count) {
- label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
+ label->u.addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
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) {
- set_jump_instruction(jump, executable_offset);
+ generate_jump_or_mov_addr(jump, executable_offset);
jump = jump->next;
}
- put_label = compiler->put_labels;
- while (put_label) {
- modify_imm32_const((sljit_u16 *)put_label->addr, put_label->label->addr);
- 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_u16);
/* SET_FLAGS must be 0x100000 as it is also the value of S bit (can be used for optimization). */
#define SET_FLAGS 0x0100000
#define UNUSED_RETURN 0x0200000
+#define REGISTER_OP 0x0400000
static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_uw arg1, sljit_uw arg2)
{
- /* dst must be register, TMP_REG1
+ /* dst must be register
arg1 must be register, imm
arg2 must be register, imm */
sljit_s32 reg;
case SLJIT_REV_U32:
case SLJIT_REV_S32:
case SLJIT_MUL:
+ case SLJIT_MULADD:
/* No form with immediate operand. */
break;
case SLJIT_MOV:
return push_inst32(compiler, REV_W | RN4(arg2) | RD4(dst) | RM4(arg2));
case SLJIT_REV_U16:
case SLJIT_REV_S16:
- SLJIT_ASSERT(arg1 == TMP_REG2 && dst != TMP_REG2);
+ SLJIT_ASSERT(arg1 == TMP_REG2);
- flags &= 0xffff;
if (IS_2_LO_REGS(dst, arg2))
FAIL_IF(push_inst16(compiler, REV16 | RD3(dst) | RN3(arg2)));
else
FAIL_IF(push_inst32(compiler, REV16_W | RN4(arg2) | RD4(dst) | RM4(arg2)));
- if (dst == TMP_REG1 || (arg2 == TMP_REG1 && flags == SLJIT_REV_U16))
+ if (!(flags & REGISTER_OP))
return SLJIT_SUCCESS;
+ flags &= 0xffff;
if (reg_map[dst] <= 7)
return push_inst16(compiler, (flags == SLJIT_REV_U16 ? UXTH : SXTH) | RD3(dst) | RN3(dst));
return push_inst32(compiler, (flags == SLJIT_REV_U16 ? UXTH_W : SXTH_W) | RD4(dst) | RM4(dst));
compiler->status_flags_state = 0;
if (!(flags & SET_FLAGS))
return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2));
- SLJIT_ASSERT(dst != TMP_REG2);
- FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(TMP_REG2) | RN4(arg1) | RM4(arg2)));
+ reg = (dst == TMP_REG2) ? TMP_REG1 : TMP_REG2;
+ FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(reg) | RN4(arg1) | RM4(arg2)));
/* cmp TMP_REG2, dst asr #31. */
- return push_inst32(compiler, CMP_W | RN4(TMP_REG2) | 0x70e0 | RM4(dst));
+ return push_inst32(compiler, CMP_W | RN4(reg) | 0x70e0 | RM4(dst));
case SLJIT_AND:
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, ANDS | RD3(dst) | RN3(arg2));
return push_inst16(compiler, EORS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, EOR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_MSHL:
- FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(arg2) | 0x1f));
- arg2 = TMP_REG2;
+ reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
+ FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f));
+ arg2 = (sljit_uw)reg;
/* fallthrough */
case SLJIT_SHL:
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, LSLS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, LSL_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_MLSHR:
- FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(arg2) | 0x1f));
- arg2 = TMP_REG2;
+ reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
+ FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f));
+ arg2 = (sljit_uw)reg;
/* fallthrough */
case SLJIT_LSHR:
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, LSRS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, LSR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_MASHR:
- FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(arg2) | 0x1f));
- arg2 = TMP_REG2;
+ reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
+ FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f));
+ arg2 = (sljit_uw)reg;
/* fallthrough */
case SLJIT_ASHR:
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, ASRS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, ASR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_ROTL:
- FAIL_IF(push_inst32(compiler, RSB_WI | RD4(TMP_REG2) | RN4(arg2) | 0));
- arg2 = TMP_REG2;
+ reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
+ FAIL_IF(push_inst32(compiler, RSB_WI | RD4(reg) | RN4(arg2) | 0));
+ arg2 = (sljit_uw)reg;
/* fallthrough */
case SLJIT_ROTR:
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, RORS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, ROR_W | RD4(dst) | RN4(arg1) | RM4(arg2));
+ case SLJIT_MULADD:
+ compiler->status_flags_state = 0;
+ return push_inst32(compiler, MLA | RD4(dst) | RN4(arg1) | RM4(arg2) | RT4(dst));
}
SLJIT_UNREACHABLE();
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r, flags;
- sljit_s32 op_flags = GET_ALL_FLAGS(op);
CHECK_ERROR();
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src, srcw);
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
op = GET_OPCODE(op);
if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) {
if (src == SLJIT_IMM)
FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG2, (sljit_uw)srcw));
- else if (src & SLJIT_MEM) {
+ else if (src & SLJIT_MEM)
FAIL_IF(emit_op_mem(compiler, flags, dst_r, src, srcw, TMP_REG1));
- } else {
- if (dst_r != TMP_REG1)
- return emit_op_imm(compiler, op, dst_r, TMP_REG2, (sljit_uw)src);
+ else if (FAST_IS_REG(dst))
+ return emit_op_imm(compiler, op, dst_r, TMP_REG2, (sljit_uw)src);
+ else
dst_r = src;
- }
if (!(dst & SLJIT_MEM))
return SLJIT_SUCCESS;
- return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2);
+ return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG1);
}
SLJIT_COMPILE_ASSERT(WORD_SIZE == 0, word_size_must_be_0);
- flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
+ flags = WORD_SIZE;
- if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16)
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {
+ if (!(dst & SLJIT_MEM) && (!(src & SLJIT_MEM) || op == SLJIT_REV_S16))
+ op |= REGISTER_OP;
flags |= HALF_SIZE;
+ }
if (src & SLJIT_MEM) {
FAIL_IF(emit_op_mem(compiler, flags, TMP_REG1, src, srcw, TMP_REG1));
src = TMP_REG1;
}
- emit_op_imm(compiler, flags | op, dst_r, TMP_REG2, (sljit_uw)src);
+ emit_op_imm(compiler, op, dst_r, TMP_REG2, (sljit_uw)src);
if (SLJIT_UNLIKELY(dst & SLJIT_MEM))
- return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2);
+ return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG1);
return SLJIT_SUCCESS;
}
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
- sljit_s32 dst_reg, flags, src2_reg;
+ sljit_s32 dst_reg, src2_tmp_reg, flags;
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
- dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
if (dst == TMP_REG1)
flags |= UNUSED_RETURN;
+ if (src2 == SLJIT_IMM)
+ flags |= ARG2_IMM;
+ else if (src2 & SLJIT_MEM) {
+ src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2;
+ emit_op_mem(compiler, WORD_SIZE, src2_tmp_reg, src2, src2w, TMP_REG1);
+ src2w = src2_tmp_reg;
+ } else
+ src2w = src2;
+
if (src1 == SLJIT_IMM)
flags |= ARG1_IMM;
else if (src1 & SLJIT_MEM) {
emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1);
src1w = TMP_REG1;
- }
- else
+ } else
src1w = src1;
- if (src2 == SLJIT_IMM)
- flags |= ARG2_IMM;
- else if (src2 & SLJIT_MEM) {
- src2_reg = (!(flags & ARG1_IMM) && (src1w == TMP_REG1)) ? TMP_REG2 : TMP_REG1;
- emit_op_mem(compiler, WORD_SIZE, src2_reg, src2, src2w, src2_reg);
- src2w = src2_reg;
- }
- else
- src2w = src2;
-
emit_op_imm(compiler, flags | GET_OPCODE(op), dst_reg, (sljit_uw)src1w, (sljit_uw)src2w);
if (!(dst & SLJIT_MEM))
return SLJIT_SUCCESS;
- return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG2);
+ return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG1);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,
return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w);
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op2(compiler, op, dst_reg, 0, src1, src1w, src2, src2w);
+ }
+
+ return SLJIT_SUCCESS;
+}
+
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,
switch (GET_OPCODE(op)) {
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src)));
else
dst_r = src;
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
type &= 0xff;
- PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0));
if (type < SLJIT_JUMP) {
jump->flags |= IS_COND;
cc = get_cc(compiler, type);
PTR_FAIL_IF(push_inst16(compiler, BLX | RN3(TMP_REG1)));
}
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
jump->u.target = (sljit_uw)srcw;
- FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0));
jump->addr = compiler->size;
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1));
}
}
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG2));
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG1));
if (src2_reg != dst_reg) {
src1 = src2_reg;
}
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));
- src1 = TMP_FREG1;
+ FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG2, src1, src1w));
+ src1 = TMP_FREG2;
}
FAIL_IF(push_inst16(compiler, IT | (get_cc(compiler, type & ~SLJIT_32) << 4) | 0x8));
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
- PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, 0));
+ PTR_FAIL_IF(push_inst16(compiler, RDN3(dst_r)));
+ compiler->size += 3;
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
#define FRK(fk) ((sljit_ins)freg_map[fk] << 10)
#define FRA(fa) ((sljit_ins)freg_map[fa] << 15)
+#define IMM_V(imm) ((sljit_ins)(imm) << 10)
#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_I20(imm) (((sljit_ins)(imm)&0xffffffff) >> 12 << 5)
#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 FSTX_S OPC_3R(0x7070)
#define FSTX_D OPC_3R(0x7078)
+/* Vector Instructions */
+
+/* Vector Arithmetic Instructions */
+#define VOR_V OPC_3R(0xe24d)
+#define VXOR_V OPC_3R(0xe24e)
+#define VAND_V OPC_3R(0xe24c)
+#define VMSKLTZ OPC_2R(0x1ca710)
+
+/* Vector Memory Access Instructions */
+#define VLD OPC_2RI12(0xb0)
+#define VST OPC_2RI12(0xb1)
+#define XVLD OPC_2RI12(0xb2)
+#define XVST OPC_2RI12(0xb3)
+#define VSTELM OPC_2RI8(0xc40)
+
+/* Vector Float Conversion Instructions */
+#define VFCVTL_D_S OPC_2R(0x1ca77c)
+
+/* Vector Bit Manipulate Instructions */
+#define VSLLWIL OPC_2R(0x1cc200)
+
+/* Vector Move And Shuffle Instructions */
+#define VLDREPL OPC_2R(0xc0000)
+#define VINSGR2VR OPC_2R(0x1cbac0)
+#define VPICKVE2GR_U OPC_2R(0x1cbce0)
+#define VREPLGR2VR OPC_2R(0x1ca7c0)
+#define VREPLVE OPC_3R(0xe244)
+#define VREPLVEI OPC_2R(0x1cbde0)
+#define XVPERMI OPC_2RI8(0x1dfa)
+
#define I12_MAX (0x7ff)
#define I12_MIN (-0x800)
#define BRANCH16_MAX (0x7fff << 2)
/* LoongArch CPUCFG register for feature detection */
#define LOONGARCH_CFG2 0x02
-#define LOONGARCH_FEATURE_LAMCAS (1 << 28)
+#define LOONGARCH_CFG2_LAMCAS (1 << 28)
-static sljit_u32 cpu_feature_list = 0;
+static sljit_u32 cfg2_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;
-}
+/* According to Software Development and Build Convention for LoongArch Architectures,
++ the status of LSX and LASX extension must be checked through HWCAP */
+#include <sys/auxv.h>
+
+#define LOONGARCH_HWCAP_LSX (1 << 4)
+#define LOONGARCH_HWCAP_LASX (1 << 5)
+
+static sljit_u32 hwcap_feature_list = 0;
+
+/* Feature type */
+#define GET_CFG2 0
+#define GET_HWCAP 1
+
+static SLJIT_INLINE sljit_u32 get_cpu_features(sljit_u32 feature_type)
+ {
+ if (cfg2_feature_list == 0)
+ __asm__ ("cpucfg %0, %1" : "+&r"(cfg2_feature_list) : "r"(LOONGARCH_CFG2));
+ if (hwcap_feature_list == 0)
+ hwcap_feature_list = (sljit_u32)getauxval(AT_HWCAP);
+
+ return feature_type ? hwcap_feature_list : cfg2_feature_list;
+ }
static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
if (jump->flags & JUMP_ADDR)
target_addr = jump->u.target;
else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+ SLJIT_ASSERT(jump->u.label != NULL);
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--;
inst[0] = (inst[0] & 0xfc0003ff) ^ 0x4000000;
+ jump->flags |= PATCH_B;
jump->addr = (sljit_uw)inst;
return inst;
}
- inst++;
diff -= SSIZE_OF(ins);
}
return inst + 3;
}
-static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
{
- if (max_label <= (sljit_uw)S32_MAX) {
- put_label->flags = PATCH_ABS32;
+ sljit_uw addr;
+ sljit_sw diff;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ SLJIT_ASSERT(jump->flags < ((sljit_uw)6 << JUMP_SIZE_SHIFT));
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ if (diff >= S32_MIN && diff <= S32_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_REL32;
+ return 1;
+ }
+
+ if (addr <= S32_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS32;
return 1;
}
- if (max_label <= S52_MAX) {
- put_label->flags = PATCH_ABS52;
+ if (addr <= S52_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)2 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS52;
return 2;
}
- put_label->flags = 0;
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));
return 3;
}
-static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
+static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump, sljit_sw executable_offset)
{
- struct sljit_jump *jump = NULL;
- struct sljit_put_label *put_label;
- sljit_uw flags;
- sljit_ins *inst;
- sljit_uw addr;
+ sljit_uw flags = jump->flags;
+ sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
+ sljit_ins *ins = (sljit_ins*)jump->addr;
+ sljit_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : TMP_REG1;
+ SLJIT_UNUSED_ARG(executable_offset);
- 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_REL32) {
+ addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset);
+
+ SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX);
+
+ if ((addr & 0x800) != 0)
+ addr += 0x1000;
+
+ ins[0] = PCADDU12I | RD(reg) | IMM_I20(addr);
+
+ if (!(flags & JUMP_MOV_ADDR)) {
+ SLJIT_ASSERT((ins[1] & OPC_2RI16(0x3f)) == JIRL);
+ ins[1] = (ins[1] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I16((addr & 0xfff) >> 2);
+ } else
+ ins[1] = ADDI_D | RD(reg) | RJ(reg) | IMM_I12(addr);
+ return;
}
if (flags & PATCH_ABS32) {
SLJIT_ASSERT(addr <= S32_MAX);
- inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+ ins[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;
+ ins[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+ ins[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5);
+ ins += 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;
+ ins[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+ ins[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5);
+ ins[2] = LU52I_D | RD(reg) | RJ(reg) | IMM_I12(addr >> 52);
+ ins += 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);
+ if (!(flags & JUMP_MOV_ADDR)) {
+ SLJIT_ASSERT((ins[1] & OPC_2RI16(0x3f)) == JIRL);
+ ins[1] = (ins[1] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I16((addr & 0xfff) >> 2);
} else
- inst[1] = ORI | RD(reg) | RJ(reg) | IMM_I12(addr);
+ ins[1] = ORI | RD(reg) | RJ(reg) | IMM_I12(addr);
+}
+
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_uw total_size;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+
+ SLJIT_NEXT_INIT_TYPES();
+
+ while (1) {
+ SLJIT_GET_NEXT_MIN();
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr == next_const_addr) {
+ const_->addr -= size_reduce;
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ continue;
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ jump->addr -= size_reduce;
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ total_size = JUMP_MAX_SIZE;
+
+ if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {
+ if (jump->flags & JUMP_ADDR) {
+ if (jump->u.target <= S32_MAX)
+ total_size = 2;
+ else if (jump->u.target <= S52_MAX)
+ total_size = 3;
+ } else {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if ((jump->flags & IS_COND) && (diff + 1) <= (BRANCH16_MAX / SSIZE_OF(ins)) && (diff + 1) >= (BRANCH16_MIN / SSIZE_OF(ins)))
+ total_size = 0;
+ else if (diff >= (JUMP_MIN / SSIZE_OF(ins)) && diff <= (JUMP_MAX / SSIZE_OF(ins)))
+ total_size = 1;
+ else if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins)))
+ total_size = 2;
+ }
+ }
+
+ size_reduce += JUMP_MAX_SIZE - total_size;
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+ } else {
+ total_size = 3;
+
+ if (!(jump->flags & JUMP_ADDR)) {
+ /* Real size minus 1. Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins)))
+ total_size = 1;
+ } else if (jump->u.target < S32_MAX)
+ total_size = 1;
+ else if (jump->u.target <= S52_MAX)
+ total_size = 2;
+
+ size_reduce += 3 - total_size;
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+ }
+
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_ins *code;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
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);
+ reduce_code_size(compiler);
+
+ code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
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;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
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) {
+ if (next_min_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);
+ if (next_min_addr == next_label_size) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (jump && jump->addr == word_count) {
- word_count += 3;
- jump->addr = (sljit_uw)code_ptr;
- code_ptr = detect_jump_type(jump, code, executable_offset);
+
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT);
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr = detect_jump_type(jump, code, executable_offset);
+ SLJIT_ASSERT((jump->flags & PATCH_B) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins)));
+ } else {
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+ addr = (sljit_uw)code_ptr;
+ code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset);
+ jump->addr = addr;
+ }
jump = jump->next;
- }
- if (const_ && const_->addr == word_count) {
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- 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);
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
word_count++;
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)code_ptr;
+ label->u.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);
+ if (!(jump->flags & (PATCH_B | PATCH_J)) || (jump->flags & JUMP_MOV_ADDR)) {
+ load_addr_to_reg(jump, executable_offset);
break;
}
- addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+ addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
buf_ptr = (sljit_ins *)jump->addr;
addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
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);
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);
return 1;
#endif
+ case SLJIT_HAS_LASX:
+ return (LOONGARCH_HWCAP_LASX & get_cpu_features(GET_HWCAP));
+
+ case SLJIT_HAS_SIMD:
+ return (LOONGARCH_HWCAP_LSX & get_cpu_features(GET_HWCAP));
+
case SLJIT_HAS_ATOMIC:
- return (LOONGARCH_FEATURE_LAMCAS & get_cpu_features());
+ return (LOONGARCH_CFG2_LAMCAS & get_cpu_features(GET_CFG2));
case SLJIT_HAS_CLZ:
case SLJIT_HAS_CTZ:
#define SLOW_SRC1 0x08000
#define SLOW_SRC2 0x10000
#define SLOW_DEST 0x20000
+#define MEM_USE_TMP2 0x40000
#define STACK_STORE ST_D
#define STACK_LOAD LD_D
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_s32 tmp_r = (flags & MEM_USE_TMP2) ? TMP_REG2 : TMP_REG1;
sljit_sw offset;
SLJIT_ASSERT(arg & SLJIT_MEM);
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;
FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(dst))); \
} \
} \
- } \
- else { \
+ } else { \
if (op & SLJIT_SET_Z) \
FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); \
if (!(flags & UNUSED_DEST)) \
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_s32 is_overflow, is_carry, carry_src_r, is_handled, reg;
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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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);
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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);
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
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)
+ } 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 {
+ } else {
if (is_overflow)
FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
else if (op & SLJIT_SET_Z)
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) {
+ } 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;
}
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;
+ reg = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(reg) | RJ(TMP_ZERO) | IMM_I12(src2)));
+ src2 = reg;
flags &= ~SRC2_IMM;
}
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 {
+ } 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))
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)
+ } 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)
/* 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 {
+ } 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, 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 {
+ } else {
if (is_carry)
FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
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) {
sljit_s32 dst_r = TMP_REG2;
sljit_s32 src1_r;
sljit_sw src2_r = 0;
- sljit_s32 sugg_src2_r = TMP_REG2;
+ sljit_s32 src2_tmp_reg = (GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
SLJIT_ASSERT(HAS_FLAGS(op));
flags |= UNUSED_DEST;
dst = TMP_REG2;
- }
- else if (FAST_IS_REG(dst)) {
+ } 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))
+ src2_tmp_reg = 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) {
+ } else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && src1w <= I12_MAX && src1w >= I12_MIN) {
flags |= SRC2_IMM;
src2_r = src1w;
if (FAST_IS_REG(src1)) {
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));
src1_r = TMP_REG1;
}
else
src1_r = TMP_ZERO;
- }
- else {
+ } else {
if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w))
FAIL_IF(compiler->error);
else
flags |= REG2_SOURCE;
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));
- src2_r = sugg_src2_r;
- }
- else {
+ FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w));
+ src2_r = src2_tmp_reg;
+ } else {
src2_r = TMP_ZERO;
if (flags & MOVE_OP) {
if (dst & SLJIT_MEM)
}
}
}
- }
- else {
- if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w))
+ } else {
+ if (getput_arg_fast(compiler, flags | LOAD_DATA, src2_tmp_reg, src2, src2w))
FAIL_IF(compiler->error);
else
flags |= SLOW_SRC2;
- src2_r = sugg_src2_r;
+ src2_r = src2_tmp_reg;
}
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)) {
+ if ((flags & SLOW_DEST) && !can_cache(src2, src2w, src1, src1w) && can_cache(src2, src2w, dst, dstw)) {
+ FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
+ FAIL_IF(getput_arg(compiler, flags | LOAD_DATA | MEM_USE_TMP2, TMP_REG2, src2, src2w, dst, dstw));
+ } else {
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(getput_arg(compiler, flags | LOAD_DATA | ((src1_r == TMP_REG1) ? MEM_USE_TMP2 : 0), src2_tmp_reg, src2, src2w, dst, dstw));
FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
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);
+ return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 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_ZERO, 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);
+ return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 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_ZERO, 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_ZERO, 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);
+ return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, op, flags, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_ZERO, 0, src, srcw);
}
SLJIT_UNREACHABLE();
return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w));
+ return push_inst(compiler, ADD_D | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG2));
+ }
+
+ return SLJIT_SUCCESS;
+}
+
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,
if (type == SLJIT_GP_REGISTER)
return reg_map[reg];
- if (type != SLJIT_FLOAT_REGISTER)
+ if (type != SLJIT_FLOAT_REGISTER && type != SLJIT_SIMD_REG_128 && type != SLJIT_SIMD_REG_256)
return -1;
return freg_map[reg];
switch (GET_OPCODE(op)) {
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst(compiler, FINST(FMOV, op) | FRD(dst_r) | FRJ(src)));
else
dst_r = src;
}
if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+ if ((dst & SLJIT_MEM) && !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 {
+ } 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));
}
break;
}
- if (dst_r == TMP_FREG2)
+ if (dst_r != dst)
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
return SLJIT_SUCCESS;
}
PTR_FAIL_IF(push_inst(compiler, inst));
/* Maximum number of instructions required for generating a constant. */
- compiler->size += 3;
-
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
struct sljit_jump *jump;
sljit_s32 flags;
sljit_ins inst;
+ sljit_s32 src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
}
if (src2 & SLJIT_MEM) {
- PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG2, src2, src2w, 0, 0));
- src2 = TMP_REG2;
+ PTR_FAIL_IF(emit_op_mem2(compiler, flags, src2_tmp_reg, src2, src2w, 0, 0));
+ src2 = src2_tmp_reg;
}
if (src1 == SLJIT_IMM) {
if (src2 == SLJIT_IMM) {
if (src2w != 0) {
- PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w));
- src2 = TMP_REG2;
+ PTR_FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w));
+ src2 = src2_tmp_reg;
}
else
src2 = TMP_ZERO;
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;
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
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;
+ compiler->size += JUMP_MAX_SIZE - 1;
return SLJIT_SUCCESS;
}
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)));
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(dst_reg) | IMM_I12(0)));
if ((src1 & REG_MASK) == dst_reg)
- src1 = (src1 & ~REG_MASK) | TMP_REG2;
+ src1 = (src1 & ~REG_MASK) | TMP_REG1;
if (OFFS_REG(src1) == dst_reg)
- src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1);
}
FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_reg) | RJ(src2_reg) | IMM_I12(0)));
if ((type & ~SLJIT_32) == SLJIT_EQUAL)
invert = 1;
FAIL_IF(push_inst(compiler, MOVGR2CF | FCD(F_OTHER_FLAG) | RJ(EQUAL_FLAG)));
- }
- else
+ } else {
+ if (get_jump_instruction(type & ~SLJIT_32) == (BNE | RJ(OTHER_FLAG) | RD(TMP_ZERO)))
+ invert = 1;
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));
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, TMP_FREG2, 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));
+ return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(TMP_FREG2) | FRK(src2_freg) | FCA(F_OTHER_FLAG));
+ return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src2_freg) | FRK(TMP_FREG2) | FCA(F_OTHER_FLAG));
} else {
if (invert)
return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src1) | FRK(src2_freg) | FCA(F_OTHER_FLAG));
#undef TO_ARGW_HI
+static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, sljit_s32 *mem_ptr, sljit_sw memw)
+{
+ sljit_s32 mem = *mem_ptr;
+
+ if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+ *mem_ptr = TMP_REG3;
+ FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG3) | RJ(OFFS_REG(mem)) | IMM_I12(memw & 0x3)));
+ return push_inst(compiler, ADD_D | RD(TMP_REG3) | RJ(TMP_REG3) | RK(mem & REG_MASK));
+ }
+
+ if (!(mem & REG_MASK)) {
+ *mem_ptr = TMP_REG3;
+ return load_immediate(compiler, TMP_REG3, memw);
+ }
+
+ mem &= REG_MASK;
+
+ if (memw == 0) {
+ *mem_ptr = mem;
+ return SLJIT_SUCCESS;
+ }
+
+ *mem_ptr = TMP_REG3;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG3, memw));
+ return push_inst(compiler, ADD_D | RD(TMP_REG3) | RJ(TMP_REG3) | RK(mem));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (!(srcdst & SLJIT_MEM)) {
+ if (type & SLJIT_SIMD_STORE)
+ ins = FRD(srcdst) | FRJ(freg) | FRK(freg);
+ else
+ ins = FRD(freg) | FRJ(srcdst) | FRK(srcdst);
+
+ if (reg_size == 5)
+ ins |= VOR_V | (sljit_ins)1 << 26;
+ else
+ ins |= VOR_V;
+
+ return push_inst(compiler, ins);
+ }
+
+ ins = (type & SLJIT_SIMD_STORE) ? VST : VLD;
+
+ if (reg_size == 5)
+ ins = (type & SLJIT_SIMD_STORE) ? XVST : XVLD;
+
+ if (FAST_IS_REG(srcdst) && srcdst >= 0 && (srcdstw >= I12_MIN && srcdstw <= I12_MAX))
+ return push_inst(compiler, ins | FRD(freg) | RJ((sljit_u8)srcdst) | IMM_I12(srcdstw));
+ else {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+ return push_inst(compiler, ins | FRD(freg) | RJ(srcdst) | IMM_I12(0));
+ }
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+
+ if (reg_size == 5)
+ ins = (sljit_ins)1 << 25;
+
+ return push_inst(compiler, VLDREPL | ins | FRD(freg) | RJ(src) | (sljit_ins)1 << (23 - elem_size));
+ }
+
+ if (reg_size == 5)
+ ins = (sljit_ins)1 << 26;
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (src == SLJIT_IMM)
+ return push_inst(compiler, VREPLGR2VR | ins | FRD(freg) | RJ(TMP_ZERO) | (sljit_ins)elem_size << 10);
+
+ FAIL_IF(push_inst(compiler, VREPLVE | ins | FRD(freg) | FRJ(src) | RK(TMP_ZERO) | (sljit_ins)elem_size << 15));
+
+ if (reg_size == 5) {
+ ins = (sljit_ins)(0x44 << 10);
+ return push_inst(compiler, XVPERMI | ins | FRD(freg) | FRJ(freg));
+ }
+
+ return SLJIT_SUCCESS;
+ }
+
+ ins |= VREPLGR2VR | (sljit_ins)elem_size << 10;
+
+ if (src == SLJIT_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG2, srcw));
+ src = TMP_REG2;
+ }
+
+ return push_inst(compiler, ins | FRD(freg) | RJ(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ ins = (reg_size == 5) ? ((sljit_ins)1 << 26) : 0;
+
+ if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) {
+ FAIL_IF(push_inst(compiler, VOR_V | ins | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg)));
+ srcdst = TMP_FREG1;
+ srcdstw = 0;
+ }
+
+ FAIL_IF(push_inst(compiler, VXOR_V | ins | FRD(freg) | FRJ(freg) | FRK(freg)));
+ }
+
+ if (srcdst & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+
+ if (reg_size == 5)
+ ins = (sljit_ins)1 << 25;
+
+ if (type & SLJIT_SIMD_STORE) {
+ ins |= (sljit_ins)lane_index << 18 | (sljit_ins)(1 << (23 - elem_size));
+ return push_inst(compiler, VSTELM | ins | FRD(freg) | RJ(srcdst));
+ } else {
+ emit_op_mem(compiler, (elem_size == 3 ? WORD_DATA : (elem_size == 2 ? INT_DATA : (elem_size == 1 ? HALF_DATA : BYTE_DATA))) | LOAD_DATA, TMP_REG1, srcdst | SLJIT_MEM, 0);
+ srcdst = TMP_REG1;
+ ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10;
+
+ if (reg_size == 5) {
+ if (elem_size < 2) {
+ FAIL_IF(push_inst(compiler, VOR_V | (sljit_ins)1 << 26 | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg)));
+ if (lane_index >= (2 << (3 - elem_size))) {
+ FAIL_IF(push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(TMP_FREG1) | FRJ(freg) | IMM_I8(1)));
+ FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(TMP_FREG1) | RJ(srcdst) | IMM_V(lane_index % (2 << (3 - elem_size)))));
+ return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(2));
+ } else {
+ FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index)));
+ return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(18));
+ }
+ } else
+ ins = (sljit_ins)(0x3f ^ (0x3f >> elem_size)) << 10 | (sljit_ins)1 << 26;
+ }
+
+ return push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index));
+ }
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ ins = (reg_size == 5) ? (sljit_ins)(0x3f ^ (0x3f >> elem_size)) << 10 | (sljit_ins)1 << 26 : (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10;
+
+ if (type & SLJIT_SIMD_STORE) {
+ FAIL_IF(push_inst(compiler, VPICKVE2GR_U | ins | RD(TMP_REG1) | FRJ(freg) | IMM_V(lane_index)));
+ return push_inst(compiler, VINSGR2VR | ins | FRD(srcdst) | RJ(TMP_REG1) | IMM_V(0));
+ } else {
+ FAIL_IF(push_inst(compiler, VPICKVE2GR_U | ins | RD(TMP_REG1) | FRJ(srcdst) | IMM_V(0)));
+ return push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(TMP_REG1) | IMM_V(lane_index));
+ }
+ }
+
+ if (srcdst == SLJIT_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcdstw));
+ srcdst = TMP_REG1;
+ }
+
+ if (type & SLJIT_SIMD_STORE) {
+ ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10;
+
+ if (type & SLJIT_SIMD_LANE_SIGNED)
+ ins |= (sljit_ins)(VPICKVE2GR_U ^ (0x7 << 18));
+ else
+ ins |= VPICKVE2GR_U;
+
+ if (reg_size == 5) {
+ if (elem_size < 2) {
+ if (lane_index >= (2 << (3 - elem_size))) {
+ if (type & SLJIT_SIMD_LANE_SIGNED)
+ ins |= (sljit_ins)(VPICKVE2GR_U ^ (0x7 << 18));
+ else
+ ins |= VPICKVE2GR_U;
+
+ FAIL_IF(push_inst(compiler, VOR_V | (sljit_ins)1 << 26 | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg)));
+ FAIL_IF(push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(TMP_FREG1) | FRJ(freg) | IMM_I8(1)));
+ return push_inst(compiler, ins | RD(srcdst) | FRJ(TMP_FREG1) | IMM_V(lane_index % (2 << (3 - elem_size))));
+ }
+ } else {
+ ins ^= (sljit_ins)1 << (15 - elem_size);
+ ins |= (sljit_ins)1 << 26;
+ }
+ }
+
+ return push_inst(compiler, ins | RD(srcdst) | FRJ(freg) | IMM_V(lane_index));
+ } else {
+ ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10;
+
+ if (reg_size == 5) {
+ if (elem_size < 2) {
+ FAIL_IF(push_inst(compiler, VOR_V | (sljit_ins)1 << 26 | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg)));
+ if (lane_index >= (2 << (3 - elem_size))) {
+ FAIL_IF(push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(TMP_FREG1) | FRJ(freg) | IMM_I8(1)));
+ FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(TMP_FREG1) | RJ(srcdst) | IMM_V(lane_index % (2 << (3 - elem_size)))));
+ return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(2));
+ } else {
+ FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index)));
+ return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(18));
+ }
+ } else
+ ins = (sljit_ins)(0x3f ^ (0x3f >> elem_size)) << 10 | (sljit_ins)1 << 26;
+ }
+
+ return push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index));
+ }
+
+ return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10;
+
+ if (reg_size == 5) {
+ FAIL_IF(push_inst(compiler, VREPLVEI | (sljit_ins)1 << 26 | ins | FRD(freg) | FRJ(src) | IMM_V(src_lane_index % (2 << (3 - elem_size)))));
+
+ ins = (src_lane_index < (2 << (3 - elem_size))) ? (sljit_ins)(0x44 << 10) : (sljit_ins)(0xee << 10);
+
+ return push_inst(compiler, XVPERMI | ins | FRD(freg) | FRJ(freg));
+ }
+
+ return push_inst(compiler, VREPLVEI | ins | FRD(freg) | FRJ(src) | IMM_V(src_lane_index));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (src & SLJIT_MEM) {
+ ins = (type & SLJIT_SIMD_STORE) ? VST : VLD;
+
+ if (reg_size == 5)
+ ins = (type & SLJIT_SIMD_STORE) ? XVST : XVLD;
+
+ if (FAST_IS_REG(src) && src >= 0 && (srcw >= I12_MIN && srcw <= I12_MAX))
+ FAIL_IF(push_inst(compiler, ins | FRD(freg) | RJ(src) | IMM_I12(srcw)));
+ else {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+ FAIL_IF(push_inst(compiler, ins | FRD(freg) | RJ(src) | IMM_I12(0)));
+ }
+ src = freg;
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size != 2 || elem2_size != 3)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ ins = 0;
+ if (reg_size == 5) {
+ ins = (sljit_ins)1 << 26;
+ FAIL_IF(push_inst(compiler, XVPERMI | FRD(src) | FRJ(src) | IMM_I8(16)));
+ }
+
+ return push_inst(compiler, VFCVTL_D_S | ins | FRD(freg) | FRJ(src));
+ }
+
+ ins = (type & SLJIT_SIMD_EXTEND_SIGNED) ? VSLLWIL : (VSLLWIL | (sljit_ins)1 << 18);
+
+ if (reg_size == 5)
+ ins |= (sljit_ins)1 << 26;
+
+ do {
+ if (reg_size == 5)
+ FAIL_IF(push_inst(compiler, XVPERMI | FRD(src) | FRJ(src) | IMM_I8(16)));
+
+ FAIL_IF(push_inst(compiler, ins | ((sljit_ins)1 << (13 + elem_size)) | FRD(freg) | FRJ(src)));
+ src = freg;
+ } while (++elem_size < elem2_size);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
+
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (elem_size > 3 || ((type & SLJIT_SIMD_FLOAT) && elem_size < 2))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+
+ if (reg_size == 5)
+ ins = (sljit_ins)1 << 26;
+
+ FAIL_IF(push_inst(compiler, VMSKLTZ | ins | (sljit_ins)(elem_size << 10) | FRD(TMP_FREG1) | FRJ(freg)));
+
+ FAIL_IF(push_inst(compiler, VPICKVE2GR_U | (sljit_ins)(0x3c << 10) | RD(dst_r) | FRJ(TMP_FREG1)));
+
+ if (reg_size == 5) {
+ FAIL_IF(push_inst(compiler, VPICKVE2GR_U | (sljit_ins)(0x38 << 10) | ins | RD(TMP_REG3) | FRJ(TMP_FREG1) | IMM_V(2)));
+ FAIL_IF(push_inst(compiler, SLLI_W | RD(TMP_REG3) | RJ(TMP_REG3) | IMM_I12(2 << (3 - elem_size))));
+ FAIL_IF(push_inst(compiler, OR | RD(dst_r) | RJ(dst_r) | RK(TMP_REG3)));
+ }
+
+ if (dst_r == TMP_REG2)
+ return emit_op_mem(compiler, ((type & SLJIT_32) ? INT_DATA : WORD_DATA), TMP_REG2, dst, dstw);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
+
+ if (reg_size != 5 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ switch (SLJIT_SIMD_GET_OPCODE(type)) {
+ case SLJIT_SIMD_OP2_AND:
+ ins = VAND_V;
+ break;
+ case SLJIT_SIMD_OP2_OR:
+ ins = VOR_V;
+ break;
+ case SLJIT_SIMD_OP2_XOR:
+ ins = VXOR_V;
+ break;
+ }
+
+ if (reg_size == 5)
+ ins |= (sljit_ins)1 << 26;
+
+ return push_inst(compiler, ins | FRD(dst_freg) | FRJ(src1_freg) | FRK(src2_freg));
+}
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler,
sljit_s32 op,
sljit_s32 dst_reg,
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;
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;
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
- compiler->size += 3;
+ compiler->size += JUMP_MAX_SIZE - 1;
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
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);
+ SLJIT_ASSERT(reg_map[TMP_REG2] == 4 && freg_map[TMP_FREG1] == 12);
arg_types >>= SLJIT_ARG_SHIFT;
} else if (type & SLJIT_CALL_RETURN)
PTR_FAIL_IF(emit_stack_frame_release(compiler, 0, &ins));
- SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+ SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);
if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS)
jump->flags |= IS_MOVABLE;
return sljit_emit_ijump(compiler, type, src, srcw);
}
- SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+ SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);
if (src == SLJIT_IMM)
FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
sljit_ins prev_ins = *ins_ptr;
sljit_ins ins = NOP;
- SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
+ SLJIT_ASSERT(reg_map[TMP_REG2] == 4 && freg_map[TMP_FREG1] == 12);
arg_types >>= SLJIT_ARG_SHIFT;
if ((type & 0xff) != SLJIT_CALL_REG_ARG)
PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins));
- SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+ SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);
if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS)
jump->flags |= IS_MOVABLE;
return sljit_emit_ijump(compiler, type, src, srcw);
}
- SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+ SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG1);
if (src == SLJIT_IMM)
FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
/* For position independent code, t9 must contain the function address. */
-#define PIC_ADDR_REG TMP_REG2
+#define PIC_ADDR_REG TMP_REG1
/* Floating point status register. */
#define FCSR_REG 31
#define OTHER_FLAG 1
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
- 0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 4, 25, 31, 3, 1
+ 0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 25, 4, 31, 3, 1
};
#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
if (jump->flags & JUMP_ADDR)
target_addr = jump->u.target;
else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+ SLJIT_ASSERT(jump->u.label != NULL);
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
}
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
-static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset)
{
- if (max_label < 0x80000000l) {
- put_label->flags = PATCH_ABS32;
+ sljit_uw addr;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ if (addr < 0x80000000l) {
+ jump->flags |= PATCH_ABS32;
return 1;
}
- if (max_label < 0x800000000000l) {
- put_label->flags = PATCH_ABS48;
+ if (addr < 0x800000000000l) {
+ jump->flags |= PATCH_ABS48;
return 3;
}
- put_label->flags = 0;
return 5;
}
#endif /* SLJIT_CONFIG_MIPS_64 */
-static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
+static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump)
{
- struct sljit_jump *jump;
- 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;
-#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
- flags = put_label->flags;
-#endif
- inst = (sljit_ins*)put_label->addr;
- addr = put_label->label->addr;
- reg = *inst;
- }
+ sljit_uw flags = jump->flags;
+ sljit_ins *ins = (sljit_ins*)jump->addr;
+ sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
+ sljit_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : PIC_ADDR_REG;
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- inst[0] = LUI | T(reg) | IMM(addr >> 16);
+ ins[0] = LUI | T(reg) | IMM(addr >> 16);
#else /* !SLJIT_CONFIG_MIPS_32 */
if (flags & PATCH_ABS32) {
SLJIT_ASSERT(addr < 0x80000000l);
- inst[0] = LUI | T(reg) | IMM(addr >> 16);
+ ins[0] = LUI | T(reg) | IMM(addr >> 16);
}
else if (flags & PATCH_ABS48) {
SLJIT_ASSERT(addr < 0x800000000000l);
- inst[0] = LUI | T(reg) | IMM(addr >> 32);
- inst[1] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff);
- inst[2] = DSLL | T(reg) | D(reg) | SH_IMM(16);
- inst += 2;
+ ins[0] = LUI | T(reg) | IMM(addr >> 32);
+ ins[1] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff);
+ ins[2] = DSLL | T(reg) | D(reg) | SH_IMM(16);
+ ins += 2;
}
else {
- inst[0] = LUI | T(reg) | IMM(addr >> 48);
- inst[1] = ORI | S(reg) | T(reg) | IMM((addr >> 32) & 0xffff);
- inst[2] = DSLL | T(reg) | D(reg) | SH_IMM(16);
- inst[3] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff);
- inst[4] = DSLL | T(reg) | D(reg) | SH_IMM(16);
- inst += 4;
+ ins[0] = LUI | T(reg) | IMM(addr >> 48);
+ ins[1] = ORI | S(reg) | T(reg) | IMM((addr >> 32) & 0xffff);
+ ins[2] = DSLL | T(reg) | D(reg) | SH_IMM(16);
+ ins[3] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff);
+ ins[4] = DSLL | T(reg) | D(reg) | SH_IMM(16);
+ ins += 4;
}
#endif /* SLJIT_CONFIG_MIPS_32 */
- inst[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff);
+ ins[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff);
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_ins *code;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
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);
+ code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
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;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
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) {
+ if (next_min_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);
+ if (next_min_addr == next_label_size) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (jump && jump->addr == word_count) {
+
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- word_count += 2;
-#else
- word_count += 6;
-#endif
- jump->addr = (sljit_uw)(code_ptr - 1);
- code_ptr = detect_jump_type(jump, code, executable_offset);
+ word_count += 2;
+#else /* !SLJIT_CONFIG_MIPS_32 */
+ word_count += 6;
+#endif /* SLJIT_CONFIG_MIPS_32 */
+ jump->addr = (sljit_uw)(code_ptr - 1);
+ code_ptr = detect_jump_type(jump, code, executable_offset);
+ } else {
+ jump->addr = (sljit_uw)code_ptr;
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+ code_ptr += 1;
+ word_count += 1;
+#else /* !SLJIT_CONFIG_MIPS_32 */
+ code_ptr += mov_addr_get_length(jump, code, executable_offset);
+ word_count += 5;
+#endif /* SLJIT_CONFIG_MIPS_32 */
+ }
+
jump = jump->next;
- }
- if (const_ && const_->addr == word_count) {
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- if (put_label && put_label->addr == word_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
-#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- code_ptr += 1;
- word_count += 1;
-#else
- code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
- word_count += 5;
-#endif
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
+
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
word_count++;
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)code_ptr;
+ label->u.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 {
- addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+ addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
buf_ptr = (sljit_ins *)jump->addr;
if (jump->flags & PATCH_B) {
break;
}
- load_addr_to_reg(jump, PIC_ADDR_REG);
+ load_addr_to_reg(jump);
} 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;
+ jump = jump->next;
}
compiler->error = SLJIT_ERR_COMPILED;
static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size, sljit_ins *ins_ptr);
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-#define SELECT_OP(a, b) (b)
+#define SELECT_OP(d, w) (w)
#else
-#define SELECT_OP(a, b) (!(op & SLJIT_32) ? a : b)
+#define SELECT_OP(d, w) (!(op & SLJIT_32) ? (d) : (w))
#endif
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
offset = local_size - SSIZE_OF(sw);
} else {
FAIL_IF(load_immediate(compiler, OTHER_FLAG, local_size));
- FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, SUBU_W | S(SLJIT_SP) | TA(OTHER_FLAG) | D(SLJIT_SP), DR(SLJIT_SP)));
- base = S(TMP_REG2);
+ base = S(TMP_REG1);
offset = -SSIZE_OF(sw);
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
local_size = 0;
if (tmp < frame_size)
tmp = frame_size;
- FAIL_IF(load_immediate(compiler, DR(TMP_REG1), local_size - tmp));
- FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | T(TMP_REG1) | D(SLJIT_SP), DR(SLJIT_SP)));
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG2), local_size - tmp));
+ FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | T(TMP_REG2) | D(SLJIT_SP), DR(SLJIT_SP)));
local_size = tmp;
}
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_ar, is_handled;
+ sljit_s32 is_overflow, is_carry, carry_src_ar, is_handled, reg;
sljit_ins op_imm, op_v;
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
sljit_ins ins, op_dimm, op_dimm32, op_dv;
is_handled = 1;
if (flags & SRC2_IMM) {
- FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
- src2 = TMP_REG2;
+ reg = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+ FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(reg) | IMM(src2), DR(reg)));
+ src2 = reg;
flags &= ~SRC2_IMM;
}
sljit_s32 dst_r = TMP_REG2;
sljit_s32 src1_r;
sljit_sw src2_r = 0;
- sljit_s32 sugg_src2_r = TMP_REG2;
+ sljit_s32 src2_tmp_reg = (GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
dst_r = dst;
flags |= REG_DEST;
if (flags & MOVE_OP)
- sugg_src2_r = dst_r;
+ src2_tmp_reg = dst_r;
}
else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, DR(TMP_REG1), dst, dstw))
flags |= SLOW_DEST;
else if (src2 == SLJIT_IMM) {
if (!(flags & SRC2_IMM)) {
if (src2w) {
- FAIL_IF(load_immediate(compiler, DR(sugg_src2_r), src2w));
- src2_r = sugg_src2_r;
+ FAIL_IF(load_immediate(compiler, DR(src2_tmp_reg), src2w));
+ src2_r = src2_tmp_reg;
}
else {
src2_r = 0;
}
}
else {
- if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w))
+ if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(src2_tmp_reg), src2, src2w))
FAIL_IF(compiler->error);
else
flags |= SLOW_SRC2;
- src2_r = sugg_src2_r;
+ src2_r = src2_tmp_reg;
}
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)) {
+ if ((flags & SLOW_DEST) && !can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG2), src2, src2w, src1, src1w));
FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw));
}
else if (flags & SLOW_SRC1)
FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw));
else if (flags & SLOW_SRC2)
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w, dst, dstw));
+ FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(src2_tmp_reg), src2, src2w, dst, dstw));
FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
#define SELECT_OP3(op, src2w, D, D32, W) (((op & SLJIT_32) ? (W) : ((src2w) < 32) ? (D) : (D32)) | (((sljit_ins)src2w & 0x1f) << 6))
-#define SELECT_OP2(op, D, W) ((op & SLJIT_32) ? (W) : (D))
#else /* !SLJIT_CONFIG_MIPS_64 */
#define SELECT_OP3(op, src2w, D, D32, W) ((W) | ((sljit_ins)(src2w) << 6))
-#define SELECT_OP2(op, D, W) (W)
#endif /* SLJIT_CONFIG_MIPS_64 */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w));
+ return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst_reg) | T(TMP_REG2) | D(dst_reg), DR(dst_reg));
+ }
+
+ return SLJIT_SUCCESS;
+}
+
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,
FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src3, src3w));
src3 = TMP_REG2;
} else if (dst_reg == src3) {
- FAIL_IF(push_inst(compiler, SELECT_OP2(op, DADDU, ADDU) | S(src3) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src3) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
src3 = TMP_REG2;
}
if (is_left) {
- ins1 = SELECT_OP2(op, DSRL, SRL);
- ins2 = SELECT_OP2(op, DSLLV, SLLV);
- ins3 = SELECT_OP2(op, DSRLV, SRLV);
+ ins1 = SELECT_OP(DSRL, SRL);
+ ins2 = SELECT_OP(DSLLV, SLLV);
+ ins3 = SELECT_OP(DSRLV, SRLV);
} else {
- ins1 = SELECT_OP2(op, DSLL, SLL);
- ins2 = SELECT_OP2(op, DSRLV, SRLV);
- ins3 = SELECT_OP2(op, DSLLV, SLLV);
+ ins1 = SELECT_OP(DSLL, SLL);
+ ins2 = SELECT_OP(DSRLV, SRLV);
+ ins3 = SELECT_OP(DSLLV, SLLV);
}
FAIL_IF(push_inst(compiler, ins2 | S(src3) | T(src1_reg) | D(dst_reg), DR(dst_reg)));
FAIL_IF(push_inst(compiler, XORI | S(src3) | T(TMP_REG2) | ((sljit_ins)bit_length - 1), DR(TMP_REG2)));
src2_reg = TMP_REG1;
} else
- FAIL_IF(push_inst(compiler, SELECT_OP2(op, DSUBU, SUBU) | SA(0) | T(src3) | D(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(0) | T(src3) | D(TMP_REG2), DR(TMP_REG2)));
FAIL_IF(push_inst(compiler, ins3 | S(TMP_REG2) | T(src2_reg) | D(TMP_REG1), DR(TMP_REG1)));
return push_inst(compiler, OR | S(dst_reg) | T(TMP_REG1) | D(dst_reg), DR(dst_reg));
}
#undef SELECT_OP3
-#undef SELECT_OP2
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src, sljit_sw srcw)
switch (GET_OPCODE(op)) {
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst(compiler, MOV_fmt(FMT(op)) | FS(src) | FD(dst_r), MOVABLE_INS));
else
dst_r = src;
}
if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+ if ((dst & SLJIT_MEM) && !can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, src1, src1w));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, dst, dstw));
- }
- else {
+ } else {
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, src2, src2w));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, dst, dstw));
}
PTR_FAIL_IF(push_inst(compiler, inst, UNMOVABLE_INS));
if (type <= SLJIT_JUMP)
- PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS));
+ PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS));
else {
jump->flags |= IS_JAL;
- PTR_FAIL_IF(push_inst(compiler, JALR | S(TMP_REG2) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
+ PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
}
jump->addr = compiler->size;
#define RESOLVE_IMM2() \
if (src2 == SLJIT_IMM) { \
if (src2w) { \
- PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG2), src2w)); \
- src2 = TMP_REG2; \
+ PTR_FAIL_IF(load_immediate(compiler, DR(src2_tmp_reg), src2w)); \
+ src2 = src2_tmp_reg; \
} \
else \
src2 = 0; \
struct sljit_jump *jump;
sljit_s32 flags;
sljit_ins inst;
+ sljit_s32 src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
}
if (src2 & SLJIT_MEM) {
- PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG2), src2, src2w, 0, 0));
- src2 = TMP_REG2;
+ PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(src2_tmp_reg), src2, src2w, 0, 0));
+ src2 = src2_tmp_reg;
}
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
PTR_FAIL_IF(push_inst(compiler, (type == SLJIT_EQUAL ? BNE : BEQ) | S(TMP_REG1) | TA(0) | BRANCH_LENGTH, UNMOVABLE_INS));
}
- PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS));
+ PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS));
jump->addr = compiler->size;
PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
if (compiler->delay_slot != UNMOVABLE_INS)
jump->flags |= IS_MOVABLE;
- src = TMP_REG2;
+ src = PIC_ADDR_REG;
} else if (src & SLJIT_MEM) {
ADJUST_LOCAL_OFFSET(src, srcw);
- FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(TMP_REG2), src, srcw));
- src = TMP_REG2;
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
+ src = PIC_ADDR_REG;
}
if (type <= SLJIT_JUMP)
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src1, src1w));
- src1 = TMP_REG2;
+ FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG1), src1, src1w));
+ src1 = TMP_REG1;
} else if (src1 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
if (type & SLJIT_32)
type ^= 0x1;
} else {
if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
- FAIL_IF(push_inst(compiler, ADDU_W | S(dst_reg) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, ADDU_W | S(dst_reg) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
if ((src1 & REG_MASK) == dst_reg)
- src1 = (src1 & ~REG_MASK) | TMP_REG2;
+ src1 = (src1 & ~REG_MASK) | TMP_REG1;
if (OFFS_REG(src1) == dst_reg)
- src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1);
}
FAIL_IF(push_inst(compiler, mov_ins | S(src2_reg) | TA(0) | D(dst_reg), DR(dst_reg)));
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, FR(TMP_FREG1), src1, src1w));
- src1 = TMP_FREG1;
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, FR(TMP_FREG2), src1, src1w));
+ src1 = TMP_FREG2;
}
return push_inst(compiler, get_select_cc(type, 1) | FMT(type) | FS(src1) | FD(dst_freg), MOVABLE_INS);
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r, UNMOVABLE_INS));
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw));
- return put_label;
+ return jump;
}
#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
#define TMP_CALL_REG (SLJIT_NUMBER_OF_REGISTERS + 5)
#else
-#define TMP_CALL_REG TMP_REG2
+#define TMP_CALL_REG TMP_REG1
#endif
#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
{
sljit_sw diff;
sljit_uw target_addr;
- sljit_uw extra_jump_flags;
#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL))
- return 0;
+ goto exit;
#else
if (jump->flags & SLJIT_REWRITABLE_JUMP)
- return 0;
+ goto exit;
#endif
if (jump->flags & JUMP_ADDR)
target_addr = jump->u.target;
else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+ SLJIT_ASSERT(jump->u.label != NULL);
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
}
goto keep_address;
#endif
- diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l;
+ diff = (sljit_sw)target_addr - (sljit_sw)code_ptr - executable_offset;
- extra_jump_flags = 0;
if (jump->flags & IS_COND) {
if (diff <= 0x7fff && diff >= -0x8000) {
jump->flags |= PATCH_B;
- return 1;
+ return code_ptr;
}
if (target_addr <= 0xffff) {
jump->flags |= PATCH_B | PATCH_ABS_B;
- return 1;
+ return code_ptr;
}
- extra_jump_flags = REMOVE_COND;
diff -= SSIZE_OF(ins);
}
if (diff <= 0x01ffffff && diff >= -0x02000000) {
- jump->flags |= PATCH_B | extra_jump_flags;
- return 1;
+ jump->flags |= PATCH_B;
+ } else if (target_addr <= 0x01ffffff) {
+ jump->flags |= PATCH_B | PATCH_ABS_B;
}
- if (target_addr <= 0x03ffffff) {
- jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags;
- return 1;
+ if (jump->flags & PATCH_B) {
+ if (!(jump->flags & IS_COND))
+ return code_ptr;
+
+ code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001);
+ code_ptr[1] = Bx;
+ jump->addr += sizeof(sljit_ins);
+ jump->flags -= IS_COND;
+ return code_ptr + 1;
}
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
keep_address:
-#endif
- if (target_addr <= 0x7fffffff) {
+#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
+ if (target_addr < 0x80000000l) {
jump->flags |= PATCH_ABS32;
- return 1;
+ code_ptr[2] = MTCTR | S(TMP_CALL_REG);
+ code_ptr[3] = code_ptr[0];
+ return code_ptr + 3;
}
- if (target_addr <= 0x7fffffffffffl) {
+ if (target_addr < 0x800000000000l) {
jump->flags |= PATCH_ABS48;
- return 1;
+ code_ptr[4] = MTCTR | S(TMP_CALL_REG);
+ code_ptr[5] = code_ptr[0];
+ return code_ptr + 5;
}
-#endif
+#endif /* SLJIT_CONFIG_PPC_64 */
- return 0;
+exit:
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+ code_ptr[2] = MTCTR | S(TMP_CALL_REG);
+ code_ptr[3] = code_ptr[0];
+#else /* !SLJIT_CONFIG_PPC_32 */
+ code_ptr[5] = MTCTR | S(TMP_CALL_REG);
+ code_ptr[6] = code_ptr[0];
+#endif /* SLJIT_CONFIG_PPC_32 */
+ return code_ptr + JUMP_MAX_SIZE - 1;
}
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset)
{
- if (max_label < 0x100000000l) {
- put_label->flags = 0;
+ sljit_uw addr;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ SLJIT_ASSERT(jump->flags < ((sljit_uw)5 << JUMP_SIZE_SHIFT));
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ if (addr < 0x80000000l) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS32;
return 1;
}
- if (max_label < 0x1000000000000l) {
- put_label->flags = 1;
+ if (addr < 0x800000000000l) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS48;
return 3;
}
- put_label->flags = 2;
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)4 << JUMP_SIZE_SHIFT));
return 4;
}
-static SLJIT_INLINE void put_label_set(struct sljit_put_label *put_label)
-{
- sljit_uw addr = put_label->label->addr;
- sljit_ins *inst = (sljit_ins *)put_label->addr;
- sljit_u32 reg = *inst;
+#endif /* SLJIT_CONFIG_PPC_64 */
- if (put_label->flags == 0) {
- SLJIT_ASSERT(addr < 0x100000000l);
- inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 16);
- }
- else {
- if (put_label->flags == 1) {
- SLJIT_ASSERT(addr < 0x1000000000000l);
- inst[0] = ORI | S(TMP_ZERO) | A(reg) | IMM(addr >> 32);
+static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset)
+{
+ sljit_uw flags = jump->flags;
+ sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
+ sljit_ins *ins = (sljit_ins*)jump->addr;
+ sljit_s32 reg;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ if (flags & PATCH_B) {
+ if (flags & IS_COND) {
+ if (!(flags & PATCH_ABS_B)) {
+ addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset);
+ SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);
+ ins[0] = BCx | ((sljit_ins)addr & 0xfffc) | (ins[0] & 0x03ff0001);
+ } else {
+ SLJIT_ASSERT(addr <= 0xffff);
+ ins[0] = BCx | ((sljit_ins)addr & 0xfffc) | 0x2 | ((*ins) & 0x03ff0001);
+ }
+ return;
}
- else {
- inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 48);
- inst[1] = ORI | S(reg) | A(reg) | IMM((addr >> 32) & 0xffff);
- inst++;
+
+ if (!(flags & PATCH_ABS_B)) {
+ addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset);
+ SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);
+ ins[0] = Bx | ((sljit_ins)addr & 0x03fffffc) | (ins[0] & 0x1);
+ } else {
+ SLJIT_ASSERT(addr <= 0x03ffffff);
+ ins[0] = Bx | ((sljit_ins)addr & 0x03fffffc) | 0x2 | (ins[0] & 0x1);
}
+ return;
+ }
+
+ reg = (flags & JUMP_MOV_ADDR) ? (sljit_s32)ins[0] : TMP_CALL_REG;
+
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+ ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 16);
+ ins[1] = ORI | S(reg) | A(reg) | IMM(addr);
+#else /* !SLJIT_CONFIG_PPC_32 */
+
+ /* The TMP_ZERO cannot be used because it is restored for tail calls. */
+ if (flags & PATCH_ABS32) {
+ SLJIT_ASSERT(addr < 0x80000000l);
+ ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 16);
+ ins[1] = ORI | S(reg) | A(reg) | IMM(addr);
+ return;
+ }
- inst[1] = SLDI(32) | S(reg) | A(reg);
- inst[2] = ORIS | S(reg) | A(reg) | IMM((addr >> 16) & 0xffff);
- inst += 2;
+ if (flags & PATCH_ABS48) {
+ SLJIT_ASSERT(addr < 0x800000000000l);
+ ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 32);
+ ins[1] = ORI | S(reg) | A(reg) | IMM(addr >> 16);
+ ins[2] = SLDI(16) | S(reg) | A(reg);
+ ins[3] = ORI | S(reg) | A(reg) | IMM(addr);
+ return;
}
- inst[1] = ORI | S(reg) | A(reg) | IMM(addr & 0xffff);
+ ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 48);
+ ins[1] = ORI | S(reg) | A(reg) | IMM(addr >> 32);
+ ins[2] = SLDI(32) | S(reg) | A(reg);
+ ins[3] = ORIS | S(reg) | A(reg) | IMM(addr >> 16);
+ ins[4] = ORI | S(reg) | A(reg) | IMM(addr);
+#endif /* SLJIT_CONFIG_PPC_32 */
}
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_uw total_size;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+ SLJIT_NEXT_INIT_TYPES();
+
+ while (1) {
+ SLJIT_GET_NEXT_MIN();
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr == next_const_addr) {
+ const_->addr -= size_reduce;
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ continue;
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ jump->addr -= size_reduce;
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ total_size = JUMP_MAX_SIZE - 1;
+
+ if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {
+ if (jump->flags & JUMP_ADDR) {
+ if (jump->u.target <= 0x01ffffff)
+ total_size = 1 - 1;
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ else if (jump->u.target < 0x80000000l)
+ total_size = 4 - 1;
+ else if (jump->u.target < 0x800000000000l)
+ total_size = 6 - 1;
+#endif /* SLJIT_CONFIG_PPC_64 */
+ } else {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if (jump->flags & IS_COND) {
+ if (diff <= (0x7fff / SSIZE_OF(ins)) && diff >= (-0x8000 / SSIZE_OF(ins)))
+ total_size = 1 - 1;
+ else if ((diff - 1) <= (0x01ffffff / SSIZE_OF(ins)) && (diff - 1) >= (-0x02000000 / SSIZE_OF(ins)))
+ total_size = 2 - 1;
+ } else if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins)))
+ total_size = 1 - 1;
+ }
+ }
+
+ size_reduce += (JUMP_MAX_SIZE - 1) - total_size;
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ } else {
+ total_size = (sljit_uw)4 << JUMP_SIZE_SHIFT;
+
+ if (jump->flags & JUMP_ADDR) {
+ if (jump->u.target < 0x80000000l) {
+ total_size = (sljit_uw)1 << JUMP_SIZE_SHIFT;
+ size_reduce += 3;
+ } else if (jump->u.target < 0x800000000000l) {
+ total_size = (sljit_uw)3 << JUMP_SIZE_SHIFT;
+ size_reduce += 1;
+ }
+ }
+ jump->flags |= total_size;
#endif /* SLJIT_CONFIG_PPC_64 */
+ }
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_ins *code;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
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);
+
+ reduce_code_size(compiler);
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
/* add to compiler->size additional instruction space to hold the trampoline and padding */
compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
#endif
#endif
- code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+ code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
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;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
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) {
+ if (next_min_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) {
+ if (next_min_addr == next_label_size) {
/* Just recording the address. */
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (jump && jump->addr == word_count) {
-#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- jump->addr = (sljit_uw)(code_ptr - 3);
-#else
- jump->addr = (sljit_uw)(code_ptr - 6);
-#endif
- if (detect_jump_type(jump, code_ptr, code, executable_offset)) {
-#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- code_ptr[-3] = code_ptr[0];
- code_ptr -= 3;
-#else
- if (jump->flags & PATCH_ABS32) {
- code_ptr -= 3;
- code_ptr[-1] = code_ptr[2];
- code_ptr[0] = code_ptr[3];
- }
- else if (jump->flags & PATCH_ABS48) {
- code_ptr--;
- code_ptr[-1] = code_ptr[0];
- code_ptr[0] = code_ptr[1];
- /* rldicr rX,rX,32,31 -> rX,rX,16,47 */
- SLJIT_ASSERT((code_ptr[-3] & 0xfc00ffff) == 0x780007c6);
- code_ptr[-3] ^= 0x8422;
- /* oris -> ori */
- code_ptr[-2] ^= 0x4000000;
- }
- else {
- code_ptr[-6] = code_ptr[0];
- code_ptr -= 6;
- }
-#endif
- if (jump->flags & REMOVE_COND) {
- code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001);
- code_ptr++;
- jump->addr += sizeof(sljit_ins);
- code_ptr[0] = Bx;
- jump->flags -= IS_COND;
- }
+
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
+ SLJIT_ASSERT(((sljit_uw)code_ptr - jump->addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins)));
+ } else {
+ jump->addr = (sljit_uw)code_ptr;
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+ code_ptr += mov_addr_get_length(jump, code, executable_offset);
+#else /* !SLJIT_CONFIG_PPC_64 */
+ word_count++;
+ code_ptr++;
+#endif /* SLJIT_CONFIG_PPC_64 */
}
jump = jump->next;
- }
- if (const_ && const_->addr == word_count) {
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- if (put_label && put_label->addr == word_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
-#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
- word_count += 4;
-#endif
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
+
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
word_count++;
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
}
SLJIT_ASSERT(!label);
SLJIT_ASSERT(!jump);
SLJIT_ASSERT(!const_);
- SLJIT_ASSERT(!put_label);
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
SLJIT_ASSERT(code_ptr - code <= (sljit_sw)(compiler->size - (sizeof(struct sljit_function_context) / sizeof(sljit_ins))));
jump = compiler->jumps;
while (jump) {
- do {
- addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
- buf_ptr = (sljit_ins *)jump->addr;
-
- if (jump->flags & PATCH_B) {
- if (jump->flags & IS_COND) {
- if (!(jump->flags & PATCH_ABS_B)) {
- addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
- SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);
- *buf_ptr = BCx | ((sljit_ins)addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001);
- }
- else {
- SLJIT_ASSERT(addr <= 0xffff);
- *buf_ptr = BCx | ((sljit_ins)addr & 0xfffc) | 0x2 | ((*buf_ptr) & 0x03ff0001);
- }
- }
- else {
- if (!(jump->flags & PATCH_ABS_B)) {
- addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
- SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);
- *buf_ptr = Bx | ((sljit_ins)addr & 0x03fffffc) | ((*buf_ptr) & 0x1);
- }
- else {
- SLJIT_ASSERT(addr <= 0x03ffffff);
- *buf_ptr = Bx | ((sljit_ins)addr & 0x03fffffc) | 0x2 | ((*buf_ptr) & 0x1);
- }
- }
- break;
- }
-
- /* Set the fields of immediate loads. */
-#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1]) & 0xffff) == 0);
- buf_ptr[0] |= (sljit_ins)(addr >> 16) & 0xffff;
- buf_ptr[1] |= (sljit_ins)addr & 0xffff;
-#else
- if (jump->flags & PATCH_ABS32) {
- SLJIT_ASSERT(addr <= 0x7fffffff);
- SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1]) & 0xffff) == 0);
- buf_ptr[0] |= (sljit_ins)(addr >> 16) & 0xffff;
- buf_ptr[1] |= (sljit_ins)addr & 0xffff;
- break;
- }
-
- if (jump->flags & PATCH_ABS48) {
- SLJIT_ASSERT(addr <= 0x7fffffffffff);
- SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1] | buf_ptr[3]) & 0xffff) == 0);
- buf_ptr[0] |= (sljit_ins)(addr >> 32) & 0xffff;
- buf_ptr[1] |= (sljit_ins)(addr >> 16) & 0xffff;
- buf_ptr[3] |= (sljit_ins)addr & 0xffff;
- break;
- }
-
- SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1] | buf_ptr[3] | buf_ptr[4]) & 0xffff) == 0);
- buf_ptr[0] |= (sljit_ins)(addr >> 48) & 0xffff;
- buf_ptr[1] |= (sljit_ins)(addr >> 32) & 0xffff;
- buf_ptr[3] |= (sljit_ins)(addr >> 16) & 0xffff;
- buf_ptr[4] |= (sljit_ins)addr & 0xffff;
-#endif
- } while (0);
+ generate_jump_or_mov_addr(jump, executable_offset);
jump = jump->next;
}
- put_label = compiler->put_labels;
- while (put_label) {
-#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- addr = put_label->label->addr;
- buf_ptr = (sljit_ins *)put_label->addr;
-
- SLJIT_ASSERT((buf_ptr[0] & 0xfc1f0000) == ADDIS && (buf_ptr[1] & 0xfc000000) == ORI);
- buf_ptr[0] |= (addr >> 16) & 0xffff;
- buf_ptr[1] |= addr & 0xffff;
-#else
- put_label_set(put_label);
-#endif
- put_label = put_label->next;
- }
-
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins) + sizeof(struct sljit_function_context);
-
return code_ptr;
#else
compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
-
return code;
#endif
}
sljit_s32 i, tmp, base, offset;
sljit_s32 local_size = compiler->local_size;
+ SLJIT_ASSERT(TMP_CALL_REG != TMP_REG2);
+
base = SLJIT_SP;
if (local_size > STACK_MAX_DISTANCE) {
- base = TMP_REG1;
+ base = TMP_REG2;
if (local_size > 2 * STACK_MAX_DISTANCE + LR_SAVE_OFFSET) {
FAIL_IF(push_inst(compiler, STACK_LOAD | D(base) | A(SLJIT_SP) | IMM(0)));
local_size = 0;
} else {
- FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG1) | A(SLJIT_SP) | IMM(local_size - STACK_MAX_DISTANCE)));
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(SLJIT_SP) | IMM(local_size - STACK_MAX_DISTANCE)));
local_size = STACK_MAX_DISTANCE;
}
}
if (local_size > 0)
return push_inst(compiler, ADDI | D(SLJIT_SP) | A(base) | IMM(local_size));
- SLJIT_ASSERT(base == TMP_REG1);
+ SLJIT_ASSERT(base == TMP_REG2);
return push_inst(compiler, OR | S(base) | A(SLJIT_SP) | B(base));
}
sljit_s32 dst_r = TMP_REG2;
sljit_s32 src1_r;
sljit_s32 src2_r;
- sljit_s32 sugg_src2_r = TMP_REG2;
+ sljit_s32 src2_tmp_reg = (!(input_flags & ALT_SIGN_EXT) && GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2;
sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_SIGN_EXT | ALT_SET_FLAGS);
/* Destination check. */
flags |= REG_DEST;
if (op >= SLJIT_MOV && op <= SLJIT_MOV_P)
- sugg_src2_r = dst_r;
- }
-
- /* Source 1. */
- if (FAST_IS_REG(src1)) {
- src1_r = src1;
- flags |= REG1_SOURCE;
- }
- else if (src1 == SLJIT_IMM) {
- src1_r = TMP_ZERO;
- if (src1w != 0) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
- src1_r = TMP_REG1;
- }
- }
- else {
- FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
- src1_r = TMP_REG1;
+ src2_tmp_reg = dst_r;
}
/* Source 2. */
if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)
dst_r = src2_r;
- }
- else if (src2 == SLJIT_IMM) {
+ } else if (src2 == SLJIT_IMM) {
src2_r = TMP_ZERO;
if (src2w != 0) {
- FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
- src2_r = sugg_src2_r;
+ FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w));
+ src2_r = src2_tmp_reg;
}
+ } else {
+ FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, src2_tmp_reg, src2, src2w, TMP_REG1));
+ src2_r = src2_tmp_reg;
}
- else {
- FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, TMP_REG2));
- src2_r = sugg_src2_r;
+
+ /* Source 1. */
+ if (FAST_IS_REG(src1)) {
+ src1_r = src1;
+ flags |= REG1_SOURCE;
+ } else if (src1 == SLJIT_IMM) {
+ src1_r = TMP_ZERO;
+ if (src1w != 0) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+ src1_r = TMP_REG1;
+ }
+ } else {
+ FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
+ src1_r = TMP_REG1;
}
FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL) {
- if (dst == TMP_REG2) {
+ if (dst == TMP_REG1) {
if (TEST_UL_IMM(src2, src2w)) {
compiler->imm = (sljit_ins)src2w & 0xffff;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
}
- if (dst == TMP_REG2 && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+ if (dst == TMP_REG1 && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
if (TEST_SL_IMM(src2, src2w)) {
compiler->imm = (sljit_ins)src2w & 0xffff;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
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, TMP_REG1, 0, src1, src1w, src2, src2w);
}
#undef TEST_ADD_FORM1
#undef TEST_SUB_FORM2
#undef TEST_SUB_FORM3
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w));
+ return push_inst(compiler, ADD | D(dst_reg) | A(dst_reg) | B(TMP_REG2));
+ }
+
+ return SLJIT_SUCCESS;
+}
+
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,
/* Fall through. */
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src)));
else
dst_r = src;
}
if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2));
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG1));
src2 = TMP_FREG2;
}
type &= 0xff;
if ((type | 0x1) == SLJIT_NOT_CARRY)
- PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));
+ PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG2) | A(TMP_ZERO) | B(TMP_ZERO)));
/* In PPC, we don't need to touch the arguments. */
if (type < SLJIT_JUMP)
jump->flags |= IS_CALL;
#endif
- PTR_FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
- PTR_FAIL_IF(push_inst(compiler, MTCTR | S(TMP_CALL_REG)));
jump->addr = compiler->size;
PTR_FAIL_IF(push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0)));
+
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- if (FAST_IS_REG(src)) {
-#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
- if (type >= SLJIT_CALL && src != TMP_CALL_REG) {
- FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));
- src_r = TMP_CALL_REG;
- }
- else
- src_r = src;
-#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
- src_r = src;
-#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
- } else if (src == SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
/* These jumps are converted to jump/call instructions when possible. */
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
FAIL_IF(!jump);
jump->flags |= IS_CALL;
#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
- FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
- src_r = TMP_CALL_REG;
+ jump->addr = compiler->size;
+ FAIL_IF(push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0)));
+
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
+ return SLJIT_SUCCESS;
+ }
+
+ if (FAST_IS_REG(src)) {
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
+ if (type >= SLJIT_CALL && src != TMP_CALL_REG) {
+ FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));
+ src_r = TMP_CALL_REG;
+ } else
+ src_r = src;
+#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
+ src_r = src;
+#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
} else {
ADJUST_LOCAL_OFFSET(src, srcw);
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG));
}
FAIL_IF(push_inst(compiler, MTCTR | S(src_r)));
- if (jump)
- jump->addr = compiler->size;
return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0));
}
type ^= 0x1;
} else {
if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
- FAIL_IF(push_inst(compiler, OR | S(dst_reg) | A(TMP_REG2) | B(dst_reg)));
+ FAIL_IF(push_inst(compiler, OR | S(dst_reg) | A(TMP_REG1) | B(dst_reg)));
if ((src1 & REG_MASK) == dst_reg)
- src1 = (src1 & ~REG_MASK) | TMP_REG2;
+ src1 = (src1 & ~REG_MASK) | TMP_REG1;
if (OFFS_REG(src1) == dst_reg)
- src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1);
}
FAIL_IF(push_inst(compiler, OR | S(src2_reg) | A(dst_reg) | B(src2_reg)));
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
- PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
+ compiler->size++;
#else
- PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
compiler->size += 4;
#endif
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
if (jump->flags & JUMP_ADDR)
target_addr = jump->u.target;
else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+ SLJIT_ASSERT(jump->u.label != NULL);
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 >= BRANCH_MIN && diff <= BRANCH_MAX) {
- jump->flags |= PATCH_B;
+ inst--;
inst[0] = (inst[0] & 0x1fff07f) ^ 0x1000;
+ jump->flags |= PATCH_B;
jump->addr = (sljit_uw)inst;
return inst;
}
- inst++;
diff -= SSIZE_OF(ins);
}
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
{
- if (max_label <= (sljit_uw)S32_MAX) {
- put_label->flags = PATCH_ABS32;
+ sljit_uw addr;
+ sljit_sw diff;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ SLJIT_ASSERT(jump->flags < ((sljit_uw)6 << JUMP_SIZE_SHIFT));
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);
+
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ if (diff >= S32_MIN && diff <= S32_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_REL32;
+ return 1;
+ }
+
+ if (addr <= S32_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS32;
return 1;
}
- if (max_label <= S44_MAX) {
- put_label->flags = PATCH_ABS44;
+ if (addr <= S44_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS44;
return 3;
}
- if (max_label <= S52_MAX) {
- put_label->flags = PATCH_ABS52;
+ if (addr <= S52_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)4 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS52;
return 4;
}
- put_label->flags = 0;
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)5 << JUMP_SIZE_SHIFT));
return 5;
}
#endif /* SLJIT_CONFIG_RISCV_64 */
-static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
+static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump, sljit_sw executable_offset)
{
- struct sljit_jump *jump = NULL;
- struct sljit_put_label *put_label;
- sljit_uw flags;
- sljit_ins *inst;
+ sljit_uw flags = jump->flags;
+ sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
+ sljit_ins *ins = (sljit_ins*)jump->addr;
+ sljit_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : TMP_REG1;
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
sljit_sw high;
#endif
- sljit_uw addr;
+ SLJIT_UNUSED_ARG(executable_offset);
- 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;
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- flags = put_label->flags;
-#endif
- inst = (sljit_ins*)put_label->addr;
- addr = put_label->label->addr;
- reg = *inst;
+ if (flags & PATCH_REL32) {
+ addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset);
+
+ SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX);
+
+ if ((addr & 0x800) != 0)
+ addr += 0x1000;
+
+ ins[0] = AUIPC | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
+
+ if (!(flags & JUMP_MOV_ADDR)) {
+ SLJIT_ASSERT((ins[1] & 0x707f) == JALR);
+ ins[1] = (ins[1] & 0xfffff) | IMM_I(addr);
+ } else
+ ins[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr);
+ return;
}
+#endif
if ((addr & 0x800) != 0)
addr += 0x1000;
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
- inst[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
+ ins[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
#else /* !SLJIT_CONFIG_RISCV_32 */
if (flags & PATCH_ABS32) {
SLJIT_ASSERT(addr <= S32_MAX);
- inst[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
+ ins[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
} else if (flags & PATCH_ABS44) {
high = (sljit_sw)addr >> 12;
SLJIT_ASSERT((sljit_uw)high <= 0x7fffffff);
if (high > S32_MAX) {
SLJIT_ASSERT((high & 0x800) != 0);
- inst[0] = LUI | RD(reg) | (sljit_ins)0x80000000u;
- inst[1] = XORI | RD(reg) | RS1(reg) | IMM_I(high);
+ ins[0] = LUI | RD(reg) | (sljit_ins)0x80000000u;
+ ins[1] = XORI | RD(reg) | RS1(reg) | IMM_I(high);
} else {
if ((high & 0x800) != 0)
high += 0x1000;
- inst[0] = LUI | RD(reg) | (sljit_ins)(high & ~0xfff);
- inst[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(high);
+ ins[0] = LUI | RD(reg) | (sljit_ins)(high & ~0xfff);
+ ins[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(high);
}
- inst[2] = SLLI | RD(reg) | RS1(reg) | IMM_I(12);
- inst += 2;
+ ins[2] = SLLI | RD(reg) | RS1(reg) | IMM_I(12);
+ ins += 2;
} else {
high = (sljit_sw)addr >> 32;
if (flags & PATCH_ABS52) {
SLJIT_ASSERT(addr <= S52_MAX);
- inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high << 12);
+ ins[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++;
+ ins[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff);
+ ins[1] = ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high);
+ ins++;
}
- inst[1] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
- inst[2] = SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I((flags & PATCH_ABS52) ? 20 : 32);
- inst[3] = XOR | RD(reg) | RS1(reg) | RS2(TMP_REG3);
- inst += 3;
+ ins[1] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff);
+ ins[2] = SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I((flags & PATCH_ABS52) ? 20 : 32);
+ ins[3] = XOR | RD(reg) | RS1(reg) | RS2(TMP_REG3);
+ ins += 3;
}
#endif /* !SLJIT_CONFIG_RISCV_32 */
- if (jump != NULL) {
- SLJIT_ASSERT((inst[1] & 0x707f) == JALR);
- inst[1] = (inst[1] & 0xfffff) | IMM_I(addr);
+ if (!(flags & JUMP_MOV_ADDR)) {
+ SLJIT_ASSERT((ins[1] & 0x707f) == JALR);
+ ins[1] = (ins[1] & 0xfffff) | IMM_I(addr);
} else
- inst[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr);
+ ins[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr);
+}
+
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_uw total_size;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+ SLJIT_NEXT_INIT_TYPES();
+
+ while (1) {
+ SLJIT_GET_NEXT_MIN();
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr == next_const_addr) {
+ const_->addr -= size_reduce;
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ continue;
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ jump->addr -= size_reduce;
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ total_size = JUMP_MAX_SIZE;
+
+ if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {
+ if (jump->flags & JUMP_ADDR) {
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ if (jump->u.target <= S32_MAX)
+ total_size = 2;
+ else if (jump->u.target <= S44_MAX)
+ total_size = 4;
+ else if (jump->u.target <= S52_MAX)
+ total_size = 5;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+ } else {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if ((jump->flags & IS_COND) && (diff + 1) <= (BRANCH_MAX / SSIZE_OF(ins)) && (diff + 1) >= (BRANCH_MIN / SSIZE_OF(ins)))
+ total_size = 0;
+ else if (diff >= (JUMP_MIN / SSIZE_OF(ins)) && diff <= (JUMP_MAX / SSIZE_OF(ins)))
+ total_size = 1;
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ else if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins)))
+ total_size = 2;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+ }
+ }
+
+ size_reduce += JUMP_MAX_SIZE - total_size;
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ } else {
+ total_size = 5;
+
+ if (!(jump->flags & JUMP_ADDR)) {
+ /* Real size minus 1. Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;
+
+ if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins)))
+ total_size = 1;
+ } else if (jump->u.target < S32_MAX)
+ total_size = 1;
+ else if (jump->u.target < S44_MAX)
+ total_size = 3;
+ else if (jump->u.target <= S52_MAX)
+ total_size = 4;
+
+ size_reduce += 5 - total_size;
+ jump->flags |= total_size << JUMP_SIZE_SHIFT;
+#endif /* !SLJIT_CONFIG_RISCV_64 */
+ }
+
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_ins *code;
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_uw next_addr;
+ SLJIT_NEXT_DEFINE_TYPES;
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);
+ reduce_code_size(compiler);
+
+ code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
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;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
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) {
+ if (next_min_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);
+ if (next_min_addr == next_label_size) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
}
- if (jump && jump->addr == word_count) {
+
+ if (next_min_addr == next_jump_addr) {
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+ word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT);
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr = detect_jump_type(jump, code, executable_offset);
+ SLJIT_ASSERT((jump->flags & PATCH_B) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins)));
+ } else {
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
- word_count += 1;
-#else
- word_count += 5;
-#endif
- jump->addr = (sljit_uw)code_ptr;
- code_ptr = detect_jump_type(jump, code, executable_offset);
+ word_count += 1;
+ jump->addr = (sljit_uw)code_ptr;
+ code_ptr += 1;
+#else /* !SLJIT_CONFIG_RISCV_32 */
+ word_count += jump->flags >> JUMP_SIZE_SHIFT;
+ addr = (sljit_uw)code_ptr;
+ code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset);
+ jump->addr = addr;
+#endif /* SLJIT_CONFIG_RISCV_32 */
+ }
jump = jump->next;
- }
- if (const_ && const_->addr == word_count) {
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
const_->addr = (sljit_uw)code_ptr;
const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
}
- if (put_label && put_label->addr == word_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
-#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
- code_ptr += 1;
- word_count += 1;
-#else
- code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
- word_count += 5;
-#endif
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
+
+ SLJIT_GET_NEXT_MIN();
}
code_ptr++;
word_count++;
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)code_ptr;
+ label->u.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);
+ if (!(jump->flags & (PATCH_B | PATCH_J)) || (jump->flags & JUMP_MOV_ADDR)) {
+ load_addr_to_reg(jump, executable_offset);
break;
}
- addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+ addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
buf_ptr = (sljit_ins *)jump->addr;
addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
break;
}
-#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- if (jump->flags & PATCH_REL32) {
- SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX);
-
- if ((addr & 0x800) != 0)
- addr += 0x1000;
-
- buf_ptr[0] = AUIPC | RD(TMP_REG1) | (sljit_ins)((sljit_sw)addr & ~0xfff);
- SLJIT_ASSERT((buf_ptr[1] & 0x707f) == JALR);
- buf_ptr[1] |= IMM_I(addr);
- break;
- }
-#endif
-
SLJIT_ASSERT((sljit_sw)addr >= JUMP_MIN && (sljit_sw)addr <= JUMP_MAX);
addr = (addr & 0xff000) | ((addr & 0x800) << 9) | ((addr & 0x7fe) << 20) | ((addr & 0x100000) << 11);
buf_ptr[0] = JAL | RD((jump->flags & IS_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | (sljit_ins)addr;
} 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;
+ jump = jump->next;
}
compiler->error = SLJIT_ERR_COMPILED;
#define SLOW_SRC1 0x08000
#define SLOW_SRC2 0x10000
#define SLOW_DEST 0x20000
+#define MEM_USE_TMP2 0x40000
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
#define STACK_STORE SW
/* 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);
if (!(arg & OFFS_REG_MASK) && argw <= SIMM_MAX && argw >= SIMM_MIN) {
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_s32 tmp_r = (flags & MEM_USE_TMP2) ? TMP_REG2 : TMP_REG1;
sljit_sw offset, argw_hi;
SLJIT_ASSERT(arg & SLJIT_MEM);
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) && reg == TMP_REG2)
- tmp_r = reg;
-
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
argw &= 0x3;
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_s32 is_overflow, is_carry, carry_src_r, is_handled, reg;
sljit_ins op_imm, op_reg;
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, ADDI | RD(dst) | RS1(src2) | IMM_I(0));
return SLJIT_SUCCESS;
case SLJIT_MOV_U8:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
return push_inst(compiler, ANDI | RD(dst) | RS1(src2) | IMM_I(0xff));
SLJIT_ASSERT(dst == src2);
return SLJIT_SUCCESS;
case SLJIT_MOV_S8:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src2) | IMM_EXTEND(24)));
return push_inst(compiler, SRAI | WORD | RD(dst) | RS1(dst) | IMM_EXTEND(24));
return SLJIT_SUCCESS;
case SLJIT_MOV_U16:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src2) | IMM_EXTEND(16)));
return push_inst(compiler, SRLI | WORD | RD(dst) | RS1(dst) | IMM_EXTEND(16));
return SLJIT_SUCCESS;
case SLJIT_MOV_S16:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src2) | IMM_EXTEND(16)));
return push_inst(compiler, SRAI | WORD | RD(dst) | RS1(dst) | IMM_EXTEND(16));
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
case SLJIT_MOV_U32:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(src2) | IMM_I(32)));
return push_inst(compiler, SRLI | RD(dst) | RS1(dst) | IMM_I(32));
return SLJIT_SUCCESS;
case SLJIT_MOV_S32:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE))
return push_inst(compiler, ADDI | 0x8 | RD(dst) | RS1(src2) | IMM_I(0));
SLJIT_ASSERT(dst == src2);
case SLJIT_CLZ:
case SLJIT_CTZ:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM));
return emit_clz_ctz(compiler, op, dst, src2);
case SLJIT_REV:
#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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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));
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(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);
+ SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM) && dst != TMP_REG1);
FAIL_IF(emit_rev(compiler, op, dst, src2));
if (dst == TMP_REG2)
return SLJIT_SUCCESS;
is_handled = 1;
if (flags & SRC2_IMM) {
- FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(TMP_ZERO) | IMM_I(src2)));
- src2 = TMP_REG2;
+ reg = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+ FAIL_IF(push_inst(compiler, ADDI | RD(reg) | RS1(TMP_ZERO) | IMM_I(src2)));
+ src2 = reg;
flags &= ~SRC2_IMM;
}
sljit_s32 dst_r = TMP_REG2;
sljit_s32 src1_r;
sljit_sw src2_r = 0;
- sljit_s32 sugg_src2_r = TMP_REG2;
+ sljit_s32 src2_tmp_reg = (GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
dst_r = dst;
flags |= REG_DEST;
if (flags & MOVE_OP)
- sugg_src2_r = dst_r;
+ src2_tmp_reg = dst_r;
}
else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
flags |= SLOW_DEST;
if (FAST_IS_REG(src1)) {
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;
}
else
src1_r = TMP_ZERO;
- }
- else {
+ } else {
if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w))
FAIL_IF(compiler->error);
else
flags |= REG2_SOURCE;
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));
- src2_r = sugg_src2_r;
- }
- else {
+ FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w, TMP_REG3));
+ src2_r = src2_tmp_reg;
+ } else {
src2_r = TMP_ZERO;
if (flags & MOVE_OP) {
if (dst & SLJIT_MEM)
}
}
}
- }
- else {
- if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w))
+ } else {
+ if (getput_arg_fast(compiler, flags | LOAD_DATA, src2_tmp_reg, src2, src2w))
FAIL_IF(compiler->error);
else
flags |= SLOW_SRC2;
- src2_r = sugg_src2_r;
+ src2_r = src2_tmp_reg;
}
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)) {
+ if ((flags & SLOW_DEST) && !can_cache(src2, src2w, src1, src1w) && can_cache(src2, src2w, dst, dstw)) {
+ FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
+ FAIL_IF(getput_arg(compiler, flags | LOAD_DATA | MEM_USE_TMP2, TMP_REG2, src2, src2w, dst, dstw));
+ } else {
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(getput_arg(compiler, flags | LOAD_DATA | ((src1_r == TMP_REG1) ? MEM_USE_TMP2 : 0), src2_tmp_reg, src2, src2w, dst, dstw));
FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
case SLJIT_MOV32:
#endif
case SLJIT_MOV_P:
- return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, srcw);
#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_ZERO, 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_ZERO, 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_ZERO, 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_ZERO, 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_ZERO, 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);
+ return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, op, flags, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_ZERO, 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);
+ return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_ZERO, 0, src, srcw);
}
SLJIT_UNREACHABLE();
return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w));
+ return push_inst(compiler, ADD | WORD | RD(dst_reg) | RS1(dst_reg) | RS2(TMP_REG2));
+ }
+
+ return SLJIT_SUCCESS;
+}
+
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,
switch (GET_OPCODE(op)) {
case SLJIT_MOV_F64:
if (src != dst_r) {
- if (dst_r != TMP_FREG1)
+ if (!(dst & SLJIT_MEM))
FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src) | FRS2(src)));
else
dst_r = src;
}
if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+ if ((dst & SLJIT_MEM) && !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 {
+ } 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));
}
return push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2));
}
- if (dst_r == TMP_FREG2)
+ if (dst_r != dst)
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
return SLJIT_SUCCESS;
PTR_FAIL_IF(push_inst(compiler, inst));
/* Maximum number of instructions required for generating a constant. */
-#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
- compiler->size += 1;
-#else
- compiler->size += 5;
-#endif
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
struct sljit_jump *jump;
sljit_s32 flags;
sljit_ins inst;
+ sljit_s32 src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
}
if (src2 & SLJIT_MEM) {
- PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG2, src2, src2w, 0, 0));
- src2 = TMP_REG2;
+ PTR_FAIL_IF(emit_op_mem2(compiler, flags, src2_tmp_reg, src2, src2w, 0, 0));
+ src2 = src2_tmp_reg;
}
if (src1 == SLJIT_IMM) {
if (src2 == SLJIT_IMM) {
if (src2w != 0) {
- PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w, TMP_REG3));
- src2 = TMP_REG2;
+ PTR_FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w, TMP_REG3));
+ src2 = src2_tmp_reg;
}
else
src2 = TMP_ZERO;
PTR_FAIL_IF(push_inst(compiler, JALR | RD(TMP_ZERO) | RS1(TMP_REG1) | IMM_I(0)));
/* Maximum number of instructions required for generating a constant. */
-#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
- compiler->size += 1;
-#else
- compiler->size += 5;
-#endif
+ compiler->size += JUMP_MAX_SIZE - 1;
return jump;
}
FAIL_IF(push_inst(compiler, JALR | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RS1(TMP_REG1) | IMM_I(0)));
/* Maximum number of instructions required for generating a constant. */
-#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
- compiler->size += 1;
-#else
- compiler->size += 5;
-#endif
+ compiler->size += JUMP_MAX_SIZE - 1;
return SLJIT_SUCCESS;
}
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)));
+ FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(dst_reg) | IMM_I(0)));
if ((src1 & REG_MASK) == dst_reg)
- src1 = (src1 & ~REG_MASK) | TMP_REG2;
+ src1 = (src1 & ~REG_MASK) | TMP_REG1;
if (OFFS_REG(src1) == dst_reg)
- src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1);
}
FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src2_reg) | IMM_I(0)));
} 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);
+ size = compiler->size - size;
+ *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((size & 0x7) << 9) | (sljit_ins)((size >> 3) << 25);
return SLJIT_SUCCESS;
}
else
FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(type) | FRD(dst_freg) | FRS1(src1) | FRS2(src1)));
- *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9);
+ size = compiler->size - size;
+ *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((size & 0x7) << 9) | (sljit_ins)((size >> 3) << 25);
return SLJIT_SUCCESS;
}
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_s32 dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
compiler->size += 1;
-#else
+#else /* !SLJIT_CONFIG_RISCV_32 */
compiler->size += 5;
-#endif
+#endif /* SLJIT_CONFIG_RISCV_32 */
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
return "s390x" SLJIT_CPUINFO;
}
-/* Instructions. */
+/* Instructions are stored as 64 bit values regardless their size. */
typedef sljit_uw sljit_ins;
-/* Instruction tags (most significant halfword). */
-static const sljit_ins sljit_ins_const = (sljit_ins)1 << 48;
-
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
return reg_map[r];
}
-/* Size of instruction in bytes. Tags must already be cleared. */
-static SLJIT_INLINE sljit_uw sizeof_ins(sljit_ins ins)
-{
- /* keep faulting instructions */
- if (ins == 0)
- return 2;
-
- if ((ins & 0x00000000ffffL) == ins)
- return 2;
- if ((ins & 0x0000ffffffffL) == ins)
- return 4;
- if ((ins & 0xffffffffffffL) == ins)
- return 6;
-
- SLJIT_UNREACHABLE();
- return (sljit_uw)-1;
-}
-
static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
sljit_ins *ibuf = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ibuf);
*ibuf = ins;
+
+ SLJIT_ASSERT(ins <= 0xffffffffffffL);
+
compiler->size++;
- return SLJIT_SUCCESS;
-}
+ if (ins & 0xffff00000000L)
+ compiler->size++;
-static sljit_s32 encode_inst(void **ptr, sljit_ins ins)
-{
- sljit_u16 *ibuf = (sljit_u16 *)*ptr;
- sljit_uw size = sizeof_ins(ins);
+ if (ins & 0xffffffff0000L)
+ compiler->size++;
- SLJIT_ASSERT((size & 6) == size);
- switch (size) {
- case 6:
- *ibuf++ = (sljit_u16)(ins >> 32);
- /* fallthrough */
- case 4:
- *ibuf++ = (sljit_u16)(ins >> 16);
- /* fallthrough */
- case 2:
- *ibuf++ = (sljit_u16)(ins);
- }
- *ptr = (void*)ibuf;
return SLJIT_SUCCESS;
}
return emit_rrf(compiler, ins, dst, src1, src1w, src2, src2w);
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_label *label;
struct sljit_jump *jump;
- struct sljit_s390x_const *const_;
- struct sljit_put_label *put_label;
+ struct sljit_const *const_;
sljit_sw executable_offset;
- sljit_uw ins_size = 0; /* instructions */
+ sljit_uw ins_size = compiler->size << 1;
sljit_uw pool_size = 0; /* literal pool */
sljit_uw pad_size;
- sljit_uw i, j = 0;
+ sljit_uw half_count;
+ SLJIT_NEXT_DEFINE_TYPES;
struct sljit_memory_fragment *buf;
- void *code, *code_ptr;
+ sljit_ins *buf_ptr;
+ sljit_ins *buf_end;
+ sljit_u16 *code;
+ sljit_u16 *code_ptr;
sljit_uw *pool, *pool_ptr;
- sljit_sw source, offset; /* TODO(carenas): only need 32 bit */
+ sljit_ins ins;
+ sljit_sw source, offset;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_generate_code(compiler));
reverse_buf(compiler);
- /* branch handling */
- label = compiler->labels;
jump = compiler->jumps;
- put_label = compiler->put_labels;
-
- /* TODO(carenas): compiler->executable_size could be calculated
- * before to avoid the following loop (except for
- * pool_size)
- */
- /* calculate the size of the code */
- for (buf = compiler->buf; buf != NULL; buf = buf->next) {
- sljit_uw len = buf->used_size / sizeof(sljit_ins);
- sljit_ins *ibuf = (sljit_ins *)buf->memory;
- for (i = 0; i < len; ++i, ++j) {
- sljit_ins ins = ibuf[i];
-
- /* TODO(carenas): instruction tag vs size/addr == j
- * using instruction tags for const is creative
- * but unlike all other architectures, and is not
- * done consistently for all other objects.
- * This might need reviewing later.
- */
- if (ins & sljit_ins_const) {
- pool_size += sizeof(*pool);
- ins &= ~sljit_ins_const;
- }
- if (label && label->size == j) {
- label->size = ins_size;
- label = label->next;
- }
- if (jump && jump->addr == j) {
- if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) {
- /* encoded: */
- /* brasl %r14, <rel_addr> (or brcl <mask>, <rel_addr>) */
- /* replace with: */
- /* lgrl %r1, <pool_addr> */
- /* bras %r14, %r1 (or bcr <mask>, %r1) */
- pool_size += sizeof(*pool);
- ins_size += 2;
- }
- jump = jump->next;
- }
- if (put_label && put_label->addr == j) {
- pool_size += sizeof(*pool);
- put_label = put_label->next;
- }
- ins_size += sizeof_ins(ins);
+ while (jump != NULL) {
+ if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR | JUMP_MOV_ADDR)) {
+ /* encoded: */
+ /* brasl %r14, <rel_addr> (or brcl <mask>, <rel_addr>) */
+ /* replace with: */
+ /* lgrl %r1, <pool_addr> */
+ /* bras %r14, %r1 (or bcr <mask>, %r1) */
+ pool_size += sizeof(*pool);
+ if (!(jump->flags & JUMP_MOV_ADDR))
+ ins_size += 2;
}
+ jump = jump->next;
}
- /* emit trailing label */
- if (label && label->size == j) {
- label->size = ins_size;
- label = label->next;
+ const_ = compiler->consts;
+ while (const_) {
+ pool_size += sizeof(*pool);
+ const_ = const_->next;
}
- SLJIT_ASSERT(!label);
- SLJIT_ASSERT(!jump);
- SLJIT_ASSERT(!put_label);
-
/* pad code size to 8 bytes so is accessible with half word offsets */
/* the literal pool needs to be doubleword aligned */
pad_size = ((ins_size + 7UL) & ~7UL) - ins_size;
SLJIT_ASSERT(pad_size < 8UL);
/* allocate target buffer */
- code = SLJIT_MALLOC_EXEC(ins_size + pad_size + pool_size,
- compiler->exec_allocator_data);
+ code = (sljit_u16*)allocate_executable_memory(ins_size + pad_size + pool_size, options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
code_ptr = code;
- executable_offset = SLJIT_EXEC_OFFSET(code);
/* TODO(carenas): pool is optional, and the ABI recommends it to
* be created before the function code, instead of
*/
pool = (sljit_uw *)((sljit_uw)code + ins_size + pad_size);
pool_ptr = pool;
- const_ = (struct sljit_s390x_const *)compiler->consts;
+ buf = compiler->buf;
+ half_count = 0;
- /* update label addresses */
label = compiler->labels;
- while (label) {
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(
- (sljit_uw)code_ptr + label->size, executable_offset);
- label = label->next;
- }
-
- /* reset jumps */
jump = compiler->jumps;
- put_label = compiler->put_labels;
+ const_ = compiler->consts;
+ SLJIT_NEXT_INIT_TYPES();
+ SLJIT_GET_NEXT_MIN();
- /* emit the code */
- j = 0;
- for (buf = compiler->buf; buf != NULL; buf = buf->next) {
- sljit_uw len = buf->used_size / sizeof(sljit_ins);
- sljit_ins *ibuf = (sljit_ins *)buf->memory;
- for (i = 0; i < len; ++i, ++j) {
- sljit_ins ins = ibuf[i];
- if (ins & sljit_ins_const) {
- /* clear the const tag */
- ins &= ~sljit_ins_const;
+ do {
+ buf_ptr = (sljit_ins*)buf->memory;
+ buf_end = buf_ptr + (buf->used_size >> 3);
+ do {
+ ins = *buf_ptr++;
+
+ if (next_min_addr == half_count) {
+ SLJIT_ASSERT(!label || label->size >= half_count);
+ SLJIT_ASSERT(!jump || jump->addr >= half_count);
+ SLJIT_ASSERT(!const_ || const_->addr >= half_count);
+
+ if (next_min_addr == next_label_size) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
- /* update instruction with relative address of constant */
- source = (sljit_sw)code_ptr;
- offset = (sljit_sw)pool_ptr - source;
+ if (next_min_addr == next_jump_addr) {
+ if (SLJIT_UNLIKELY(jump->flags & JUMP_MOV_ADDR)) {
+ source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ jump->addr = (sljit_uw)pool_ptr;
+
+ /* store target into pool */
+ offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
+ pool_ptr++;
+
+ SLJIT_ASSERT(!(offset & 1));
+ offset >>= 1;
+ SLJIT_ASSERT(is_s32(offset));
+ ins |= (sljit_ins)offset & 0xffffffff;
+ } else if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR)) {
+ sljit_ins arg;
+
+ jump->addr = (sljit_uw)pool_ptr;
+
+ /* load address into tmp1 */
+ source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
+
+ SLJIT_ASSERT(!(offset & 1));
+ offset >>= 1;
+ SLJIT_ASSERT(is_s32(offset));
+
+ code_ptr[0] = (sljit_u16)(0xc408 | R4A(tmp1) /* lgrl */);
+ code_ptr[1] = (sljit_u16)(offset >> 16);
+ code_ptr[2] = (sljit_u16)offset;
+ code_ptr += 3;
+ pool_ptr++;
+
+ /* branch to tmp1 */
+ arg = (ins >> 36) & 0xf;
+ if (((ins >> 32) & 0xf) == 4) {
+ /* brcl -> bcr */
+ ins = bcr(arg, tmp1);
+ } else {
+ SLJIT_ASSERT(((ins >> 32) & 0xf) == 5);
+ /* brasl -> basr */
+ ins = basr(arg, tmp1);
+ }
+
+ /* Adjust half_count. */
+ half_count += 2;
+ } else
+ jump->addr = (sljit_uw)code_ptr;
+
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ } else if (next_min_addr == next_const_addr) {
+ /* update instruction with relative address of constant */
+ source = (sljit_sw)code_ptr;
+ offset = (sljit_sw)pool_ptr - source;
+
+ SLJIT_ASSERT(!(offset & 0x1));
+ offset >>= 1; /* halfword (not byte) offset */
+ SLJIT_ASSERT(is_s32(offset));
- SLJIT_ASSERT(!(offset & 1));
- offset >>= 1; /* halfword (not byte) offset */
- SLJIT_ASSERT(is_s32(offset));
+ ins |= (sljit_ins)offset & 0xffffffff;
- ins |= (sljit_ins)offset & 0xffffffff;
+ /* update address */
+ const_->addr = (sljit_uw)pool_ptr;
- /* update address */
- const_->const_.addr = (sljit_uw)pool_ptr;
+ /* store initial value into pool and update pool address */
+ *(pool_ptr++) = (sljit_uw)(((struct sljit_s390x_const*)const_)->init_value);
- /* store initial value into pool and update pool address */
- *(pool_ptr++) = (sljit_uw)const_->init_value;
+ /* move to next constant */
+ const_ = const_->next;
+ next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
+ }
- /* move to next constant */
- const_ = (struct sljit_s390x_const *)const_->const_.next;
+ SLJIT_GET_NEXT_MIN();
}
- if (jump && jump->addr == j) {
- sljit_sw target = (sljit_sw)((jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
- if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) {
- sljit_ins op, arg;
- jump->addr = (sljit_uw)pool_ptr;
+ if (ins & 0xffff00000000L) {
+ *code_ptr++ = (sljit_u16)(ins >> 32);
+ half_count++;
+ }
- /* load address into tmp1 */
- source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
- offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
+ if (ins & 0xffffffff0000L) {
+ *code_ptr++ = (sljit_u16)(ins >> 16);
+ half_count++;
+ }
- SLJIT_ASSERT(!(offset & 1));
- offset >>= 1;
- SLJIT_ASSERT(is_s32(offset));
+ *code_ptr++ = (sljit_u16)ins;
+ half_count++;
+ } while (buf_ptr < buf_end);
- encode_inst(&code_ptr, lgrl(tmp1, offset & 0xffffffff));
-
- /* store jump target into pool and update pool address */
- *(pool_ptr++) = (sljit_uw)target;
-
- /* branch to tmp1 */
- op = (ins >> 32) & 0xf;
- arg = (ins >> 36) & 0xf;
- switch (op) {
- case 4: /* brcl -> bcr */
- ins = bcr(arg, tmp1);
- break;
- case 5: /* brasl -> basr */
- ins = basr(arg, tmp1);
- break;
- default:
- abort();
- }
- }
- else {
- jump->addr = (sljit_uw)code_ptr + 2;
- source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
- offset = target - source;
+ buf = buf->next;
+ } while (buf);
- /* offset must be halfword aligned */
- SLJIT_ASSERT(!(offset & 1));
- offset >>= 1;
- SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */
+ if (next_label_size == half_count) {
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ label = label->next;
+ }
- /* patch jump target */
- ins |= (sljit_ins)offset & 0xffffffff;
- }
- jump = jump->next;
- }
- if (put_label && put_label->addr == j) {
- source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ SLJIT_ASSERT(!label);
+ SLJIT_ASSERT(!jump);
+ SLJIT_ASSERT(!const_);
+ SLJIT_ASSERT(code + (ins_size >> 1) == code_ptr);
+ SLJIT_ASSERT((sljit_u8 *)pool + pool_size == (sljit_u8 *)pool_ptr);
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
+ jump = compiler->jumps;
+ while (jump != NULL) {
+ offset = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr);
- /* store target into pool */
- *pool_ptr = put_label->label->addr;
- offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
- pool_ptr++;
+ if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR | JUMP_MOV_ADDR)) {
+ /* Store jump target into pool. */
+ *(sljit_uw*)(jump->addr) = (sljit_uw)offset;
+ } else {
+ code_ptr = (sljit_u16*)jump->addr;
+ offset -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
- SLJIT_ASSERT(!(offset & 1));
- offset >>= 1;
- SLJIT_ASSERT(is_s32(offset));
- ins |= (sljit_ins)offset & 0xffffffff;
+ /* offset must be halfword aligned */
+ SLJIT_ASSERT(!(offset & 1));
+ offset >>= 1;
+ SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */
- put_label = put_label->next;
- }
- encode_inst(&code_ptr, ins);
+ code_ptr[1] = (sljit_u16)(offset >> 16);
+ code_ptr[2] = (sljit_u16)offset;
}
+ jump = jump->next;
}
- SLJIT_ASSERT((sljit_u8 *)code + ins_size == code_ptr);
- SLJIT_ASSERT((sljit_u8 *)pool + pool_size == (sljit_u8 *)pool_ptr);
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
compiler->executable_size = ins_size;
if (pool_size)
compiler->executable_size += (pad_size + pool_size);
- code = SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
- code_ptr = SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ code = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+ code_ptr = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
SLJIT_CACHE_FLUSH(code, code_ptr);
SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
return code;
const struct ins_forms *forms;
sljit_ins ins;
- if (dst == (sljit_s32)tmp0 && flag_type <= SLJIT_SIG_LESS_EQUAL) {
+ if (dst == TMP_REG2 && flag_type <= SLJIT_SIG_LESS_EQUAL) {
int compare_signed = flag_type >= SLJIT_SIG_LESS;
compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_COMPARE;
- the first operand is less if the sign bit of the result is not set
The -result operation sets the corrent sign, because the result cannot be zero.
The overflow is considered greater, since the result must be equal to INT_MIN so its sign bit is set. */
- FAIL_IF(push_inst(compiler, brc(0xe, 2 + 2)));
+ FAIL_IF(push_inst(compiler, brc(0xe, (op & SLJIT_32) ? (2 + 1) : (2 + 2))));
FAIL_IF(push_inst(compiler, (op & SLJIT_32) ? lcr(tmp1, dst_r) : lcgr(tmp1, dst_r)));
}
else if (op & SLJIT_SET_Z)
sljit_s32 type = GET_OPCODE(op);
const struct ins_forms *forms;
- if (src2 == SLJIT_IMM && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == (sljit_s32)tmp0))) {
+ if (src2 == SLJIT_IMM && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == TMP_REG2))) {
sljit_s32 count16 = 0;
sljit_uw imm = (sljit_uw)src2w;
if ((imm & 0xffff000000000000ull) != 0)
count16++;
- if (type == SLJIT_AND && dst == (sljit_s32)tmp0 && count16 == 1) {
- sljit_gpr src_r = tmp0;
+ if (type == SLJIT_AND && dst == TMP_REG2 && count16 == 1) {
+ sljit_gpr src_r = tmp1;
if (FAST_IS_REG(src1))
src_r = gpr(src1 & REG_MASK);
else
- FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
+ FAIL_IF(emit_move(compiler, tmp1, src1, src1w));
if ((imm & 0x000000000000ffffull) != 0 || imm == 0)
return push_inst(compiler, 0xa7010000 /* tmll */ | R20A(src_r) | imm);
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
+ sljit_s32 dst_reg = (GET_OPCODE(op) == SLJIT_SUB || GET_OPCODE(op) == SLJIT_AND) ? TMP_REG2 : TMP_REG1;
+
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, (sljit_s32)tmp0, 0, src1, src1w, src2, src2w);
+ return sljit_emit_op2(compiler, op, dst_reg, 0, src1, src1w, src2, src2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ SLJIT_SKIP_CHECKS(compiler);
+ FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), 0 /* tmp0 */, 0, src1, src1w, src2, src2w));
+ return push_inst(compiler, ((op & SLJIT_32) ? 0x1a00 /* ar */ : 0xb9080000 /* agr */) | R4A(gpr(dst_reg)) | R0A(tmp0));
+ }
+
+ return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
FAIL_IF(push_inst(compiler, ins | F4(dst_r) | F0(src)));
}
- if (!(dst & SLJIT_MEM))
- return SLJIT_SUCCESS;
-
- SLJIT_ASSERT(dst_r == TMP_FREG1);
+ if (dst & SLJIT_MEM)
+ return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw);
- return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw);
+ return SLJIT_SUCCESS;
}
#define FLOAT_MOV(op, dst_r, src_r) \
if (dst & SLJIT_MEM)
return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw);
- SLJIT_ASSERT(dst_r != TMP_FREG1);
return SLJIT_SUCCESS;
}
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_32, lochi, locghi)));
} else {
- /* TODO(mundaym): no load/store-on-condition 2 facility (ipm? branch-and-set?) */
- abort();
+ FAIL_IF(push_load_imm_inst(compiler, loc_r, 1));
+ FAIL_IF(push_inst(compiler, brc(mask, 2 + 2)));
+ FAIL_IF(push_load_imm_inst(compiler, loc_r, 0));
}
#undef LEVAL
return push_inst(compiler, ins | R36A(dst_r) | (mask << 32) | (sljit_ins)(src1w & 0xffff) << 16);
}
- FAIL_IF(push_load_imm_inst(compiler, tmp0, src1w));
- src_r = tmp0;
+ FAIL_IF(push_load_imm_inst(compiler, tmp1, src1w));
+ src_r = tmp1;
} else
src_r = gpr(src1);
dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
if (have_genext())
- PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | lgrl(dst_r, 0)));
+ PTR_FAIL_IF(push_inst(compiler, lgrl(dst_r, 0)));
else {
- PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | larl(tmp1, 0)));
+ PTR_FAIL_IF(push_inst(compiler, larl(tmp1, 0)));
PTR_FAIL_IF(push_inst(compiler, lg(dst_r, 0, r0, tmp1)));
}
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label *sljit_emit_put_label(
- struct sljit_compiler *compiler,
- sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_gpr dst_r;
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
if (dst & SLJIT_MEM)
PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0));
- return put_label;
+ return jump;
}
/* TODO(carenas): EVAL probably should move up or be refactored */
/* Enter / return */
/* --------------------------------------------------------------------- */
-static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset)
+static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset)
{
sljit_uw type = jump->flags >> TYPE_SHIFT;
if (type == SLJIT_JUMP) {
*code_ptr++ = JMP_i32;
- jump->addr++;
- }
- else if (type >= SLJIT_FAST_CALL) {
+ } else if (type >= SLJIT_FAST_CALL) {
*code_ptr++ = CALL_i32;
- jump->addr++;
- }
- else {
+ } else {
*code_ptr++ = GROUP_0F;
*code_ptr++ = get_jump_code(type);
- jump->addr += 2;
}
- if (jump->flags & JUMP_LABEL)
- jump->flags |= PATCH_MW;
- else
+ jump->addr = (sljit_uw)code_ptr;
+
+ if (jump->flags & JUMP_ADDR)
sljit_unaligned_store_sw(code_ptr, (sljit_sw)(jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset));
+ else
+ jump->flags |= PATCH_MW;
code_ptr += 4;
return code_ptr;
/* Other operations */
/* --------------------------------------------------------------------- */
+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_s32 dst = dst_reg;
+ sljit_sw dstw = 0;
+ sljit_sw src2w = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ CHECK_EXTRA_REGS(dst, dstw, (void)0);
+ CHECK_EXTRA_REGS(src1, src1w, (void)0);
+ CHECK_EXTRA_REGS(src2_reg, src2w, (void)0);
+
+ type &= ~SLJIT_32;
+
+ if (dst & SLJIT_MEM) {
+ if (src1 == SLJIT_IMM || (!(src1 & SLJIT_MEM) && (src2_reg & SLJIT_MEM))) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+ src1 = src2_reg;
+ src1w = src2w;
+ type ^= 0x1;
+ } else
+ EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w);
+
+ dst_reg = TMP_REG1;
+ } else {
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = src2w;
+ type ^= 0x1;
+ } else if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ EMIT_MOV(compiler, dst_reg, 0, src1, src1w);
+ src1 = src2_reg;
+ src1w = src2w;
+ type ^= 0x1;
+ } else
+ EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w);
+ }
+ }
+
+ if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && (src1 != SLJIT_IMM || dst_reg != TMP_REG1)) {
+ if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+ src1 = TMP_REG1;
+ src1w = 0;
+ }
+
+ FAIL_IF(emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w));
+ } else
+ FAIL_IF(emit_cmov_generic(compiler, type, dst_reg, src1, src1w));
+
+ if (dst & SLJIT_MEM)
+ return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+ return SLJIT_SUCCESS;
+}
+
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)
if (u.imm == 0) {
inst[2] = PXOR_x_xm;
- inst[3] = U8(freg | (freg << 3) | MOD_REG);
+ inst[3] = U8(freg_map[freg] | (freg_map[freg] << 3) | MOD_REG);
} else {
inst[2] = MOVD_x_rm;
- inst[3] = U8(reg_map[TMP_REG1] | (freg << 3) | MOD_REG);
+ inst[3] = U8(reg_map[TMP_REG1] | (freg_map[freg] << 3) | MOD_REG);
}
return SLJIT_SUCCESS;
sljit_s32 freg, sljit_f64 value)
{
sljit_u8 *inst;
- sljit_s32 tmp_freg = freg;
union {
sljit_s32 imm[2];
sljit_f64 value;
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
+ } else {
+ SLJIT_ASSERT(cpu_feature_list != 0);
+
+ if (!(cpu_feature_list & CPU_FEATURE_SSE41) && u.imm[1] != 0 && u.imm[0] != u.imm[1]) {
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_IMM, u.imm[0]);
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_sw), SLJIT_IMM, u.imm[1]);
+
+ return emit_groupf(compiler, MOVLPD_x_m | EX86_SSE2, freg, SLJIT_MEM1(SLJIT_SP), 0);
+ }
+
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));
inst[0] = GROUP_0F;
inst[1] = SHUFPS_x_xm;
- inst[2] = U8(MOD_REG | (freg << 3) | freg);
+ inst[2] = U8(MOD_REG | (freg_map[freg] << 3) | freg_map[freg]);
inst[3] = 0x51;
return SLJIT_SUCCESS;
}
if (u.imm[0] != u.imm[1]) {
- SLJIT_ASSERT(u.imm[1] != 0 && cpu_feature_list != 0);
-
+ SLJIT_ASSERT(cpu_feature_list & CPU_FEATURE_SSE41);
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;
+ 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);
}
inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
inst[0] = GROUP_0F;
inst[1] = UNPCKLPS_x_xm;
- inst[2] = U8(MOD_REG | (freg << 3) | tmp_freg);
+ inst[2] = U8(MOD_REG | (freg_map[freg] << 3) | freg_map[freg]);
return SLJIT_SUCCESS;
}
inst[0] = GROUP_66;
inst[1] = GROUP_0F;
inst[2] = PSHUFD_x_xm;
- inst[3] = U8(MOD_REG | (TMP_FREG << 3) | freg);
+ inst[3] = U8(MOD_REG | (TMP_FREG << 3) | freg_map[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));
inst[0] = GROUP_0F;
inst[1] = UNPCKLPS_x_xm;
- inst[2] = U8(MOD_REG | (freg << 3) | (reg == 0 ? freg : TMP_FREG));
+ inst[2] = U8(MOD_REG | (freg_map[freg] << 3) | freg_map[reg == 0 ? freg : TMP_FREG]);
} else
FAIL_IF(emit_groupf(compiler, MOVD_rm_x | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw));
/* Enter / return */
/* --------------------------------------------------------------------- */
-static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr)
+static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr)
{
sljit_uw type = jump->flags >> TYPE_SHIFT;
- int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && !(jump->flags & JUMP_LABEL) && (jump->u.target <= 0xffffffff);
+ int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && (jump->flags & JUMP_ADDR) && (jump->u.target <= 0xffffffff);
/* The relative jump below specialized for this case. */
- SLJIT_ASSERT(reg_map[TMP_REG2] >= 8);
+ SLJIT_ASSERT(reg_map[TMP_REG2] >= 8 && TMP_REG2 != SLJIT_TMP_DEST_REG);
if (type < SLJIT_JUMP) {
/* Invert type. */
- *code_ptr++ = U8(get_jump_code(type ^ 0x1) - 0x10);
- *code_ptr++ = short_addr ? (6 + 3) : (10 + 3);
+ code_ptr[0] = U8(get_jump_code(type ^ 0x1) - 0x10);
+ code_ptr[1] = short_addr ? (6 + 3) : (10 + 3);
+ code_ptr += 2;
}
- *code_ptr++ = short_addr ? REX_B : (REX_W | REX_B);
- *code_ptr++ = MOV_r_i32 | reg_lmap[TMP_REG2];
+ code_ptr[0] = short_addr ? REX_B : (REX_W | REX_B);
+ code_ptr[1] = MOV_r_i32 | reg_lmap[TMP_REG2];
+ code_ptr += 2;
jump->addr = (sljit_uw)code_ptr;
- if (jump->flags & JUMP_LABEL)
+ if (!(jump->flags & JUMP_ADDR))
jump->flags |= PATCH_MD;
else if (short_addr)
sljit_unaligned_store_s32(code_ptr, (sljit_s32)jump->u.target);
code_ptr += short_addr ? sizeof(sljit_s32) : sizeof(sljit_sw);
- *code_ptr++ = REX_B;
- *code_ptr++ = GROUP_FF;
- *code_ptr++ = U8(MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2]);
+ code_ptr[0] = REX_B;
+ code_ptr[1] = GROUP_FF;
+ code_ptr[2] = U8(MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2]);
- return code_ptr;
+ return code_ptr + 3;
}
-static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label)
+static sljit_u8* generate_mov_addr_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset)
{
- if (max_label > HALFWORD_MAX) {
- put_label->addr -= put_label->flags;
- put_label->flags = PATCH_MD;
- return code_ptr;
- }
+ sljit_uw addr;
+ sljit_sw diff;
+ SLJIT_UNUSED_ARG(executable_offset);
- if (put_label->flags == 0) {
- /* Destination is register. */
- code_ptr = (sljit_u8*)put_label->addr - 2 - sizeof(sljit_uw);
+ SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) <= 10);
+ if (jump->flags & JUMP_ADDR)
+ addr = jump->u.target;
+ else
+ addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + jump->u.label->size;
- SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
- SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32);
+ if (addr > 0xffffffffl) {
+ diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
- if ((code_ptr[0] & 0x07) != 0) {
- code_ptr[0] = U8(code_ptr[0] & ~0x08);
- code_ptr += 2 + sizeof(sljit_s32);
- }
- else {
- code_ptr[0] = code_ptr[1];
- code_ptr += 1 + sizeof(sljit_s32);
+ if (diff <= HALFWORD_MAX && diff >= HALFWORD_MIN) {
+ SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) >= 7);
+ code_ptr -= SSIZE_OF(s32) - 1;
+
+ SLJIT_ASSERT((code_ptr[-3 - SSIZE_OF(s32)] & 0xf8) == REX_W);
+ SLJIT_ASSERT((code_ptr[-2 - SSIZE_OF(s32)] & 0xf8) == MOV_r_i32);
+
+ code_ptr[-3 - SSIZE_OF(s32)] = U8(REX_W | ((code_ptr[-3 - SSIZE_OF(s32)] & 0x1) << 2));
+ code_ptr[-1 - SSIZE_OF(s32)] = U8(((code_ptr[-2 - SSIZE_OF(s32)] & 0x7) << 3) | 0x5);
+ code_ptr[-2 - SSIZE_OF(s32)] = LEA_r_m;
+
+ jump->flags |= PATCH_MW;
+ return code_ptr;
}
- put_label->addr = (sljit_uw)code_ptr;
+ jump->flags |= PATCH_MD;
return code_ptr;
}
- code_ptr -= put_label->flags + (2 + sizeof(sljit_uw));
- SLJIT_MEMMOVE(code_ptr, code_ptr + (2 + sizeof(sljit_uw)), put_label->flags);
+ code_ptr -= 2 + sizeof(sljit_uw);
SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
+ SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32);
- if ((code_ptr[1] & 0xf8) == MOV_r_i32) {
- code_ptr += 2 + sizeof(sljit_uw);
- SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
+ if ((code_ptr[0] & 0x07) != 0) {
+ SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) >= 6);
+ code_ptr[0] = U8(code_ptr[0] & ~0x08);
+ code_ptr += 2 + sizeof(sljit_s32);
+ } else {
+ SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) >= 5);
+ code_ptr[0] = code_ptr[1];
+ code_ptr += 1 + sizeof(sljit_s32);
}
- SLJIT_ASSERT(code_ptr[1] == MOV_rm_r);
-
- code_ptr[0] = U8(code_ptr[0] & ~0x4);
- code_ptr[1] = MOV_rm_i32;
- code_ptr[2] = U8(code_ptr[2] & ~(0x7 << 3));
-
- code_ptr = (sljit_u8*)(put_label->addr - (2 + sizeof(sljit_uw)) + sizeof(sljit_s32));
- put_label->addr = (sljit_uw)code_ptr;
- put_label->flags = 0;
return code_ptr;
}
/* Other operations */
/* --------------------------------------------------------------------- */
+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)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ compiler->mode32 = type & SLJIT_32;
+ type &= ~SLJIT_32;
+
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ EMIT_MOV(compiler, dst_reg, 0, src1, src1w);
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ EMIT_MOV(compiler, dst_reg, 0, src2_reg, 0);
+ }
+
+ if (sljit_has_cpu_feature(SLJIT_HAS_CMOV)) {
+ if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
+ EMIT_MOV(compiler, TMP_REG2, 0, src1, src1w);
+ src1 = TMP_REG2;
+ src1w = 0;
+ }
+
+ return emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w);
+ }
+
+ return emit_cmov_generic(compiler, type, dst_reg, src1, src1w);
+}
+
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)
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer)
-#include <sanitizer/msan_interface.h>
-#endif /* __has_feature(memory_sanitizer) */
-#endif /* defined(__has_feature) */
-
SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "x86" SLJIT_CPUINFO;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
-
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = {
0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 5, 7, 6, 4, 3
};
#define RET() (*inst++ = RET_near)
#define RET_I16(n) (*inst++ = RET_i16, *inst++ = U8(n), *inst++ = 0)
+#define SLJIT_INST_LABEL 255
+#define SLJIT_INST_JUMP 254
+#define SLJIT_INST_MOV_ADDR 253
+#define SLJIT_INST_CONST 252
+
/* Multithreading does not affect these static variables, since they store
built-in CPU features. Therefore they can be overwritten by different threads
if they detect the CPU features in the same time. */
#define CPU_FEATURE_CMOV 0x020
#define CPU_FEATURE_AVX 0x040
#define CPU_FEATURE_AVX2 0x080
+#define CPU_FEATURE_OSXSAVE 0x100
static sljit_u32 cpu_feature_list = 0;
}
#endif /* _MSC_VER && _MSC_VER >= 1400 */
+}
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer)
-__msan_unpoison(info, 4 * sizeof(sljit_u32));
-#endif /* __has_feature(memory_sanitizer) */
-#endif /* defined(__has_feature) */
+static sljit_u32 execute_get_xcr0_low(void)
+{
+ sljit_u32 xcr0;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ xcr0 = (sljit_u32)_xgetbv(0);
+
+#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) || defined(__TINYC__)
+
+ /* AT&T syntax. */
+ __asm__ (
+ "xorl %%ecx, %%ecx\n"
+ "xgetbv\n"
+ : "=a" (xcr0)
+ :
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ : "ecx", "edx"
+#else /* !SLJIT_CONFIG_X86_32 */
+ : "rcx", "rdx"
+#endif /* SLJIT_CONFIG_X86_32 */
+ );
+
+#else /* _MSC_VER < 1400 */
+
+ /* Intel syntax. */
+ __asm {
+ mov ecx, 0
+ xgetbv
+ mov xcr0, eax
+ }
+
+#endif /* _MSC_VER && _MSC_VER >= 1400 */
+ return xcr0;
}
static void get_cpu_features(void)
{
sljit_u32 feature_list = CPU_FEATURE_DETECTED;
- sljit_u32 info[4];
+ sljit_u32 info[4] = {0};
sljit_u32 max_id;
- info[0] = 0;
execute_cpu_id(info);
max_id = info[0];
if (info[2] & 0x80000)
feature_list |= CPU_FEATURE_SSE41;
+ if (info[2] & 0x8000000)
+ feature_list |= CPU_FEATURE_OSXSAVE;
if (info[2] & 0x10000000)
feature_list |= CPU_FEATURE_AVX;
#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
}
info[0] = 0x80000001;
- info[2] = 0; /* Silences an incorrect compiler warning. */
execute_cpu_id(info);
if (info[2] & 0x20)
feature_list |= CPU_FEATURE_LZCNT;
+ if ((feature_list & CPU_FEATURE_OSXSAVE) && (execute_get_xcr0_low() & 0x4) == 0)
+ feature_list &= ~(sljit_u32)(CPU_FEATURE_AVX | CPU_FEATURE_AVX2);
+
cpu_feature_list = feature_list;
}
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
-static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset);
-#else
-static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr);
-static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label);
-#endif
+static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset);
+#else /* !SLJIT_CONFIG_X86_32 */
+static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr);
+static sljit_u8* generate_mov_addr_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset);
+#endif /* SLJIT_CONFIG_X86_32 */
-static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset)
+static sljit_u8* detect_near_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset)
{
sljit_uw type = jump->flags >> TYPE_SHIFT;
sljit_s32 short_jump;
sljit_uw label_addr;
- if (jump->flags & JUMP_LABEL)
- label_addr = (sljit_uw)(code + jump->u.label->size);
- else
+ if (jump->flags & JUMP_ADDR)
label_addr = jump->u.target - (sljit_uw)executable_offset;
+ else
+ label_addr = (sljit_uw)(code + jump->u.label->size);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if ((sljit_sw)(label_addr - (jump->addr + 2)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 6)) < HALFWORD_MIN)
- return generate_far_jump_code(jump, code_ptr);
-#endif
+ if ((sljit_sw)(label_addr - (sljit_uw)(code_ptr + 6)) > HALFWORD_MAX || (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 5)) < HALFWORD_MIN)
+ return detect_far_jump_type(jump, code_ptr);
+#endif /* SLJIT_CONFIG_X86_64 */
- short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127;
+ short_jump = (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 2)) >= -0x80 && (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 2)) <= 0x7f;
if (type == SLJIT_JUMP) {
if (short_jump)
*code_ptr++ = JMP_i8;
else
*code_ptr++ = JMP_i32;
- jump->addr++;
- }
- else if (type >= SLJIT_FAST_CALL) {
+ } else if (type > SLJIT_JUMP) {
short_jump = 0;
*code_ptr++ = CALL_i32;
- jump->addr++;
- }
- else if (short_jump) {
+ } else if (short_jump) {
*code_ptr++ = U8(get_jump_code(type) - 0x10);
- jump->addr++;
- }
- else {
+ } else {
*code_ptr++ = GROUP_0F;
*code_ptr++ = get_jump_code(type);
- jump->addr += 2;
}
+ jump->addr = (sljit_uw)code_ptr;
+
if (short_jump) {
jump->flags |= PATCH_MB;
code_ptr += sizeof(sljit_s8);
return code_ptr;
}
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset)
+{
+ sljit_uw flags = jump->flags;
+ sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;
+ sljit_uw jump_addr = jump->addr;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ if (SLJIT_UNLIKELY(flags & JUMP_MOV_ADDR)) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_unaligned_store_sw((void*)(jump_addr - sizeof(sljit_sw)), (sljit_sw)addr);
+#else /* SLJIT_CONFIG_X86_32 */
+ if (flags & PATCH_MD) {
+ SLJIT_ASSERT(addr > HALFWORD_MAX);
+ sljit_unaligned_store_sw((void*)(jump_addr - sizeof(sljit_sw)), (sljit_sw)addr);
+ return;
+ }
+
+ if (flags & PATCH_MW) {
+ addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET((sljit_u8*)jump_addr, executable_offset);
+ SLJIT_ASSERT((sljit_sw)addr <= HALFWORD_MAX && (sljit_sw)addr >= HALFWORD_MIN);
+ } else {
+ SLJIT_ASSERT(addr <= HALFWORD_MAX);
+ }
+ sljit_unaligned_store_s32((void*)(jump_addr - sizeof(sljit_s32)), (sljit_s32)addr);
+#endif /* !SLJIT_CONFIG_X86_32 */
+ return;
+ }
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (SLJIT_UNLIKELY(flags & PATCH_MD)) {
+ SLJIT_ASSERT(!(flags & JUMP_ADDR));
+ sljit_unaligned_store_sw((void*)jump_addr, (sljit_sw)addr);
+ return;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET((sljit_u8*)jump_addr, executable_offset);
+
+ if (flags & PATCH_MB) {
+ addr -= sizeof(sljit_s8);
+ SLJIT_ASSERT((sljit_sw)addr <= 0x7f && (sljit_sw)addr >= -0x80);
+ *(sljit_u8*)jump_addr = U8(addr);
+ return;
+ } else if (flags & PATCH_MW) {
+ addr -= sizeof(sljit_s32);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_unaligned_store_sw((void*)jump_addr, (sljit_sw)addr);
+#else /* !SLJIT_CONFIG_X86_32 */
+ SLJIT_ASSERT((sljit_sw)addr <= HALFWORD_MAX && (sljit_sw)addr >= HALFWORD_MIN);
+ sljit_unaligned_store_s32((void*)jump_addr, (sljit_s32)addr);
+#endif /* SLJIT_CONFIG_X86_32 */
+ }
+}
+
+static void reduce_code_size(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ sljit_uw next_label_size;
+ sljit_uw next_jump_addr;
+ sljit_uw next_min_addr;
+ sljit_uw size_reduce = 0;
+ sljit_sw diff;
+ sljit_uw type;
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ sljit_uw size_reduce_max;
+#endif /* SLJIT_DEBUG */
+
+ label = compiler->labels;
+ jump = compiler->jumps;
+
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+
+ while (1) {
+ next_min_addr = next_label_size;
+ if (next_jump_addr < next_min_addr)
+ next_min_addr = next_jump_addr;
+
+ if (next_min_addr == SLJIT_MAX_ADDRESS)
+ break;
+
+ if (next_min_addr == next_label_size) {
+ label->size -= size_reduce;
+
+ label = label->next;
+ next_label_size = SLJIT_GET_NEXT_SIZE(label);
+ }
+
+ if (next_min_addr != next_jump_addr)
+ continue;
+
+ if (!(jump->flags & JUMP_MOV_ADDR)) {
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ size_reduce_max = size_reduce + (((jump->flags >> TYPE_SHIFT) < SLJIT_JUMP) ? CJUMP_MAX_SIZE : JUMP_MAX_SIZE);
+#endif /* SLJIT_DEBUG */
+
+ if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {
+ if (jump->flags & JUMP_ADDR) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (jump->u.target <= 0xffffffffl)
+ size_reduce += sizeof(sljit_s32);
+#endif /* SLJIT_CONFIG_X86_64 */
+ } else {
+ /* Unit size: instruction. */
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - size_reduce);
+ type = jump->flags >> TYPE_SHIFT;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (type == SLJIT_JUMP) {
+ if (diff <= 0x7f + 2 && diff >= -0x80 + 2)
+ size_reduce += JUMP_MAX_SIZE - 2;
+ else if (diff <= HALFWORD_MAX + 5 && diff >= HALFWORD_MIN + 5)
+ size_reduce += JUMP_MAX_SIZE - 5;
+ } else if (type < SLJIT_JUMP) {
+ if (diff <= 0x7f + 2 && diff >= -0x80 + 2)
+ size_reduce += CJUMP_MAX_SIZE - 2;
+ else if (diff <= HALFWORD_MAX + 6 && diff >= HALFWORD_MIN + 6)
+ size_reduce += CJUMP_MAX_SIZE - 6;
+ } else {
+ if (diff <= HALFWORD_MAX + 5 && diff >= HALFWORD_MIN + 5)
+ size_reduce += JUMP_MAX_SIZE - 5;
+ }
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (type == SLJIT_JUMP) {
+ if (diff <= 0x7f + 2 && diff >= -0x80 + 2)
+ size_reduce += JUMP_MAX_SIZE - 2;
+ } else if (type < SLJIT_JUMP) {
+ if (diff <= 0x7f + 2 && diff >= -0x80 + 2)
+ size_reduce += CJUMP_MAX_SIZE - 2;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
+ }
+
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ jump->flags |= (size_reduce_max - size_reduce) << JUMP_SIZE_SHIFT;
+#endif /* SLJIT_DEBUG */
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ } else {
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ size_reduce_max = size_reduce + 10;
+#endif /* SLJIT_DEBUG */
+
+ if (!(jump->flags & JUMP_ADDR)) {
+ diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - size_reduce - 3);
+
+ if (diff <= HALFWORD_MAX && diff >= HALFWORD_MIN)
+ size_reduce += 3;
+ } else if (jump->u.target <= 0xffffffffl)
+ size_reduce += (jump->flags & MOV_ADDR_HI) ? 4 : 5;
+
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ jump->flags |= (size_reduce_max - size_reduce) << JUMP_SIZE_SHIFT;
+#endif /* SLJIT_DEBUG */
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
+
+ jump = jump->next;
+ next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
+ }
+
+ compiler->size -= size_reduce;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
{
struct sljit_memory_fragment *buf;
sljit_u8 *code;
sljit_u8 *buf_end;
sljit_u8 len;
sljit_sw executable_offset;
- sljit_uw jump_addr;
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ sljit_uw addr;
+#endif /* SLJIT_DEBUG */
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);
+
+ reduce_code_size(compiler);
/* Second code generation pass. */
- code = (sljit_u8*)SLJIT_MALLOC_EXEC(compiler->size, compiler->exec_allocator_data);
+ code = (sljit_u8*)allocate_executable_memory(compiler->size, options, exec_allocator_data, &executable_offset);
PTR_FAIL_WITH_EXEC_IF(code);
+
+ reverse_buf(compiler);
buf = compiler->buf;
code_ptr = code;
label = compiler->labels;
jump = compiler->jumps;
const_ = compiler->consts;
- put_label = compiler->put_labels;
- executable_offset = SLJIT_EXEC_OFFSET(code);
do {
buf_ptr = buf->memory;
buf_end = buf_ptr + buf->used_size;
do {
len = *buf_ptr++;
- if (len > 0) {
+ SLJIT_ASSERT(len > 0);
+ if (len < SLJIT_INST_CONST) {
/* The code is already generated. */
SLJIT_MEMCPY(code_ptr, buf_ptr, len);
code_ptr += len;
buf_ptr += len;
- }
- else {
- switch (*buf_ptr) {
- case 0:
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ } else {
+ switch (len) {
+ case SLJIT_INST_LABEL:
+ label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
break;
- case 1:
- jump->addr = (sljit_uw)code_ptr;
+ case SLJIT_INST_JUMP:
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ addr = (sljit_uw)code_ptr;
+#endif /* SLJIT_DEBUG */
if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
- code_ptr = generate_near_jump_code(jump, code_ptr, code, executable_offset);
+ code_ptr = detect_near_jump_type(jump, code_ptr, code, executable_offset);
else {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- code_ptr = generate_far_jump_code(jump, code_ptr, executable_offset);
-#else
- code_ptr = generate_far_jump_code(jump, code_ptr);
-#endif
+ code_ptr = detect_far_jump_type(jump, code_ptr, executable_offset);
+#else /* !SLJIT_CONFIG_X86_32 */
+ code_ptr = detect_far_jump_type(jump, code_ptr);
+#endif /* SLJIT_CONFIG_X86_32 */
}
+
+ SLJIT_ASSERT((sljit_uw)code_ptr - addr <= ((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f));
jump = jump->next;
break;
- case 2:
- const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw);
- const_ = const_->next;
+ case SLJIT_INST_MOV_ADDR:
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ code_ptr = generate_mov_addr_code(jump, code_ptr, code, executable_offset);
+#endif /* SLJIT_CONFIG_X86_64 */
+ jump->addr = (sljit_uw)code_ptr;
+ jump = jump->next;
break;
default:
- SLJIT_ASSERT(*buf_ptr == 3);
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- code_ptr = generate_put_label_code(put_label, code_ptr, (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size);
-#endif
- put_label = put_label->next;
+ SLJIT_ASSERT(len == SLJIT_INST_CONST);
+ const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw);
+ const_ = const_->next;
break;
}
- buf_ptr++;
}
} while (buf_ptr < buf_end);
+
SLJIT_ASSERT(buf_ptr == buf_end);
buf = buf->next;
} while (buf);
SLJIT_ASSERT(!label);
SLJIT_ASSERT(!jump);
SLJIT_ASSERT(!const_);
- SLJIT_ASSERT(!put_label);
SLJIT_ASSERT(code_ptr <= code + compiler->size);
jump = compiler->jumps;
while (jump) {
- if (jump->flags & (PATCH_MB | PATCH_MW)) {
- if (jump->flags & JUMP_LABEL)
- jump_addr = jump->u.label->addr;
- else
- jump_addr = jump->u.target;
-
- jump_addr -= jump->addr + (sljit_uw)executable_offset;
-
- if (jump->flags & PATCH_MB) {
- jump_addr -= sizeof(sljit_s8);
- SLJIT_ASSERT((sljit_sw)jump_addr >= -128 && (sljit_sw)jump_addr <= 127);
- *(sljit_u8*)jump->addr = U8(jump_addr);
- } else {
- jump_addr -= sizeof(sljit_s32);
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump_addr);
-#else
- SLJIT_ASSERT((sljit_sw)jump_addr >= HALFWORD_MIN && (sljit_sw)jump_addr <= HALFWORD_MAX);
- sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)jump_addr);
-#endif
- }
- }
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- else if (jump->flags & PATCH_MD) {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
- sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump->u.label->addr);
- }
-#endif
-
+ generate_jump_or_mov_addr(jump, executable_offset);
jump = jump->next;
}
- put_label = compiler->put_labels;
- while (put_label) {
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_unaligned_store_sw((void*)(put_label->addr - sizeof(sljit_sw)), (sljit_sw)put_label->label->addr);
-#else
- if (put_label->flags & PATCH_MD) {
- SLJIT_ASSERT(put_label->label->addr > HALFWORD_MAX);
- sljit_unaligned_store_sw((void*)(put_label->addr - sizeof(sljit_sw)), (sljit_sw)put_label->label->addr);
- }
- else {
- SLJIT_ASSERT(put_label->label->addr <= HALFWORD_MAX);
- sljit_unaligned_store_s32((void*)(put_label->addr - sizeof(sljit_s32)), (sljit_s32)put_label->label->addr);
- }
-#endif
-
- put_label = put_label->next;
- }
-
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
compiler->executable_size = (sljit_uw)(code_ptr - code);
BINARY_IMM32(op_imm, immw, arg, argw); \
} \
else { \
- FAIL_IF(emit_load_imm64(compiler, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, immw)); \
- inst = emit_x86_instruction(compiler, 1, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, 0, arg, argw); \
+ FAIL_IF(emit_load_imm64(compiler, FAST_IS_REG(arg) ? TMP_REG2 : TMP_REG1, immw)); \
+ inst = emit_x86_instruction(compiler, 1, FAST_IS_REG(arg) ? TMP_REG2 : TMP_REG1, 0, arg, argw); \
FAIL_IF(!inst); \
*inst = (op_mr); \
} \
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w);
FAIL_IF(!inst);
*inst = GROUP_F7;
- }
- else {
- FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src2w));
- inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src1, src1w);
+ } else {
+ FAIL_IF(emit_load_imm64(compiler, FAST_IS_REG(src1) ? TMP_REG2 : TMP_REG1, src2w));
+ inst = emit_x86_instruction(compiler, 1, FAST_IS_REG(src1) ? TMP_REG2 : TMP_REG1, 0, src1, src1w);
FAIL_IF(!inst);
*inst = TEST_rm_r;
}
compiler->mode32 = op & SLJIT_32;
#endif
- SLJIT_ASSERT(dst != TMP_REG1 || HAS_FLAGS(op));
-
switch (GET_OPCODE(op)) {
case SLJIT_ADD:
if (!HAS_FLAGS(op)) {
compiler->mode32 = op & SLJIT_32;
#endif
- if (opcode == SLJIT_SUB) {
+ if (opcode == SLJIT_SUB)
return emit_cmp_binary(compiler, src1, src1w, src2, src2w);
- }
+
return emit_test_binary(compiler, src1, src1w, src2, src2w);
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_u8* inst;
+ sljit_sw dstw = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ CHECK_EXTRA_REGS(dst_reg, dstw, (void)0);
+ CHECK_EXTRA_REGS(src1, src1w, (void)0);
+ CHECK_EXTRA_REGS(src2, src2w, (void)0);
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = op & SLJIT_32;
+#endif
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MULADD:
+ FAIL_IF(emit_mul(compiler, TMP_REG1, 0, src1, src1w, src2, src2w));
+ inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst_reg, dstw);
+ FAIL_IF(!inst);
+ *inst = ADD_rm_r;
+ return SLJIT_SUCCESS;
+ }
+
+ return SLJIT_SUCCESS;
+}
+
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,
dst_r = dst;
if (dst == src1)
; /* Do nothing here. */
- else if (dst == src2 && (op == SLJIT_ADD_F64 || op == SLJIT_MUL_F64)) {
+ else if (dst == src2 && (GET_OPCODE(op) == SLJIT_ADD_F64 || GET_OPCODE(op) == SLJIT_MUL_F64)) {
/* Swap arguments. */
src2 = src1;
src2w = src1w;
- }
- else if (dst != src2)
+ } else if (dst != src2)
FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_r, src1, src1w));
else {
dst_r = TMP_FREG;
FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w));
}
- }
- else {
+ } else {
dst_r = TMP_FREG;
FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w));
}
break;
}
- if (dst_r == TMP_FREG)
+ if (dst_r != dst)
return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
return SLJIT_SUCCESS;
}
PTR_FAIL_IF(!label);
set_label(label, compiler);
- inst = (sljit_u8*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1);
PTR_FAIL_IF(!inst);
- inst[0] = 0;
- inst[1] = 0;
+ inst[0] = SLJIT_INST_LABEL;
return label;
}
set_jump(jump, compiler, (sljit_u32)((type & SLJIT_REWRITABLE_JUMP) | ((type & 0xff) << TYPE_SHIFT)));
type &= 0xff;
+ jump->addr = compiler->size;
/* Worst case size. */
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- compiler->size += (type >= SLJIT_JUMP) ? 5 : 6;
-#else
- compiler->size += (type >= SLJIT_JUMP) ? (10 + 3) : (2 + 10 + 3);
-#endif
-
- inst = (sljit_u8*)ensure_buf(compiler, 2);
+ compiler->size += (type >= SLJIT_JUMP) ? JUMP_MAX_SIZE : CJUMP_MAX_SIZE;
+ inst = (sljit_u8*)ensure_buf(compiler, 1);
PTR_FAIL_IF_NULL(inst);
- inst[0] = 0;
- inst[1] = 1;
+ inst[0] = SLJIT_INST_JUMP;
return jump;
}
set_jump(jump, compiler, (sljit_u32)(JUMP_ADDR | (type << TYPE_SHIFT)));
jump->u.target = (sljit_uw)srcw;
+ jump->addr = compiler->size;
/* Worst case size. */
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- compiler->size += 5;
-#else
- compiler->size += 10 + 3;
-#endif
-
- inst = (sljit_u8*)ensure_buf(compiler, 2);
+ compiler->size += JUMP_MAX_SIZE;
+ inst = (sljit_u8*)ensure_buf(compiler, 1);
FAIL_IF_NULL(inst);
- inst[0] = 0;
- inst[1] = 1;
- }
- else {
+ inst[0] = SLJIT_INST_JUMP;
+ } else {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
/* REX_W is not necessary (src is not immediate). */
compiler->mode32 = 1;
#endif /* SLJIT_CONFIG_X86_64 */
}
-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)
-{
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_s32 dst = dst_reg;
- sljit_sw dstw = 0;
-#endif /* SLJIT_CONFIG_X86_32 */
- sljit_sw src2w = 0;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
-
- ADJUST_LOCAL_OFFSET(src1, src1w);
-
- CHECK_EXTRA_REGS(dst, dstw, (void)0);
- CHECK_EXTRA_REGS(src1, src1w, (void)0);
- CHECK_EXTRA_REGS(src2_reg, src2w, (void)0);
-
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = type & SLJIT_32;
-#endif /* SLJIT_CONFIG_X86_64 */
- type &= ~SLJIT_32;
-
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (dst & SLJIT_MEM) {
- if (src1 == SLJIT_IMM || (!(src1 & SLJIT_MEM) && (src2_reg & SLJIT_MEM))) {
- EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
- src1 = src2_reg;
- src1w = src2w;
- type ^= 0x1;
- } else
- EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w);
-
- dst_reg = TMP_REG1;
- } else {
-#endif /* SLJIT_CONFIG_X86_32 */
- if (dst_reg != src2_reg) {
- if (dst_reg == src1) {
- src1 = src2_reg;
- src1w = src2w;
- type ^= 0x1;
- } else {
- if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
- EMIT_MOV(compiler, dst_reg, 0, src1, src1w);
- src1 = src2_reg;
- src1w = src2w;
- type ^= 0x1;
- } else
- EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w);
- }
- }
-
- if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
- SLJIT_ASSERT(dst_reg != TMP_REG1);
- EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
- src1 = TMP_REG1;
- src1w = 0;
- }
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- }
-#endif /* SLJIT_CONFIG_X86_32 */
-
- if (sljit_has_cpu_feature(SLJIT_HAS_CMOV))
- FAIL_IF(emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w));
- else
- FAIL_IF(emit_cmov_generic(compiler, type, dst_reg, src1, src1w));
-
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (dst_reg == TMP_REG1)
- return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
-#endif /* SLJIT_CONFIG_X86_32 */
- 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,
if (type & SLJIT_SIMD_TEST)
return SLJIT_SUCCESS;
- if (op & VEX_256)
+ if ((op & VEX_256) || ((cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX)))
return emit_vex_instruction(compiler, op, freg, 0, srcdst, srcdstw);
return emit_groupf(compiler, op, freg, srcdst, srcdstw);
{
sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX);
sljit_u8 *inst;
sljit_u8 opcode = 0;
- sljit_uw size;
+ sljit_uw op;
CHECK_ERROR();
CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
return SLJIT_ERR_UNSUPPORTED;
#endif /* SLJIT_CONFIG_X86_32 */
- if (cpu_feature_list & CPU_FEATURE_AVX2) {
- if (reg_size < 4 || reg_size > 5)
- return SLJIT_ERR_UNSUPPORTED;
+ if (reg_size != 4 && (reg_size != 5 || !(cpu_feature_list & CPU_FEATURE_AVX2)))
+ return SLJIT_ERR_UNSUPPORTED;
- if (src != SLJIT_IMM && (reg_size == 5 || elem_size < 3 || !(type & SLJIT_SIMD_FLOAT))) {
- if (type & SLJIT_SIMD_TEST)
- return SLJIT_SUCCESS;
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 5)
+ use_vex = 1;
+ if (use_vex && src != SLJIT_IMM) {
+ op = 0;
+
+ switch (elem_size) {
+ case 0:
+ if (cpu_feature_list & CPU_FEATURE_AVX2)
+ op = VPBROADCASTB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ case 1:
+ if (cpu_feature_list & CPU_FEATURE_AVX2)
+ op = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ case 2:
+ if (type & SLJIT_SIMD_FLOAT) {
+ if ((cpu_feature_list & CPU_FEATURE_AVX2) || ((cpu_feature_list & CPU_FEATURE_AVX) && (src & SLJIT_MEM)))
+ op = VBROADCASTSS_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ } else if (cpu_feature_list & CPU_FEATURE_AVX2)
+ op = VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ default:
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (!(type & SLJIT_SIMD_FLOAT)) {
+ if (cpu_feature_list & CPU_FEATURE_AVX2)
+ op = VPBROADCASTQ_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (reg_size == 5)
+ op = VBROADCASTSD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ }
+
+ if (op != 0) {
if (!(src & SLJIT_MEM) && !(type & SLJIT_SIMD_FLOAT)) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (elem_size >= 3)
compiler->mode32 = 0;
#endif /* SLJIT_CONFIG_X86_64 */
- FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, src, srcw));
+ FAIL_IF(emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw));
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 1;
#endif /* SLJIT_CONFIG_X86_64 */
srcw = 0;
}
- switch (elem_size) {
- case 0:
- size = VPBROADCASTB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
- break;
- case 1:
- size = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
- break;
- case 2:
- size = ((type & SLJIT_SIMD_FLOAT) ? VBROADCASTSS_x_xm : VPBROADCASTD_x_xm) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
- break;
- default:
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- size = VBROADCASTSD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
-#else /* !SLJIT_CONFIG_X86_32 */
- size = ((type & SLJIT_SIMD_FLOAT) ? VBROADCASTSD_x_xm : VPBROADCASTQ_x_xm) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
-#endif /* SLJIT_CONFIG_X86_32 */
- break;
- }
-
if (reg_size == 5)
- size |= VEX_256;
+ op |= VEX_256;
- return emit_vex_instruction(compiler, size, freg, 0, src, srcw);
+ return emit_vex_instruction(compiler, op, freg, 0, src, srcw);
}
- } else if (reg_size != 4)
- return SLJIT_ERR_UNSUPPORTED;
-
- if (type & SLJIT_SIMD_TEST)
- return SLJIT_SUCCESS;
+ }
if (type & SLJIT_SIMD_FLOAT) {
if (src == SLJIT_IMM) {
- if (reg_size == 5)
- return emit_vex_instruction(compiler, XORPD_x_xm | VEX_256 | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0);
+ if (use_vex)
+ return emit_vex_instruction(compiler, XORPD_x_xm | (reg_size == 5 ? VEX_256 : 0) | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0);
return emit_groupf(compiler, XORPD_x_xm | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2, freg, freg, 0);
}
+ SLJIT_ASSERT(reg_size == 4);
+
+ if (use_vex) {
+ if (elem_size == 3)
+ return emit_vex_instruction(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, 0, src, srcw);
+
+ SLJIT_ASSERT(!(src & SLJIT_MEM));
+ FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, freg, src, src, 0));
+ return emit_byte(compiler, 0);
+ }
+
if (elem_size == 2 && freg != src) {
FAIL_IF(emit_sse2_load(compiler, 1, freg, src, srcw));
src = freg;
srcw = 0;
}
- FAIL_IF(emit_groupf(compiler, (elem_size == 2 ? SHUFPS_x_xm : MOVDDUP_x_xm) | (elem_size == 2 ? 0 : EX86_PREF_F2) | EX86_SSE2, freg, src, srcw));
+ op = (elem_size == 2 ? SHUFPS_x_xm : MOVDDUP_x_xm) | (elem_size == 2 ? 0 : EX86_PREF_F2) | EX86_SSE2;
+ FAIL_IF(emit_groupf(compiler, op, freg, src, srcw));
if (elem_size == 2)
return emit_byte(compiler, 0);
#endif /* SLJIT_CONFIG_X86_64 */
if (srcw == 0 || srcw == -1) {
- if (reg_size == 5)
- return emit_vex_instruction(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | VEX_256 | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0);
+ if (use_vex)
+ return emit_vex_instruction(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | (reg_size == 5 ? VEX_256 : 0) | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0);
return emit_groupf(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | EX86_PREF_66 | EX86_SSE2, freg, freg, 0);
}
src = TMP_REG1;
srcw = 0;
+
}
- size = 2;
+ op = 2;
opcode = MOVD_x_rm;
switch (elem_size) {
case 0:
if (!FAST_IS_REG(src)) {
opcode = 0x3a /* Prefix of PINSRB_x_rm_i8. */;
- size = 3;
+ op = 3;
}
break;
case 1:
#endif /* SLJIT_CONFIG_X86_64 */
}
- inst = emit_x86_instruction(compiler, size | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw);
- FAIL_IF(!inst);
- inst[0] = GROUP_0F;
- inst[1] = opcode;
+ if (use_vex) {
+ if (opcode != MOVD_x_rm) {
+ op = (opcode == 0x3a) ? (PINSRB_x_rm_i8 | VEX_OP_0F3A) : opcode;
+ FAIL_IF(emit_vex_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2_OP1 | VEX_SSE2_OPV, freg, freg, src, srcw));
+ } else
+ FAIL_IF(emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw));
+ } else {
+ inst = emit_x86_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw);
+ FAIL_IF(!inst);
+ inst[0] = GROUP_0F;
+ inst[1] = opcode;
- if (reg_size == 5) {
- SLJIT_ASSERT(opcode == MOVD_x_rm);
+ if (op == 3) {
+ SLJIT_ASSERT(opcode == 0x3a);
+ inst[2] = PINSRB_x_rm_i8;
+ }
+ }
+
+ if (use_vex && elem_size >= 2) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- size = VPBROADCASTD_x_xm;
+ op = VPBROADCASTD_x_xm;
#else /* !SLJIT_CONFIG_X86_32 */
- size = (elem_size == 3) ? VPBROADCASTQ_x_xm : VPBROADCASTD_x_xm;
+ op = (elem_size == 3) ? VPBROADCASTQ_x_xm : VPBROADCASTD_x_xm;
#endif /* SLJIT_CONFIG_X86_32 */
- return emit_vex_instruction(compiler, size | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0);
+ return emit_vex_instruction(compiler, op | ((reg_size == 5) ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0);
}
- if (size == 3) {
- SLJIT_ASSERT(opcode == 0x3a);
- inst[2] = PINSRB_x_rm_i8;
- }
+ SLJIT_ASSERT(reg_size == 4);
if (opcode != MOVD_x_rm)
FAIL_IF(emit_byte(compiler, 0));
switch (elem_size) {
case 0:
+ if (use_vex) {
+ FAIL_IF(emit_vex_instruction(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, TMP_FREG, TMP_FREG, 0));
+ return emit_vex_instruction(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, TMP_FREG, 0);
+ }
FAIL_IF(emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, TMP_FREG, 0));
return emit_groupf_ext(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, TMP_FREG, 0);
case 1:
- FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, freg, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, 0, freg, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, freg, 0));
FAIL_IF(emit_byte(compiler, 0));
/* fallthrough */
default:
- FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, 0, freg, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0));
return emit_byte(compiler, 0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
case 3:
compiler->mode32 = 1;
- FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, 0, freg, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0));
return emit_byte(compiler, 0x44);
#endif /* SLJIT_CONFIG_X86_64 */
}
{
sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX);
sljit_u8 *inst;
sljit_u8 opcode = 0;
- sljit_uw size;
+ sljit_uw op;
sljit_s32 freg_orig = freg;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
sljit_s32 srcdst_is_ereg = 0;
if (reg_size == 5) {
if (!(cpu_feature_list & CPU_FEATURE_AVX2))
return SLJIT_ERR_UNSUPPORTED;
+ use_vex = 1;
} else if (reg_size != 4)
return SLJIT_ERR_UNSUPPORTED;
}
if (elem_size == 2) {
- if (reg_size == 4)
- return emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, srcdst, srcdstw);
- return emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw);
+ if (use_vex)
+ return emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw);
+ return emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, srcdst, srcdstw);
}
} else if (srcdst & SLJIT_MEM) {
SLJIT_ASSERT(elem_size == 2 || elem_size == 3);
- if (reg_size == 4)
- return emit_groupf(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, srcdst, srcdstw);
- return emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, 0, srcdst, srcdstw);
+ if (use_vex)
+ return emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, 0, srcdst, srcdstw);
+ return emit_groupf(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, srcdst, srcdstw);
} else if (elem_size == 3) {
- if (reg_size == 4)
- return emit_groupf(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, srcdst, 0);
- return emit_vex_instruction(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, 0, srcdst, 0);
+ if (use_vex)
+ return emit_vex_instruction(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, 0, srcdst, 0);
+ return emit_groupf(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, srcdst, 0);
+ } else if (use_vex) {
+ FAIL_IF(emit_vex_instruction(compiler, XORPD_x_xm | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, TMP_FREG, TMP_FREG, 0));
+ return emit_vex_instruction(compiler, MOVSD_x_xm | EX86_PREF_F3 | EX86_SSE2 | VEX_SSE2_OPV, freg, TMP_FREG, srcdst, 0);
}
}
freg = TMP_FREG;
lane_index -= (1 << (4 - elem_size));
} else if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) {
- FAIL_IF(emit_sse2_load(compiler, elem_size == 2, TMP_FREG, srcdst, srcdstw));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, TMP_FREG, srcdst, srcdstw));
+ else
+ FAIL_IF(emit_sse2_load(compiler, elem_size == 2, TMP_FREG, srcdst, srcdstw));
srcdst = TMP_FREG;
srcdstw = 0;
}
- size = ((!(type & SLJIT_SIMD_FLOAT) || elem_size != 2) ? EX86_PREF_66 : 0)
+ op = ((!(type & SLJIT_SIMD_FLOAT) || elem_size != 2) ? EX86_PREF_66 : 0)
| ((type & SLJIT_SIMD_FLOAT) ? XORPD_x_xm : PXOR_x_xm) | EX86_SSE2;
- if (reg_size == 5)
- FAIL_IF(emit_vex_instruction(compiler, size | VEX_256 | VEX_SSE2_OPV, freg, freg, freg, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, op | (reg_size == 5 ? VEX_256 : 0) | VEX_SSE2_OPV, freg, freg, freg, 0));
else
- FAIL_IF(emit_groupf(compiler, size, freg, freg, 0));
+ FAIL_IF(emit_groupf(compiler, op, freg, freg, 0));
} else if (reg_size == 5 && lane_index >= (1 << (4 - elem_size))) {
FAIL_IF(emit_vex_instruction(compiler, ((type & SLJIT_SIMD_FLOAT) ? VEXTRACTF128_x_ym : VEXTRACTI128_x_ym) | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, 0, TMP_FREG, 0));
FAIL_IF(emit_byte(compiler, 1));
if (elem_size == 3) {
if (srcdst & SLJIT_MEM) {
if (type & SLJIT_SIMD_STORE)
- size = lane_index == 0 ? MOVLPD_m_x : MOVHPD_m_x;
+ op = lane_index == 0 ? MOVLPD_m_x : MOVHPD_m_x;
else
- size = lane_index == 0 ? MOVLPD_x_m : MOVHPD_x_m;
+ op = lane_index == 0 ? MOVLPD_x_m : MOVHPD_x_m;
- FAIL_IF(emit_groupf(compiler, size | EX86_PREF_66 | EX86_SSE2, freg, srcdst, srcdstw));
+ /* VEX prefix clears upper bits of the target register. */
+ if (use_vex && ((type & SLJIT_SIMD_STORE) || reg_size == 4 || freg == TMP_FREG))
+ FAIL_IF(emit_vex_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2
+ | ((type & SLJIT_SIMD_STORE) ? 0 : VEX_SSE2_OPV), freg, (type & SLJIT_SIMD_STORE) ? 0 : freg, srcdst, srcdstw));
+ else
+ FAIL_IF(emit_groupf(compiler, op | EX86_PREF_66 | EX86_SSE2, freg, srcdst, srcdstw));
/* In case of store, freg is not TMP_FREG. */
} else if (type & SLJIT_SIMD_STORE) {
- if (lane_index == 1)
+ if (lane_index == 1) {
+ if (use_vex)
+ return emit_vex_instruction(compiler, MOVHLPS_x_x | EX86_SSE2 | VEX_SSE2_OPV, srcdst, srcdst, freg, 0);
return emit_groupf(compiler, MOVHLPS_x_x | EX86_SSE2, srcdst, freg, 0);
+ }
+ if (use_vex)
+ return emit_vex_instruction(compiler, MOVSD_x_xm | EX86_PREF_F2 | EX86_SSE2 | VEX_SSE2_OPV, srcdst, srcdst, freg, 0);
return emit_sse2_load(compiler, 0, srcdst, freg, 0);
+ } else if (use_vex && (reg_size == 4 || freg == TMP_FREG)) {
+ if (lane_index == 1)
+ FAIL_IF(emit_vex_instruction(compiler, MOVLHPS_x_x | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, srcdst, 0));
+ else
+ FAIL_IF(emit_vex_instruction(compiler, MOVSD_x_xm | EX86_PREF_F2 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, srcdst, 0));
} else {
if (lane_index == 1)
FAIL_IF(emit_groupf(compiler, MOVLHPS_x_x | EX86_SSE2, freg, srcdst, 0));
else
- FAIL_IF(emit_sse2_store(compiler, 0, freg, 0, srcdst));
+ FAIL_IF(emit_sse2_load(compiler, 0, freg, srcdst, 0));
}
} else if (type & SLJIT_SIMD_STORE) {
- if (lane_index == 0)
+ if (lane_index == 0) {
+ if (use_vex)
+ return emit_vex_instruction(compiler, ((srcdst & SLJIT_MEM) ? MOVSD_xm_x : MOVSD_x_xm) | EX86_PREF_F3 | EX86_SSE2
+ | ((srcdst & SLJIT_MEM) ? 0 : VEX_SSE2_OPV), freg, ((srcdst & SLJIT_MEM) ? 0 : freg), srcdst, srcdstw);
return emit_sse2_store(compiler, 1, srcdst, srcdstw, freg);
+ }
if (srcdst & SLJIT_MEM) {
- FAIL_IF(emit_groupf_ext(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, srcdst, srcdstw));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, 0, srcdst, srcdstw));
+ else
+ FAIL_IF(emit_groupf_ext(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, srcdst, srcdstw));
+ return emit_byte(compiler, U8(lane_index));
+ }
+
+ if (use_vex) {
+ FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, srcdst, freg, freg, 0));
return emit_byte(compiler, U8(lane_index));
}
if (srcdst == freg)
- size = SHUFPS_x_xm | EX86_SSE2;
+ op = SHUFPS_x_xm | EX86_SSE2;
else {
- if (cpu_feature_list & CPU_FEATURE_AVX) {
- FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, srcdst, freg, freg, 0));
- return emit_byte(compiler, U8(lane_index));
- }
-
switch (lane_index) {
case 1:
- size = MOVSHDUP_x_xm | EX86_PREF_F3 | EX86_SSE2;
+ op = MOVSHDUP_x_xm | EX86_PREF_F3 | EX86_SSE2;
break;
case 2:
- size = MOVHLPS_x_x | EX86_SSE2;
+ op = MOVHLPS_x_x | EX86_SSE2;
break;
default:
SLJIT_ASSERT(lane_index == 3);
- size = PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2;
+ op = PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2;
break;
}
}
- FAIL_IF(emit_groupf(compiler, size, srcdst, freg, 0));
+ FAIL_IF(emit_groupf(compiler, op, srcdst, freg, 0));
- size &= 0xff;
- if (size == SHUFPS_x_xm || size == PSHUFD_x_xm)
+ op &= 0xff;
+ if (op == SHUFPS_x_xm || op == PSHUFD_x_xm)
return emit_byte(compiler, U8(lane_index));
return SLJIT_SUCCESS;
srcdstw = 0;
}
- size = 3;
+ op = 3;
switch (elem_size) {
case 0:
break;
case 1:
if (!(type & SLJIT_SIMD_STORE)) {
- size = 2;
+ op = 2;
opcode = PINSRW_x_rm_i8;
} else
opcode = PEXTRW_rm_x_i8;
#endif /* SLJIT_CONFIG_X86_64 */
}
- inst = emit_x86_instruction(compiler, size | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw);
- FAIL_IF(!inst);
- inst[0] = GROUP_0F;
+ if (use_vex && (type & SLJIT_SIMD_STORE)) {
+ op = opcode | ((op == 3) ? VEX_OP_0F3A : 0);
+ FAIL_IF(emit_vex_instruction(compiler, op | EX86_PREF_66 | VEX_AUTO_W | EX86_SSE2_OP1 | VEX_SSE2_OPV, freg, 0, srcdst, srcdstw));
+ } else {
+ inst = emit_x86_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw);
+ FAIL_IF(!inst);
+ inst[0] = GROUP_0F;
- if (size == 3) {
- inst[1] = 0x3a;
- inst[2] = opcode;
- } else
- inst[1] = opcode;
+ if (op == 3) {
+ inst[1] = 0x3a;
+ inst[2] = opcode;
+ } else
+ inst[1] = opcode;
+ }
FAIL_IF(emit_byte(compiler, U8(lane_index)));
compiler->mode32 = (type & SLJIT_32);
- size = 2;
+ op = 2;
if (elem_size == 0)
- size |= EX86_REX;
+ op |= EX86_REX;
if (elem_size == 2) {
if (type & SLJIT_32)
return SLJIT_SUCCESS;
SLJIT_ASSERT(!(compiler->mode32));
- size = 1;
+ op = 1;
}
- inst = emit_x86_instruction(compiler, size, srcdst, 0, srcdst, 0);
+ inst = emit_x86_instruction(compiler, op, srcdst, 0, srcdst, 0);
FAIL_IF(!inst);
- if (size != 1) {
+ if (op != 1) {
inst[0] = GROUP_0F;
inst[1] = U8((elem_size == 0) ? MOVSX_r_rm8 : MOVSX_r_rm16);
} else
{
sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX);
sljit_uw pref;
sljit_u8 byte;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
if (reg_size == 5) {
if (!(cpu_feature_list & CPU_FEATURE_AVX2))
return SLJIT_ERR_UNSUPPORTED;
+ use_vex = 1;
} else if (reg_size != 4)
return SLJIT_ERR_UNSUPPORTED;
return emit_byte(compiler, U8(byte | (byte << 4)));
}
- if (src_lane_index == 0)
+ if (src_lane_index == 0) {
+ if (use_vex)
+ return emit_vex_instruction(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, 0, src, 0);
return emit_groupf(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, src, 0);
+ }
/* Changes it to SHUFPD_x_xm. */
pref = EX86_PREF_66;
FAIL_IF(emit_byte(compiler, byte));
FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | VEX_256 | pref | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0));
byte = U8(src_lane_index);
- } else if (freg != src && (cpu_feature_list & CPU_FEATURE_AVX)) {
+ } else if (use_vex) {
FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | pref | EX86_SSE2 | VEX_SSE2_OPV, freg, src, src, 0));
} else {
if (freg != src)
src = freg;
}
- if ((freg != src && !(cpu_feature_list & CPU_FEATURE_AVX2)) || src_lane_index != 0) {
+ if (src_lane_index != 0 || (freg != src && (!(cpu_feature_list & CPU_FEATURE_AVX2) || !use_vex))) {
pref = 0;
if ((src_lane_index & 0x3) == 0) {
pref = EX86_PREF_F2;
byte = U8(src_lane_index >> 1);
} else {
- if (freg == src || !(cpu_feature_list & CPU_FEATURE_AVX2)) {
+ if (!use_vex) {
if (freg != src)
FAIL_IF(emit_groupf(compiler, MOVDQA_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0));
}
if (pref != 0) {
- FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, 0, src, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0));
FAIL_IF(emit_byte(compiler, byte));
}
src = freg;
}
- if (cpu_feature_list & CPU_FEATURE_AVX2)
+ if (use_vex && (cpu_feature_list & CPU_FEATURE_AVX2))
return emit_vex_instruction(compiler, VPBROADCASTB_x_xm | (reg_size == 5 ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, 0);
SLJIT_ASSERT(reg_size == 4);
return emit_groupf_ext(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, TMP_FREG, 0);
}
- if ((cpu_feature_list & CPU_FEATURE_AVX2) && src_lane_index == 0 && elem_size <= 3) {
+ if ((cpu_feature_list & CPU_FEATURE_AVX2) && use_vex && src_lane_index == 0 && elem_size <= 3) {
switch (elem_size) {
case 1:
pref = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
src_lane_index >>= 1;
pref = (src_lane_index & 2) == 0 ? EX86_PREF_F2 : EX86_PREF_F3;
- FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, 0, src, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0));
byte = U8(byte | (byte << 2));
FAIL_IF(emit_byte(compiler, U8(byte | (byte << 4))));
- if ((cpu_feature_list & CPU_FEATURE_AVX2) && pref == EX86_PREF_F2)
+ if ((cpu_feature_list & CPU_FEATURE_AVX2) && use_vex && pref == EX86_PREF_F2)
return emit_vex_instruction(compiler, VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0);
src = freg;
break;
}
- FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, 0, src, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0));
return emit_byte(compiler, U8(byte | (byte << 4)));
}
sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX);
sljit_u8 opcode;
CHECK_ERROR();
if (reg_size == 5) {
if (!(cpu_feature_list & CPU_FEATURE_AVX2))
return SLJIT_ERR_UNSUPPORTED;
+ use_vex = 1;
} else if (reg_size != 4)
return SLJIT_ERR_UNSUPPORTED;
if (type & SLJIT_SIMD_TEST)
return SLJIT_SUCCESS;
- if (reg_size == 4)
- return emit_groupf(compiler, CVTPS2PD_x_xm | EX86_SSE2, freg, src, srcw);
- return emit_vex_instruction(compiler, CVTPS2PD_x_xm | VEX_256 | EX86_SSE2, freg, 0, src, srcw);
+ if (use_vex)
+ return emit_vex_instruction(compiler, CVTPS2PD_x_xm | ((reg_size == 5) ? VEX_256 : 0) | EX86_SSE2, freg, 0, src, srcw);
+ return emit_groupf(compiler, CVTPS2PD_x_xm | EX86_SSE2, freg, src, srcw);
}
switch (elem_size) {
if (type & SLJIT_SIMD_TEST)
return SLJIT_SUCCESS;
- if (reg_size == 4)
- return emit_groupf_ext(compiler, opcode | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, src, srcw);
- return emit_vex_instruction(compiler, opcode | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, srcw);
+ if (use_vex)
+ return emit_vex_instruction(compiler, opcode | ((reg_size == 5) ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, srcw);
+ return emit_groupf_ext(compiler, opcode | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, src, srcw);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
{
sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX);
sljit_s32 dst_r;
- sljit_uw pref;
+ sljit_uw op;
sljit_u8 *inst;
CHECK_ERROR();
if (type & SLJIT_SIMD_TEST)
return SLJIT_SUCCESS;
- pref = EX86_PREF_66 | EX86_SSE2_OP2;
+ op = EX86_PREF_66 | EX86_SSE2_OP2;
switch (elem_size) {
case 1:
- FAIL_IF(emit_groupf(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, freg, 0));
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, freg, freg, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, freg, 0));
freg = TMP_FREG;
break;
case 2:
- pref = EX86_SSE2_OP2;
+ op = EX86_SSE2_OP2;
break;
}
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
- FAIL_IF(emit_groupf(compiler, (elem_size < 2 ? PMOVMSKB_r_x : MOVMSKPS_r_x) | pref, dst_r, freg, 0));
+ op |= (elem_size < 2) ? PMOVMSKB_r_x : MOVMSKPS_r_x;
+
+ if (use_vex)
+ FAIL_IF(emit_vex_instruction(compiler, op, dst_r, 0, freg, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, op, dst_r, freg, 0));
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = type & SLJIT_32;
FAIL_IF(emit_vex_instruction(compiler, PACKSSWB_x_xm | VEX_256 | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, freg, TMP_FREG, 0));
FAIL_IF(emit_groupf(compiler, PMOVMSKB_r_x | EX86_PREF_66 | EX86_SSE2_OP2, dst_r, TMP_FREG, 0));
} else {
- pref = MOVMSKPS_r_x | VEX_256 | EX86_SSE2_OP2;
+ op = MOVMSKPS_r_x | VEX_256 | EX86_SSE2_OP2;
if (elem_size == 0)
- pref = PMOVMSKB_r_x | VEX_256 | EX86_PREF_66 | EX86_SSE2_OP2;
+ op = PMOVMSKB_r_x | VEX_256 | EX86_PREF_66 | EX86_SSE2_OP2;
else if (elem_size == 3)
- pref |= EX86_PREF_66;
+ op |= EX86_PREF_66;
- FAIL_IF(emit_vex_instruction(compiler, pref, dst_r, 0, freg, 0));
+ FAIL_IF(emit_vex_instruction(compiler, op, dst_r, 0, freg, 0));
}
if (dst_r == TMP_REG1) {
{
sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
- sljit_s32 needs_move = 0;
sljit_uw op = 0;
CHECK_ERROR();
if (type & SLJIT_SIMD_TEST)
return SLJIT_SUCCESS;
- needs_move = dst_freg != src1_freg && dst_freg != src2_freg;
-
- if (reg_size == 5 || (needs_move && (cpu_feature_list & CPU_FEATURE_AVX2))) {
+ if (reg_size == 5 || ((cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX))) {
if (reg_size == 5)
op |= VEX_256;
return emit_vex_instruction(compiler, op | EX86_SSE2 | VEX_SSE2_OPV, dst_freg, src1_freg, src2_freg, 0);
}
- if (needs_move) {
- FAIL_IF(emit_simd_mov(compiler, type, dst_freg, src1_freg));
- } else if (dst_freg != src1_freg) {
- SLJIT_ASSERT(dst_freg == src2_freg);
- src2_freg = src1_freg;
+ if (dst_freg != src1_freg) {
+ if (dst_freg == src2_freg)
+ src2_freg = src1_freg;
+ else
+ FAIL_IF(emit_simd_mov(compiler, type, dst_freg, src1_freg));
}
FAIL_IF(emit_groupf(compiler, op | EX86_SSE2, dst_freg, src2_freg, 0));
return NULL;
#endif
- inst = (sljit_u8*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1);
PTR_FAIL_IF(!inst);
- inst[0] = 0;
- inst[1] = 2;
+ inst[0] = SLJIT_INST_CONST;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (dst & SLJIT_MEM)
return const_;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
- struct sljit_put_label *put_label;
+ struct sljit_jump *jump;
sljit_u8 *inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
sljit_s32 reg;
- sljit_uw start_size;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+ CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
CHECK_EXTRA_REGS(dst, dstw, (void)0);
- 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);
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_mov_addr(jump, compiler, 0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
- if (emit_load_imm64(compiler, reg, 0))
- return NULL;
-#else
- if (emit_mov(compiler, dst, dstw, SLJIT_IMM, 0))
- return NULL;
-#endif
+ PTR_FAIL_IF(emit_load_imm64(compiler, reg, 0));
+ jump->addr = compiler->size;
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (dst & SLJIT_MEM) {
- start_size = compiler->size;
- if (emit_mov(compiler, dst, dstw, TMP_REG1, 0))
- return NULL;
- put_label->flags = compiler->size - start_size;
- }
-#endif
+ if (reg_map[reg] >= 8)
+ jump->flags |= MOV_ADDR_HI;
+#else /* !SLJIT_CONFIG_X86_64 */
+ PTR_FAIL_IF(emit_mov(compiler, dst, dstw, SLJIT_IMM, 0));
+#endif /* SLJIT_CONFIG_X86_64 */
- inst = (sljit_u8*)ensure_buf(compiler, 2);
+ inst = (sljit_u8*)ensure_buf(compiler, 1);
PTR_FAIL_IF(!inst);
- inst[0] = 0;
- inst[1] = 3;
+ inst[0] = SLJIT_INST_MOV_ADDR;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (dst & SLJIT_MEM)
+ PTR_FAIL_IF(emit_mov(compiler, dst, dstw, TMP_REG1, 0));
+#endif /* SLJIT_CONFIG_X86_64 */
- return put_label;
+ return jump;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
--- /dev/null
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 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 sljit_s32 sljit_jump_has_label(struct sljit_jump *jump)
+{
+ return !(jump->flags & JUMP_ADDR) && (jump->u.label != NULL);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_target(struct sljit_jump *jump)
+{
+ return (jump->flags & JUMP_ADDR) != 0;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_is_mov_addr(struct sljit_jump *jump)
+{
+ return (jump->flags & JUMP_MOV_ADDR) != 0;
+}
+
+#define SLJIT_SERIALIZE_DEBUG ((sljit_u16)0x1)
+
+struct sljit_serialized_compiler {
+ sljit_u32 signature;
+ sljit_u16 version;
+ sljit_u16 cpu_type;
+
+ sljit_uw buf_segment_count;
+ sljit_uw label_count;
+ sljit_uw jump_count;
+ sljit_uw const_count;
+
+ sljit_s32 options;
+ sljit_s32 scratches;
+ sljit_s32 saveds;
+ sljit_s32 fscratches;
+ sljit_s32 fsaveds;
+ sljit_s32 local_size;
+ sljit_uw size;
+
+#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
+ sljit_s32 status_flags_state;
+#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_s32 args_size;
+#endif /* SLJIT_CONFIG_X86_32 */
+
+#if ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \
+ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+ sljit_uw args_size;
+#endif /* (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ sljit_uw cpool_diff;
+ sljit_uw cpool_fill;
+ sljit_uw patches;
+#endif /* SLJIT_CONFIG_ARM_V6 */
+
+#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+ sljit_s32 delay_slot;
+#endif /* SLJIT_CONFIG_MIPS */
+
+};
+
+struct sljit_serialized_debug_info {
+ sljit_sw last_flags;
+ sljit_s32 last_return;
+ sljit_s32 logical_local_size;
+};
+
+struct sljit_serialized_label {
+ sljit_uw size;
+};
+
+struct sljit_serialized_jump {
+ sljit_uw addr;
+ sljit_uw flags;
+ sljit_uw value;
+};
+
+struct sljit_serialized_const {
+ sljit_uw addr;
+};
+
+#define SLJIT_SERIALIZE_ALIGN(v) (((v) + sizeof(sljit_uw) - 1) & ~(sljit_uw)(sizeof(sljit_uw) - 1))
+#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#define SLJIT_SERIALIZE_SIGNATURE 0x534c4a54
+#else /* !SLJIT_LITTLE_ENDIAN */
+#define SLJIT_SERIALIZE_SIGNATURE 0x544a4c53
+#endif /* SLJIT_LITTLE_ENDIAN */
+#define SLJIT_SERIALIZE_VERSION 1
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_uw *size)
+{
+ sljit_uw serialized_size = sizeof(struct sljit_serialized_compiler);
+ struct sljit_memory_fragment *buf;
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+ struct sljit_serialized_compiler *serialized_compiler;
+ struct sljit_serialized_label *serialized_label;
+ struct sljit_serialized_jump *serialized_jump;
+ struct sljit_serialized_const *serialized_const;
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+ || (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ struct sljit_serialized_debug_info *serialized_debug_info;
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
+ sljit_uw counter, used_size;
+ sljit_u8 *result;
+ sljit_u8 *ptr;
+ SLJIT_UNUSED_ARG(options);
+
+ if (size != NULL)
+ *size = 0;
+
+ PTR_FAIL_IF(compiler->error);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+ || (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ if (!(options & SLJIT_SERIALIZE_IGNORE_DEBUG))
+ serialized_size += sizeof(struct sljit_serialized_debug_info);
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ serialized_size += SLJIT_SERIALIZE_ALIGN(compiler->cpool_fill * (sizeof(sljit_uw) + 1));
+#endif /* SLJIT_CONFIG_ARM_V6 */
+
+ /* Compute the size of the data. */
+ buf = compiler->buf;
+ while (buf != NULL) {
+ serialized_size += sizeof(sljit_uw) + SLJIT_SERIALIZE_ALIGN(buf->used_size);
+ buf = buf->next;
+ }
+
+ serialized_size += compiler->label_count * sizeof(struct sljit_serialized_label);
+
+ jump = compiler->jumps;
+ while (jump != NULL) {
+ serialized_size += sizeof(struct sljit_serialized_jump);
+ jump = jump->next;
+ }
+
+ const_ = compiler->consts;
+ while (const_ != NULL) {
+ serialized_size += sizeof(struct sljit_serialized_const);
+ const_ = const_->next;
+ }
+
+ result = (sljit_u8*)SLJIT_MALLOC(serialized_size, compiler->allocator_data);
+ PTR_FAIL_IF_NULL(result);
+
+ if (size != NULL)
+ *size = serialized_size;
+
+ ptr = result;
+ serialized_compiler = (struct sljit_serialized_compiler*)ptr;
+ ptr += sizeof(struct sljit_serialized_compiler);
+
+ serialized_compiler->signature = SLJIT_SERIALIZE_SIGNATURE;
+ serialized_compiler->version = SLJIT_SERIALIZE_VERSION;
+ serialized_compiler->cpu_type = 0;
+ serialized_compiler->label_count = compiler->label_count;
+ serialized_compiler->options = compiler->options;
+ serialized_compiler->scratches = compiler->scratches;
+ serialized_compiler->saveds = compiler->saveds;
+ serialized_compiler->fscratches = compiler->fscratches;
+ serialized_compiler->fsaveds = compiler->fsaveds;
+ serialized_compiler->local_size = compiler->local_size;
+ serialized_compiler->size = compiler->size;
+
+#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
+ serialized_compiler->status_flags_state = compiler->status_flags_state;
+#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+ || ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \
+ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+ serialized_compiler->args_size = compiler->args_size;
+#endif /* SLJIT_CONFIG_X86_32 || (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ serialized_compiler->cpool_diff = compiler->cpool_diff;
+ serialized_compiler->cpool_fill = compiler->cpool_fill;
+ serialized_compiler->patches = compiler->patches;
+
+ SLJIT_MEMCPY(ptr, compiler->cpool, compiler->cpool_fill * sizeof(sljit_uw));
+ SLJIT_MEMCPY(ptr + compiler->cpool_fill * sizeof(sljit_uw), compiler->cpool_unique, compiler->cpool_fill);
+ ptr += SLJIT_SERIALIZE_ALIGN(compiler->cpool_fill * (sizeof(sljit_uw) + 1));
+#endif /* SLJIT_CONFIG_ARM_V6 */
+
+#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+ serialized_compiler->delay_slot = compiler->delay_slot;
+#endif /* SLJIT_CONFIG_MIPS */
+
+ buf = compiler->buf;
+ counter = 0;
+ while (buf != NULL) {
+ used_size = buf->used_size;
+ *(sljit_uw*)ptr = used_size;
+ ptr += sizeof(sljit_uw);
+ SLJIT_MEMCPY(ptr, buf->memory, used_size);
+ ptr += SLJIT_SERIALIZE_ALIGN(used_size);
+ buf = buf->next;
+ counter++;
+ }
+ serialized_compiler->buf_segment_count = counter;
+
+ label = compiler->labels;
+ while (label != NULL) {
+ serialized_label = (struct sljit_serialized_label*)ptr;
+ serialized_label->size = label->size;
+ ptr += sizeof(struct sljit_serialized_label);
+ label = label->next;
+ }
+
+ jump = compiler->jumps;
+ counter = 0;
+ while (jump != NULL) {
+ serialized_jump = (struct sljit_serialized_jump*)ptr;
+ serialized_jump->addr = jump->addr;
+ serialized_jump->flags = jump->flags;
+
+ if (jump->flags & JUMP_ADDR)
+ serialized_jump->value = jump->u.target;
+ else if (jump->u.label != NULL)
+ serialized_jump->value = jump->u.label->u.index;
+ else
+ serialized_jump->value = SLJIT_MAX_ADDRESS;
+
+ ptr += sizeof(struct sljit_serialized_jump);
+ jump = jump->next;
+ counter++;
+ }
+ serialized_compiler->jump_count = counter;
+
+ const_ = compiler->consts;
+ counter = 0;
+ while (const_ != NULL) {
+ serialized_const = (struct sljit_serialized_const*)ptr;
+ serialized_const->addr = const_->addr;
+ ptr += sizeof(struct sljit_serialized_const);
+ const_ = const_->next;
+ counter++;
+ }
+ serialized_compiler->const_count = counter;
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+ || (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ if (!(options & SLJIT_SERIALIZE_IGNORE_DEBUG)) {
+ serialized_debug_info = (struct sljit_serialized_debug_info*)ptr;
+ serialized_debug_info->last_flags = compiler->last_flags;
+ serialized_debug_info->last_return = compiler->last_return;
+ serialized_debug_info->logical_local_size = compiler->logical_local_size;
+ serialized_compiler->cpu_type |= SLJIT_SERIALIZE_DEBUG;
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ ptr += sizeof(struct sljit_serialized_debug_info);
+#endif /* SLJIT_DEBUG */
+ }
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
+
+ SLJIT_ASSERT((sljit_uw)(ptr - result) == serialized_size);
+ return (sljit_uw*)result;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit_uw* buffer, sljit_uw size,
+ sljit_s32 options, void *allocator_data)
+{
+ struct sljit_compiler *compiler;
+ struct sljit_serialized_compiler *serialized_compiler;
+ struct sljit_serialized_label *serialized_label;
+ struct sljit_serialized_jump *serialized_jump;
+ struct sljit_serialized_const *serialized_const;
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+ || (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ struct sljit_serialized_debug_info *serialized_debug_info;
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
+ struct sljit_memory_fragment *buf;
+ struct sljit_memory_fragment *last_buf;
+ struct sljit_label *label;
+ struct sljit_label *last_label;
+ struct sljit_label **label_list = NULL;
+ struct sljit_jump *jump;
+ struct sljit_jump *last_jump;
+ struct sljit_const *const_;
+ struct sljit_const *last_const;
+ sljit_u8 *ptr = (sljit_u8*)buffer;
+ sljit_u8 *end = ptr + size;
+ sljit_uw i, used_size, aligned_size, label_count;
+ SLJIT_UNUSED_ARG(options);
+
+ if (size < sizeof(struct sljit_serialized_compiler) || (size & (sizeof(sljit_uw) - 1)) != 0)
+ return NULL;
+
+ serialized_compiler = (struct sljit_serialized_compiler*)ptr;
+
+ if (serialized_compiler->signature != SLJIT_SERIALIZE_SIGNATURE || serialized_compiler->version != SLJIT_SERIALIZE_VERSION)
+ return NULL;
+
+ compiler = sljit_create_compiler(allocator_data);
+ PTR_FAIL_IF(compiler == NULL);
+
+ compiler->label_count = serialized_compiler->label_count;
+ compiler->options = serialized_compiler->options;
+ compiler->scratches = serialized_compiler->scratches;
+ compiler->saveds = serialized_compiler->saveds;
+ compiler->fscratches = serialized_compiler->fscratches;
+ compiler->fsaveds = serialized_compiler->fsaveds;
+ compiler->local_size = serialized_compiler->local_size;
+ compiler->size = serialized_compiler->size;
+
+#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
+ compiler->status_flags_state = serialized_compiler->status_flags_state;
+#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+ || ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \
+ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+ compiler->args_size = serialized_compiler->args_size;
+#endif /* SLJIT_CONFIG_X86_32 || (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ used_size = serialized_compiler->cpool_fill;
+ aligned_size = SLJIT_SERIALIZE_ALIGN(used_size * (sizeof(sljit_uw) + 1));
+ compiler->cpool_diff = serialized_compiler->cpool_diff;
+ compiler->cpool_fill = used_size;
+ compiler->patches = serialized_compiler->patches;
+
+ if ((sljit_uw)(end - ptr) < aligned_size)
+ goto error;
+
+ SLJIT_MEMCPY(compiler->cpool, ptr, used_size * sizeof(sljit_uw));
+ SLJIT_MEMCPY(compiler->cpool_unique, ptr + used_size * sizeof(sljit_uw), used_size);
+ ptr += aligned_size;
+#endif /* SLJIT_CONFIG_ARM_V6 */
+
+#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+ compiler->delay_slot = serialized_compiler->delay_slot;
+#endif /* SLJIT_CONFIG_MIPS */
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+ || (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ if (!(serialized_compiler->cpu_type & SLJIT_SERIALIZE_DEBUG))
+ goto error;
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
+
+ ptr += sizeof(struct sljit_serialized_compiler);
+ i = serialized_compiler->buf_segment_count;
+ last_buf = NULL;
+ while (i > 0) {
+ if ((sljit_uw)(end - ptr) < sizeof(sljit_uw))
+ goto error;
+
+ used_size = *(sljit_uw*)ptr;
+ aligned_size = SLJIT_SERIALIZE_ALIGN(used_size);
+ ptr += sizeof(sljit_uw);
+
+ if ((sljit_uw)(end - ptr) < aligned_size)
+ goto error;
+
+ if (last_buf == NULL) {
+ SLJIT_ASSERT(compiler->buf != NULL && compiler->buf->next == NULL);
+ buf = compiler->buf;
+ } else {
+ buf = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, allocator_data);
+ if (!buf)
+ goto error;
+ buf->next = NULL;
+ }
+
+ buf->used_size = used_size;
+ SLJIT_MEMCPY(buf->memory, ptr, used_size);
+
+ if (last_buf != NULL)
+ last_buf->next = buf;
+ last_buf = buf;
+
+ ptr += aligned_size;
+ i--;
+ }
+
+ last_label = NULL;
+ label_count = serialized_compiler->label_count;
+ if ((sljit_uw)(end - ptr) < label_count * sizeof(struct sljit_serialized_label))
+ goto error;
+
+ label_list = (struct sljit_label **)SLJIT_MALLOC(label_count * sizeof(struct sljit_label*), allocator_data);
+ if (label_list == NULL)
+ goto error;
+
+ for (i = 0; i < label_count; i++) {
+ label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+ if (label == NULL)
+ goto error;
+
+ serialized_label = (struct sljit_serialized_label*)ptr;
+ label->next = NULL;
+ label->u.index = i;
+ label->size = serialized_label->size;
+
+ if (last_label != NULL)
+ last_label->next = label;
+ else
+ compiler->labels = label;
+ last_label = label;
+
+ label_list[i] = label;
+ ptr += sizeof(struct sljit_serialized_label);
+ }
+ compiler->last_label = last_label;
+
+ last_jump = NULL;
+ i = serialized_compiler->jump_count;
+ if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_jump))
+ goto error;
+
+ while (i > 0) {
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ if (jump == NULL)
+ goto error;
+
+ serialized_jump = (struct sljit_serialized_jump*)ptr;
+ jump->next = NULL;
+ jump->addr = serialized_jump->addr;
+ jump->flags = serialized_jump->flags;
+
+ if (!(serialized_jump->flags & JUMP_ADDR)) {
+ if (serialized_jump->value != SLJIT_MAX_ADDRESS) {
+ if (serialized_jump->value >= label_count)
+ goto error;
+ jump->u.label = label_list[serialized_jump->value];
+ } else
+ jump->u.label = NULL;
+ } else
+ jump->u.target = serialized_jump->value;
+
+ if (last_jump != NULL)
+ last_jump->next = jump;
+ else
+ compiler->jumps = jump;
+ last_jump = jump;
+
+ ptr += sizeof(struct sljit_serialized_jump);
+ i--;
+ }
+ compiler->last_jump = last_jump;
+
+ SLJIT_FREE(label_list, allocator_data);
+ label_list = NULL;
+
+ last_const = NULL;
+ i = serialized_compiler->const_count;
+ if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_const))
+ goto error;
+
+ while (i > 0) {
+ const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+ if (const_ == NULL)
+ goto error;
+
+ serialized_const = (struct sljit_serialized_const*)ptr;
+ const_->next = NULL;
+ const_->addr = serialized_const->addr;
+
+ if (last_const != NULL)
+ last_const->next = const_;
+ else
+ compiler->consts = const_;
+ last_const = const_;
+
+ ptr += sizeof(struct sljit_serialized_const);
+ i--;
+ }
+ compiler->last_const = last_const;
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+ || (defined SLJIT_DEBUG && SLJIT_DEBUG)
+ if ((sljit_uw)(end - ptr) < sizeof(struct sljit_serialized_debug_info))
+ goto error;
+
+ serialized_debug_info = (struct sljit_serialized_debug_info*)ptr;
+ compiler->last_flags = (sljit_s32)serialized_debug_info->last_flags;
+ compiler->last_return = serialized_debug_info->last_return;
+ compiler->logical_local_size = serialized_debug_info->logical_local_size;
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
+
+ return compiler;
+
+error:
+ sljit_free_compiler(compiler);
+ if (label_list != NULL)
+ SLJIT_FREE(label_list, allocator_data);
+ return NULL;
+}
# Check name length with non-ASCII characters
-/(?'ABáC678901234567890123456789012'...)/utf
+/(?'ABáC678901234567890123456789012012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf
-/(?'ABáC6789012345678901234567890123'...)/utf
+/(?'ABáC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf
-/(?'ABZC6789012345678901234567890123'...)/utf
+/(?'ABZC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf
/(?(n/utf
/(?<=\K.)/g,replace=-,allow_lookaround_bsk
ab
-/(?'abcdefghijklmnopqrstuvwxyzABCDEFG'toolong)/
+/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFGH'toolong)/
-/(?'abcdefghijklmnopqrstuvwxyzABCDEF'justright)/
+/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFG'justright)/
# These two use zero-termination
/abcd/max_pattern_length=3
/abcdef/hex,max_pattern_length=3
+# Test compiled length limit
+/(abcdefg){10}/max_pattern_compiled_length=100
+
# These patterns used to take a long time to compile
"(.*)
/{\84Í\84ÍÍ\84Í{'{22{2{{2{'{22{\12{22{2{'{22{2{{2{{222{{2{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{222{2Ä\84Í\84ÍÍ\84Í{'{22{2{{2{'{22{\12{11{2{'{22{2{{2{{'{22{2{{2{'{22{\12{22{1{'{22{2{{2{{222{{2{'{22{2{22{2{'{/auto_callout
//
-\=get=i00000000000000000000000000000000
+\=get=i00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
\=get=i2345678901234567890123456789012,get=i1245678901234567890123456789012
"(?(?C))"
/(a(?1)z||(?1)++)$/
abcd\=disable_recurseloop_check
+/(((?<=123?456456|ABC)))(?<=\2)../
+ ABCDEFG
+ 12345645678910
+
+# This test is crashing Perl 5.38.2.
+
+/[^\S\W]{6}/
+ .abc def..
+
# End of testinput2
\x0a\x{1b04}LF, spacingmark
\x0b\x{0711}Control, extend
\x09\x{1b04}Control, spacingmark
+ *Test Extended Pictographic after bug fix
+ \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic
+ \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P
+ \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P
+ \x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}\x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}
+ A\x{200d}\x{1f308}B
+ A\x{200d}B A ZWJ
+ \x{261D}\x{1F3FB}B Extended_Pictographic Extend
+ \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator
*There are no Prepend characters, so we can't test Prepend, CR
/^(?>\X{2})X/utf,aftertext
(\p{Medefaidrin}+)(\p{Old_Sogdian}+)(\p{Sogdian}+)/x,utf
\x{11800}\x{11da9}\x{10d27}\x{11ee0}\x{16e48}\x{10f27}\x{10f30}
-# These two are here because of differences from Perl.
-
-/^\X/utf
- A\x{200d}B A ZWJ
- \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic
- \x{261D}\x{1F3FB}B Extended_Pictographic Extend
- \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator
- \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P
- \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P
-
# Regional indicators
/^(\X)(\X)/utf,aftertext
# Check name length with non-ASCII characters
-/(?'ABáC678901234567890123456789012'...)/utf
+/(?'ABáC678901234567890123456789012012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf
-/(?'ABáC6789012345678901234567890123'...)/utf
-Failed: error 148 at offset 36: subpattern name is too long (maximum 32 code units)
+/(?'ABáC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf
+Failed: error 148 at offset 132: subpattern name is too long (maximum 128 code units)
-/(?'ABZC6789012345678901234567890123'...)/utf
+/(?'ABZC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf
/(?(n/utf
Failed: error 142 at offset 4: syntax error in subpattern name (missing terminator?)
# are different without JIT.
/abc/I,jit,jitverify
+JIT compilation was not successful (bad JIT option)
Capture group count = 0
First code unit = 'a'
Last code unit = 'c'
# JIT does not support this pattern (callout at start of condition).
/(?(?C1)(?=a)a)/I
+JIT compilation was not successful (no more memory)
Capture group count = 0
May match empty string
Subject length lower bound = 0
# The following pattern cannot be compiled by JIT.
/b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*/I
+JIT compilation was not successful (no more memory)
Capture group count = 0
May match empty string
Subject length lower bound = 0
ab
Failed: error -60: match with end before start or start moved backwards is not supported
-/(?'abcdefghijklmnopqrstuvwxyzABCDEFG'toolong)/
-Failed: error 148 at offset 36: subpattern name is too long (maximum 32 code units)
+/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFGH'toolong)/
+Failed: error 148 at offset 132: subpattern name is too long (maximum 128 code units)
-/(?'abcdefghijklmnopqrstuvwxyzABCDEF'justright)/
+/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFG'justright)/
# These two use zero-termination
/abcd/max_pattern_length=3
/abcdef/hex,max_pattern_length=3
+# Test compiled length limit
+/(abcdefg){10}/max_pattern_compiled_length=100
+Failed: error 201 at offset 13: compiled pattern would be longer than the limit set by the application
+
# These patterns used to take a long time to compile
"(.*)
/{\84Í\84ÍÍ\84Í{'{22{2{{2{'{22{\12{22{2{'{22{2{{2{{222{{2{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{222{2Ä\84Í\84ÍÍ\84Í{'{22{2{{2{'{22{\12{11{2{'{22{2{{2{{'{22{2{{2{'{22{\12{22{1{'{22{2{{2{{222{{2{'{22{2{22{2{'{/auto_callout
//
-\=get=i00000000000000000000000000000000
+\=get=i00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
** Group name in 'get' is too long
\=get=i2345678901234567890123456789012,get=i1245678901234567890123456789012
** Too many characters in named 'get' modifiers
0:
1:
+/(((?<=123?456456|ABC)))(?<=\2)../
+ ABCDEFG
+ 0: DE
+ 1:
+ 2:
+ 12345645678910
+ 0: 78
+ 1:
+ 2:
+
+# This test is crashing Perl 5.38.2.
+
+/[^\S\W]{6}/
+ .abc def..
+No match
+
# End of testinput2
Error -70: PCRE2_ERROR_BADDATA (unknown error number)
Error -62: bad serialized data
\x09\x{1b04}Control, spacingmark
0: \x{09}
0+ \x{1b04}Control, spacingmark
+ *Test Extended Pictographic after bug fix
+ 0: *
+ 0+ Test Extended Pictographic after bug fix
+ \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic
+ 0: \x{261d}
+ 0+ \x{261d}B Extended_Pictographic Extended_Pictographic
+ \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P
+ 0: \x{261d}\x{1f3fb}
+ 0+ \x{261d}B Extended_Pictographic Extend E-P
+ \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P
+ 0: \x{261d}\x{1f3fb}\x{200d}\x{261d}
+ 0+ B Extended_Pictographic Extend ZWJ E-P
+ \x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}\x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}
+ 0: \x{1f3f3}\x{fe0f}\x{200d}\x{1f308}
+ 0+ \x{1f3f4}\x{200d}\x{2620}\x{fe0f}\x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}
+ A\x{200d}\x{1f308}B
+ 0: A\x{200d}
+ 0+ \x{1f308}B
+ A\x{200d}B A ZWJ
+ 0: A\x{200d}
+ 0+ B A ZWJ
+ \x{261D}\x{1F3FB}B Extended_Pictographic Extend
+ 0: \x{261d}\x{1f3fb}
+ 0+ B Extended_Pictographic Extend
+ \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator
+ 0: \x{1f1e6}\x{1f1e7}
+ 0+ B RegionalIndicator RegionalIndicator
*There are no Prepend characters, so we can't test Prepend, CR
0: *
0+ There are no Prepend characters, so we can't test Prepend, CR
6: \x{10f27}
7: \x{10f30}
-# These two are here because of differences from Perl.
-
-/^\X/utf
- A\x{200d}B A ZWJ
- 0: A\x{200d}
- \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic
- 0: \x{261d}\x{261d}
- \x{261D}\x{1F3FB}B Extended_Pictographic Extend
- 0: \x{261d}\x{1f3fb}
- \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator
- 0: \x{1f1e6}\x{1f1e7}
- \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P
- 0: \x{261d}\x{1f3fb}\x{261d}
- \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P
- 0: \x{261d}\x{1f3fb}\x{200d}\x{261d}
-
# Regional indicators
/^(\X)(\X)/utf,aftertext
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 5 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 38
+Memory allocation - compiled block : 174
+Memory allocation - code portion : 38
------------------------------------------------------------------
0 16 Bra
2 7 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 36
+Memory allocation - compiled block : 172
+Memory allocation - code portion : 36
------------------------------------------------------------------
0 15 Bra
2 6 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 46
+Memory allocation - compiled block : 182
+Memory allocation - code portion : 46
------------------------------------------------------------------
0 20 Bra
2 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 2 Bra
2 2 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 7 Bra
2 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 10 Bra
2 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 142
+Memory allocation - compiled block : 278
+Memory allocation - code portion : 142
------------------------------------------------------------------
0 68 Bra
2 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 1648
+Memory allocation - compiled block : 1784
+Memory allocation - code portion : 1648
------------------------------------------------------------------
0 821 Bra
2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 1628
+Memory allocation - compiled block : 1764
+Memory allocation - code portion : 1628
------------------------------------------------------------------
0 811 Bra
2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 13 Bra
2 9 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 40
+Memory allocation - compiled block : 176
+Memory allocation - code portion : 40
------------------------------------------------------------------
0 17 Bra
2 13 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 54
+Memory allocation - compiled block : 242
+Memory allocation - code portion : 54
------------------------------------------------------------------
0 24 Bra
2 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 64
+Memory allocation - compiled block : 218
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 29 Bra
2 18 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 54
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 54
------------------------------------------------------------------
0 24 Bra
2 5 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 50
+Memory allocation - compiled block : 186
+Memory allocation - code portion : 50
------------------------------------------------------------------
0 22 Bra
2 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 78
+Memory allocation - compiled block : 214
+Memory allocation - code portion : 78
------------------------------------------------------------------
0 36 Bra
2 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 16
+Memory allocation - compiled block : 152
+Memory allocation - code portion : 16
------------------------------------------------------------------
0 5 Bra
2 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 16
+Memory allocation - compiled block : 152
+Memory allocation - code portion : 16
------------------------------------------------------------------
0 5 Bra
2 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 16
+Memory allocation - compiled block : 152
+Memory allocation - code portion : 16
------------------------------------------------------------------
0 5 Bra
2 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 10 Bra
2 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 22
+Memory allocation - compiled block : 158
+Memory allocation - code portion : 22
------------------------------------------------------------------
0 8 Bra
2 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 22
+Memory allocation - compiled block : 158
+Memory allocation - code portion : 22
------------------------------------------------------------------
0 8 Bra
2 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 54
+Memory allocation - compiled block : 190
+Memory allocation - code portion : 54
------------------------------------------------------------------
0 24 Bra
2 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 10 Bra
2 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 10 Bra
2 ^
Failed: error 106 at offset 13: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 27 Bra
2 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 58
+Memory allocation - compiled block : 194
+Memory allocation - code portion : 58
------------------------------------------------------------------
0 26 Bra
2 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 13 Bra
2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 13 Bra
2 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 9 Bra
2 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 23 Bra
2 19 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 42
+Memory allocation - compiled block : 178
+Memory allocation - code portion : 42
------------------------------------------------------------------
0 18 Bra
2 14 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 12 Bra
3 6 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 20 Bra
3 8 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 46
+Memory allocation - compiled block : 182
+Memory allocation - code portion : 46
------------------------------------------------------------------
0 19 Bra
3 7 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 50
+Memory allocation - compiled block : 186
+Memory allocation - code portion : 50
------------------------------------------------------------------
0 21 Bra
3 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 3 Bra
3 3 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 8 Bra
3 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 34
+Memory allocation - compiled block : 170
+Memory allocation - code portion : 34
------------------------------------------------------------------
0 13 Bra
3 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 166
+Memory allocation - compiled block : 302
+Memory allocation - code portion : 166
------------------------------------------------------------------
0 79 Bra
3 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 1652
+Memory allocation - compiled block : 1788
+Memory allocation - code portion : 1652
------------------------------------------------------------------
0 822 Bra
3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 1632
+Memory allocation - compiled block : 1768
+Memory allocation - code portion : 1632
------------------------------------------------------------------
0 812 Bra
3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 42
+Memory allocation - compiled block : 178
+Memory allocation - code portion : 42
------------------------------------------------------------------
0 17 Bra
3 11 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 54
+Memory allocation - compiled block : 190
+Memory allocation - code portion : 54
------------------------------------------------------------------
0 23 Bra
3 17 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 68
+Memory allocation - compiled block : 256
+Memory allocation - code portion : 68
------------------------------------------------------------------
0 30 Bra
3 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 84
+Memory allocation - compiled block : 238
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 38 Bra
3 23 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 64
+Memory allocation - compiled block : 206
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 28 Bra
3 6 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 62
+Memory allocation - compiled block : 198
+Memory allocation - code portion : 62
------------------------------------------------------------------
0 27 Bra
3 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 106
+Memory allocation - compiled block : 242
+Memory allocation - code portion : 106
------------------------------------------------------------------
0 49 Bra
3 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 6 Bra
3 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 6 Bra
3 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 6 Bra
3 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 9 Bra
3 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 9 Bra
3 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 26 Bra
3 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 12 Bra
3 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 12 Bra
3 ^
Failed: error 106 at offset 13: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 66
+Memory allocation - compiled block : 202
+Memory allocation - code portion : 66
------------------------------------------------------------------
0 29 Bra
3 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 64
+Memory allocation - compiled block : 200
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 28 Bra
3 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 36
+Memory allocation - compiled block : 172
+Memory allocation - code portion : 36
------------------------------------------------------------------
0 14 Bra
3 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 36
+Memory allocation - compiled block : 172
+Memory allocation - code portion : 36
------------------------------------------------------------------
0 14 Bra
3 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 70
+Memory allocation - compiled block : 206
+Memory allocation - code portion : 70
------------------------------------------------------------------
0 31 Bra
3 25 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 56
+Memory allocation - compiled block : 192
+Memory allocation - code portion : 56
------------------------------------------------------------------
0 24 Bra
3 18 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 12 Bra
3 6 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 20 Bra
3 8 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 46
+Memory allocation - compiled block : 182
+Memory allocation - code portion : 46
------------------------------------------------------------------
0 19 Bra
3 7 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 50
+Memory allocation - compiled block : 186
+Memory allocation - code portion : 50
------------------------------------------------------------------
0 21 Bra
3 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 3 Bra
3 3 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 8 Bra
3 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 34
+Memory allocation - compiled block : 170
+Memory allocation - code portion : 34
------------------------------------------------------------------
0 13 Bra
3 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 166
+Memory allocation - compiled block : 302
+Memory allocation - code portion : 166
------------------------------------------------------------------
0 79 Bra
3 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 1652
+Memory allocation - compiled block : 1788
+Memory allocation - code portion : 1652
------------------------------------------------------------------
0 822 Bra
3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 1632
+Memory allocation - compiled block : 1768
+Memory allocation - code portion : 1632
------------------------------------------------------------------
0 812 Bra
3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 42
+Memory allocation - compiled block : 178
+Memory allocation - code portion : 42
------------------------------------------------------------------
0 17 Bra
3 11 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 54
+Memory allocation - compiled block : 190
+Memory allocation - code portion : 54
------------------------------------------------------------------
0 23 Bra
3 17 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 68
+Memory allocation - compiled block : 256
+Memory allocation - code portion : 68
------------------------------------------------------------------
0 30 Bra
3 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 84
+Memory allocation - compiled block : 238
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 38 Bra
3 23 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 64
+Memory allocation - compiled block : 206
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 28 Bra
3 6 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 62
+Memory allocation - compiled block : 198
+Memory allocation - code portion : 62
------------------------------------------------------------------
0 27 Bra
3 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 106
+Memory allocation - compiled block : 242
+Memory allocation - code portion : 106
------------------------------------------------------------------
0 49 Bra
3 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 6 Bra
3 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 6 Bra
3 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 6 Bra
3 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 9 Bra
3 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 9 Bra
3 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 26 Bra
3 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 12 Bra
3 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 12 Bra
3 ^
Failed: error 106 at offset 13: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 66
+Memory allocation - compiled block : 202
+Memory allocation - code portion : 66
------------------------------------------------------------------
0 29 Bra
3 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 64
+Memory allocation - compiled block : 200
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 28 Bra
3 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 36
+Memory allocation - compiled block : 172
+Memory allocation - code portion : 36
------------------------------------------------------------------
0 14 Bra
3 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 36
+Memory allocation - compiled block : 172
+Memory allocation - code portion : 36
------------------------------------------------------------------
0 14 Bra
3 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 11 Bra
3 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 70
+Memory allocation - compiled block : 206
+Memory allocation - code portion : 70
------------------------------------------------------------------
0 31 Bra
3 25 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 56
+Memory allocation - compiled block : 192
+Memory allocation - code portion : 56
------------------------------------------------------------------
0 24 Bra
3 18 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 5 Bra
3 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 5 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 76
+Memory allocation - compiled block : 212
+Memory allocation - code portion : 76
------------------------------------------------------------------
0 16 Bra
2 7 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 72
+Memory allocation - compiled block : 208
+Memory allocation - code portion : 72
------------------------------------------------------------------
0 15 Bra
2 6 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 2 Bra
2 2 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 40
+Memory allocation - compiled block : 176
+Memory allocation - code portion : 40
------------------------------------------------------------------
0 7 Bra
2 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 220
+Memory allocation - compiled block : 356
+Memory allocation - code portion : 220
------------------------------------------------------------------
0 52 Bra
2 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 3296
+Memory allocation - compiled block : 3432
+Memory allocation - code portion : 3296
------------------------------------------------------------------
0 821 Bra
2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 3256
+Memory allocation - compiled block : 3392
+Memory allocation - code portion : 3256
------------------------------------------------------------------
0 811 Bra
2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 64
+Memory allocation - compiled block : 200
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 13 Bra
2 9 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 80
+Memory allocation - compiled block : 216
+Memory allocation - code portion : 80
------------------------------------------------------------------
0 17 Bra
2 13 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 108
+Memory allocation - compiled block : 348
+Memory allocation - code portion : 108
------------------------------------------------------------------
0 24 Bra
2 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 128
+Memory allocation - compiled block : 300
+Memory allocation - code portion : 128
------------------------------------------------------------------
0 29 Bra
2 18 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 108
+Memory allocation - compiled block : 256
+Memory allocation - code portion : 108
------------------------------------------------------------------
0 24 Bra
2 5 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 100
+Memory allocation - compiled block : 236
+Memory allocation - code portion : 100
------------------------------------------------------------------
0 22 Bra
2 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 156
+Memory allocation - compiled block : 292
+Memory allocation - code portion : 156
------------------------------------------------------------------
0 36 Bra
2 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 8 Bra
2 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 8 Bra
2 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 76
+Memory allocation - compiled block : 212
+Memory allocation - code portion : 76
------------------------------------------------------------------
0 16 Bra
2 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 ^
Failed: error 106 at offset 13: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 88
+Memory allocation - compiled block : 224
+Memory allocation - code portion : 88
------------------------------------------------------------------
0 19 Bra
2 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 84
+Memory allocation - compiled block : 220
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 18 Bra
2 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 104
+Memory allocation - compiled block : 240
+Memory allocation - code portion : 104
------------------------------------------------------------------
0 23 Bra
2 19 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 84
+Memory allocation - compiled block : 220
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 18 Bra
2 14 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 5 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 76
+Memory allocation - compiled block : 212
+Memory allocation - code portion : 76
------------------------------------------------------------------
0 16 Bra
2 7 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 72
+Memory allocation - compiled block : 208
+Memory allocation - code portion : 72
------------------------------------------------------------------
0 15 Bra
2 6 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 2 Bra
2 2 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 40
+Memory allocation - compiled block : 176
+Memory allocation - code portion : 40
------------------------------------------------------------------
0 7 Bra
2 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 220
+Memory allocation - compiled block : 356
+Memory allocation - code portion : 220
------------------------------------------------------------------
0 52 Bra
2 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 3296
+Memory allocation - compiled block : 3432
+Memory allocation - code portion : 3296
------------------------------------------------------------------
0 821 Bra
2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 3256
+Memory allocation - compiled block : 3392
+Memory allocation - code portion : 3256
------------------------------------------------------------------
0 811 Bra
2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 64
+Memory allocation - compiled block : 200
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 13 Bra
2 9 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 80
+Memory allocation - compiled block : 216
+Memory allocation - code portion : 80
------------------------------------------------------------------
0 17 Bra
2 13 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 108
+Memory allocation - compiled block : 348
+Memory allocation - code portion : 108
------------------------------------------------------------------
0 24 Bra
2 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 128
+Memory allocation - compiled block : 300
+Memory allocation - code portion : 128
------------------------------------------------------------------
0 29 Bra
2 18 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 108
+Memory allocation - compiled block : 256
+Memory allocation - code portion : 108
------------------------------------------------------------------
0 24 Bra
2 5 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 100
+Memory allocation - compiled block : 236
+Memory allocation - code portion : 100
------------------------------------------------------------------
0 22 Bra
2 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 156
+Memory allocation - compiled block : 292
+Memory allocation - code portion : 156
------------------------------------------------------------------
0 36 Bra
2 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 8 Bra
2 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 8 Bra
2 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 76
+Memory allocation - compiled block : 212
+Memory allocation - code portion : 76
------------------------------------------------------------------
0 16 Bra
2 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 ^
Failed: error 106 at offset 13: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 88
+Memory allocation - compiled block : 224
+Memory allocation - code portion : 88
------------------------------------------------------------------
0 19 Bra
2 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 84
+Memory allocation - compiled block : 220
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 18 Bra
2 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 104
+Memory allocation - compiled block : 240
+Memory allocation - code portion : 104
------------------------------------------------------------------
0 23 Bra
2 19 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 84
+Memory allocation - compiled block : 220
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 18 Bra
2 14 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 5 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 76
+Memory allocation - compiled block : 212
+Memory allocation - code portion : 76
------------------------------------------------------------------
0 16 Bra
2 7 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 72
+Memory allocation - compiled block : 208
+Memory allocation - code portion : 72
------------------------------------------------------------------
0 15 Bra
2 6 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 2 Bra
2 2 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 40
+Memory allocation - compiled block : 176
+Memory allocation - code portion : 40
------------------------------------------------------------------
0 7 Bra
2 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 220
+Memory allocation - compiled block : 356
+Memory allocation - code portion : 220
------------------------------------------------------------------
0 52 Bra
2 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 3296
+Memory allocation - compiled block : 3432
+Memory allocation - code portion : 3296
------------------------------------------------------------------
0 821 Bra
2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 3256
+Memory allocation - compiled block : 3392
+Memory allocation - code portion : 3256
------------------------------------------------------------------
0 811 Bra
2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 64
+Memory allocation - compiled block : 200
+Memory allocation - code portion : 64
------------------------------------------------------------------
0 13 Bra
2 9 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 80
+Memory allocation - compiled block : 216
+Memory allocation - code portion : 80
------------------------------------------------------------------
0 17 Bra
2 13 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 108
+Memory allocation - compiled block : 348
+Memory allocation - code portion : 108
------------------------------------------------------------------
0 24 Bra
2 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 128
+Memory allocation - compiled block : 300
+Memory allocation - code portion : 128
------------------------------------------------------------------
0 29 Bra
2 18 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 108
+Memory allocation - compiled block : 256
+Memory allocation - code portion : 108
------------------------------------------------------------------
0 24 Bra
2 5 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 100
+Memory allocation - compiled block : 236
+Memory allocation - code portion : 100
------------------------------------------------------------------
0 22 Bra
2 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 156
+Memory allocation - compiled block : 292
+Memory allocation - code portion : 156
------------------------------------------------------------------
0 36 Bra
2 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 8 Bra
2 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 8 Bra
2 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 76
+Memory allocation - compiled block : 212
+Memory allocation - code portion : 76
------------------------------------------------------------------
0 16 Bra
2 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 52
+Memory allocation - compiled block : 188
+Memory allocation - code portion : 52
------------------------------------------------------------------
0 10 Bra
2 ^
Failed: error 106 at offset 13: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 88
+Memory allocation - compiled block : 224
+Memory allocation - code portion : 88
------------------------------------------------------------------
0 19 Bra
2 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 84
+Memory allocation - compiled block : 220
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 18 Bra
2 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 60
+Memory allocation - compiled block : 196
+Memory allocation - code portion : 60
------------------------------------------------------------------
0 12 Bra
2 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 9 Bra
2 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 104
+Memory allocation - compiled block : 240
+Memory allocation - code portion : 104
------------------------------------------------------------------
0 23 Bra
2 19 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 84
+Memory allocation - compiled block : 220
+Memory allocation - code portion : 84
------------------------------------------------------------------
0 18 Bra
2 14 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 4 Bra
2 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 17
+Memory allocation - compiled block : 153
+Memory allocation - code portion : 17
------------------------------------------------------------------
0 13 Bra
3 7 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 25
+Memory allocation - compiled block : 161
+Memory allocation - code portion : 25
------------------------------------------------------------------
0 21 Bra
3 9 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 23
+Memory allocation - compiled block : 159
+Memory allocation - code portion : 23
------------------------------------------------------------------
0 19 Bra
3 7 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 41
+Memory allocation - compiled block : 177
+Memory allocation - code portion : 41
------------------------------------------------------------------
0 37 Bra
3 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 7
+Memory allocation - compiled block : 143
+Memory allocation - code portion : 7
------------------------------------------------------------------
0 3 Bra
3 3 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 9 Bra
3 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 14 Bra
3 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 120
+Memory allocation - compiled block : 256
+Memory allocation - code portion : 120
------------------------------------------------------------------
0 116 Bra
3 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 826
+Memory allocation - compiled block : 962
+Memory allocation - code portion : 826
------------------------------------------------------------------
0 822 Bra
3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 816
+Memory allocation - compiled block : 952
+Memory allocation - code portion : 816
------------------------------------------------------------------
0 812 Bra
3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 22
+Memory allocation - compiled block : 158
+Memory allocation - code portion : 22
------------------------------------------------------------------
0 18 Bra
3 12 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 24 Bra
3 18 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 36
+Memory allocation - compiled block : 200
+Memory allocation - code portion : 36
------------------------------------------------------------------
0 32 Bra
3 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 45
+Memory allocation - compiled block : 193
+Memory allocation - code portion : 45
------------------------------------------------------------------
0 41 Bra
3 25 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 34
+Memory allocation - compiled block : 174
+Memory allocation - code portion : 34
------------------------------------------------------------------
0 30 Bra
3 7 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 31
+Memory allocation - compiled block : 167
+Memory allocation - code portion : 31
------------------------------------------------------------------
0 27 Bra
3 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 53
+Memory allocation - compiled block : 189
+Memory allocation - code portion : 53
------------------------------------------------------------------
0 49 Bra
3 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 7 Bra
3 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 8 Bra
3 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 8 Bra
3 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 8 Bra
3 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 14 Bra
3 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 19
+Memory allocation - compiled block : 155
+Memory allocation - code portion : 19
------------------------------------------------------------------
0 15 Bra
3 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 19
+Memory allocation - compiled block : 155
+Memory allocation - code portion : 19
------------------------------------------------------------------
0 15 Bra
3 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 47
+Memory allocation - compiled block : 183
+Memory allocation - code portion : 47
------------------------------------------------------------------
0 43 Bra
3 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 14 Bra
3 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 14 Bra
3 ^
Failed: error 106 at offset 15: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 11 Bra
3 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 11 Bra
3 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 11 Bra
3 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 11 Bra
3 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 50
+Memory allocation - compiled block : 186
+Memory allocation - code portion : 50
------------------------------------------------------------------
0 46 Bra
3 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 11 Bra
3 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 48
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 48
------------------------------------------------------------------
0 44 Bra
3 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 25
+Memory allocation - compiled block : 161
+Memory allocation - code portion : 25
------------------------------------------------------------------
0 21 Bra
3 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 25
+Memory allocation - compiled block : 161
+Memory allocation - code portion : 25
------------------------------------------------------------------
0 21 Bra
3 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 17
+Memory allocation - compiled block : 153
+Memory allocation - code portion : 17
------------------------------------------------------------------
0 13 Bra
3 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 38
+Memory allocation - compiled block : 174
+Memory allocation - code portion : 38
------------------------------------------------------------------
0 34 Bra
3 28 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 26 Bra
3 20 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 5 Bra
3 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 10
+Memory allocation - compiled block : 146
+Memory allocation - code portion : 10
------------------------------------------------------------------
0 6 Bra
3 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 16 Bra
4 8 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 30
+Memory allocation - compiled block : 166
+Memory allocation - code portion : 30
------------------------------------------------------------------
0 25 Bra
4 10 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 28
+Memory allocation - compiled block : 164
+Memory allocation - code portion : 28
------------------------------------------------------------------
0 23 Bra
4 8 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 43
+Memory allocation - compiled block : 179
+Memory allocation - code portion : 43
------------------------------------------------------------------
0 38 Bra
4 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 9
+Memory allocation - compiled block : 145
+Memory allocation - code portion : 9
------------------------------------------------------------------
0 4 Bra
4 4 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 10 Bra
4 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 22
+Memory allocation - compiled block : 158
+Memory allocation - code portion : 22
------------------------------------------------------------------
0 17 Bra
4 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 132
+Memory allocation - compiled block : 268
+Memory allocation - code portion : 132
------------------------------------------------------------------
0 127 Bra
4 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 828
+Memory allocation - compiled block : 964
+Memory allocation - code portion : 828
------------------------------------------------------------------
0 823 Bra
4 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 818
+Memory allocation - compiled block : 954
+Memory allocation - code portion : 818
------------------------------------------------------------------
0 813 Bra
4 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 27
+Memory allocation - compiled block : 163
+Memory allocation - code portion : 27
------------------------------------------------------------------
0 22 Bra
4 14 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 35
+Memory allocation - compiled block : 171
+Memory allocation - code portion : 35
------------------------------------------------------------------
0 30 Bra
4 22 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 43
+Memory allocation - compiled block : 207
+Memory allocation - code portion : 43
------------------------------------------------------------------
0 38 Bra
4 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 55
+Memory allocation - compiled block : 203
+Memory allocation - code portion : 55
------------------------------------------------------------------
0 50 Bra
4 30 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 39
+Memory allocation - compiled block : 179
+Memory allocation - code portion : 39
------------------------------------------------------------------
0 34 Bra
4 8 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 37
+Memory allocation - compiled block : 173
+Memory allocation - code portion : 37
------------------------------------------------------------------
0 32 Bra
4 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 67
+Memory allocation - compiled block : 203
+Memory allocation - code portion : 67
------------------------------------------------------------------
0 62 Bra
4 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 8 Bra
4 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 9 Bra
4 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 9 Bra
4 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 9 Bra
4 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 15 Bra
4 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 16 Bra
4 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 16 Bra
4 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 50
+Memory allocation - compiled block : 186
+Memory allocation - code portion : 50
------------------------------------------------------------------
0 45 Bra
4 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 16 Bra
4 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 16 Bra
4 ^
Failed: error 106 at offset 15: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 13 Bra
4 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 13 Bra
4 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 13 Bra
4 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 13 Bra
4 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 53
+Memory allocation - compiled block : 189
+Memory allocation - code portion : 53
------------------------------------------------------------------
0 48 Bra
4 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 18
+Memory allocation - compiled block : 154
+Memory allocation - code portion : 18
------------------------------------------------------------------
0 13 Bra
4 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 51
+Memory allocation - compiled block : 187
+Memory allocation - code portion : 51
------------------------------------------------------------------
0 46 Bra
4 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 27
+Memory allocation - compiled block : 163
+Memory allocation - code portion : 27
------------------------------------------------------------------
0 22 Bra
4 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 27
+Memory allocation - compiled block : 163
+Memory allocation - code portion : 27
------------------------------------------------------------------
0 22 Bra
4 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 20
+Memory allocation - compiled block : 156
+Memory allocation - code portion : 20
------------------------------------------------------------------
0 15 Bra
4 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 47
+Memory allocation - compiled block : 183
+Memory allocation - code portion : 47
------------------------------------------------------------------
0 42 Bra
4 34 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 37
+Memory allocation - compiled block : 173
+Memory allocation - code portion : 37
------------------------------------------------------------------
0 32 Bra
4 24 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 6 Bra
4 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 12
+Memory allocation - compiled block : 148
+Memory allocation - code portion : 12
------------------------------------------------------------------
0 7 Bra
4 [^\x{aa}]
#pattern fullbincode,memory
/((?i)b)/
-Memory allocation (code space): 25
+Memory allocation - compiled block : 161
+Memory allocation - code portion : 25
------------------------------------------------------------------
0 19 Bra
5 9 CBra 1
------------------------------------------------------------------
/(?s)(.*X|^B)/
-Memory allocation (code space): 35
+Memory allocation - compiled block : 171
+Memory allocation - code portion : 35
------------------------------------------------------------------
0 29 Bra
5 11 CBra 1
------------------------------------------------------------------
/(?s:.*X|^B)/
-Memory allocation (code space): 33
+Memory allocation - compiled block : 169
+Memory allocation - code portion : 33
------------------------------------------------------------------
0 27 Bra
5 9 Bra
------------------------------------------------------------------
/^[[:alnum:]]/
-Memory allocation (code space): 45
+Memory allocation - compiled block : 181
+Memory allocation - code portion : 45
------------------------------------------------------------------
0 39 Bra
5 ^
------------------------------------------------------------------
/#/Ix
-Memory allocation (code space): 11
+Memory allocation - compiled block : 147
+Memory allocation - code portion : 11
------------------------------------------------------------------
0 5 Bra
5 5 Ket
Subject length lower bound = 0
/a#/Ix
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 a
Subject length lower bound = 1
/x?+/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 x?+
------------------------------------------------------------------
/x++/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 x++
------------------------------------------------------------------
/x{1,3}+/
-Memory allocation (code space): 17
+Memory allocation - compiled block : 153
+Memory allocation - code portion : 17
------------------------------------------------------------------
0 11 Bra
5 x
------------------------------------------------------------------
/(x)*+/
-Memory allocation (code space): 26
+Memory allocation - compiled block : 162
+Memory allocation - code portion : 26
------------------------------------------------------------------
0 20 Bra
5 Braposzero
------------------------------------------------------------------
/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
-Memory allocation (code space): 144
+Memory allocation - compiled block : 280
+Memory allocation - code portion : 144
------------------------------------------------------------------
0 138 Bra
5 ^
------------------------------------------------------------------
"8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 830
+Memory allocation - compiled block : 966
+Memory allocation - code portion : 830
------------------------------------------------------------------
0 824 Bra
5 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
"\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b"
-Memory allocation (code space): 820
+Memory allocation - compiled block : 956
+Memory allocation - code portion : 820
------------------------------------------------------------------
0 814 Bra
5 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
------------------------------------------------------------------
/(a(?1)b)/
-Memory allocation (code space): 32
+Memory allocation - compiled block : 168
+Memory allocation - code portion : 32
------------------------------------------------------------------
0 26 Bra
5 16 CBra 1
------------------------------------------------------------------
/(a(?1)+b)/
-Memory allocation (code space): 42
+Memory allocation - compiled block : 178
+Memory allocation - code portion : 42
------------------------------------------------------------------
0 36 Bra
5 26 CBra 1
------------------------------------------------------------------
/a(?P<name1>b|c)d(?P<longername2>e)/
-Memory allocation (code space): 50
+Memory allocation - compiled block : 214
+Memory allocation - code portion : 50
------------------------------------------------------------------
0 44 Bra
5 a
------------------------------------------------------------------
/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/
-Memory allocation (code space): 65
+Memory allocation - compiled block : 213
+Memory allocation - code portion : 65
------------------------------------------------------------------
0 59 Bra
5 35 Bra
------------------------------------------------------------------
/(?P<a>a)...(?P=a)bbb(?P>a)d/
-Memory allocation (code space): 44
+Memory allocation - compiled block : 184
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 38 Bra
5 9 CBra 1
------------------------------------------------------------------
/abc(?C255)de(?C)f/
-Memory allocation (code space): 43
+Memory allocation - compiled block : 179
+Memory allocation - code portion : 43
------------------------------------------------------------------
0 37 Bra
5 abc
------------------------------------------------------------------
/abcde/auto_callout
-Memory allocation (code space): 81
+Memory allocation - compiled block : 217
+Memory allocation - code portion : 81
------------------------------------------------------------------
0 75 Bra
5 Callout 255 0 1
------------------------------------------------------------------
/\x{100}/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{100}
------------------------------------------------------------------
/\x{1000}/utf
-Memory allocation (code space): 15
+Memory allocation - compiled block : 151
+Memory allocation - code portion : 15
------------------------------------------------------------------
0 9 Bra
5 \x{1000}
------------------------------------------------------------------
/\x{10000}/utf
-Memory allocation (code space): 16
+Memory allocation - compiled block : 152
+Memory allocation - code portion : 16
------------------------------------------------------------------
0 10 Bra
5 \x{10000}
------------------------------------------------------------------
/\x{100000}/utf
-Memory allocation (code space): 16
+Memory allocation - compiled block : 152
+Memory allocation - code portion : 16
------------------------------------------------------------------
0 10 Bra
5 \x{100000}
------------------------------------------------------------------
/\x{10ffff}/utf
-Memory allocation (code space): 16
+Memory allocation - compiled block : 152
+Memory allocation - code portion : 16
------------------------------------------------------------------
0 10 Bra
5 \x{10ffff}
Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large
/[\x{ff}]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{ff}
------------------------------------------------------------------
/[\x{100}]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{100}
------------------------------------------------------------------
/\x80/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{80}
------------------------------------------------------------------
/\xff/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{ff}
------------------------------------------------------------------
/\x{0041}\x{2262}\x{0391}\x{002e}/I,utf
-Memory allocation (code space): 22
+Memory allocation - compiled block : 158
+Memory allocation - code portion : 22
------------------------------------------------------------------
0 16 Bra
5 A\x{2262}\x{391}.
Subject length lower bound = 4
/\x{D55c}\x{ad6d}\x{C5B4}/I,utf
-Memory allocation (code space): 23
+Memory allocation - compiled block : 159
+Memory allocation - code portion : 23
------------------------------------------------------------------
0 17 Bra
5 \x{d55c}\x{ad6d}\x{c5b4}
Subject length lower bound = 3
/\x{65e5}\x{672c}\x{8a9e}/I,utf
-Memory allocation (code space): 23
+Memory allocation - compiled block : 159
+Memory allocation - code portion : 23
------------------------------------------------------------------
0 17 Bra
5 \x{65e5}\x{672c}\x{8a9e}
Subject length lower bound = 3
/[\x{100}]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{100}
------------------------------------------------------------------
/[Z\x{100}]/utf
-Memory allocation (code space): 53
+Memory allocation - compiled block : 189
+Memory allocation - code portion : 53
------------------------------------------------------------------
0 47 Bra
5 [Z\x{100}]
------------------------------------------------------------------
/^[\x{100}\E-\Q\E\x{150}]/utf
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 18 Bra
5 ^
------------------------------------------------------------------
/^[\QĀ\E-\QŐ\E]/utf
-Memory allocation (code space): 24
+Memory allocation - compiled block : 160
+Memory allocation - code portion : 24
------------------------------------------------------------------
0 18 Bra
5 ^
Failed: error 106 at offset 15: missing terminating ] for character class
/[\p{L}]/
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 15 Bra
5 [\p{L}]
------------------------------------------------------------------
/[\p{^L}]/
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 15 Bra
5 [\P{L}]
------------------------------------------------------------------
/[\P{L}]/
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 15 Bra
5 [\P{L}]
------------------------------------------------------------------
/[\P{^L}]/
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 15 Bra
5 [\p{L}]
------------------------------------------------------------------
/[abc\p{L}\x{0660}]/utf
-Memory allocation (code space): 56
+Memory allocation - compiled block : 192
+Memory allocation - code portion : 56
------------------------------------------------------------------
0 50 Bra
5 [a-c\p{L}\x{660}]
------------------------------------------------------------------
/[\p{Nd}]/utf
-Memory allocation (code space): 21
+Memory allocation - compiled block : 157
+Memory allocation - code portion : 21
------------------------------------------------------------------
0 15 Bra
5 [\p{Nd}]
------------------------------------------------------------------
/[\p{Nd}+-]+/utf
-Memory allocation (code space): 54
+Memory allocation - compiled block : 190
+Memory allocation - code portion : 54
------------------------------------------------------------------
0 48 Bra
5 [+\-\p{Nd}]++
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf
-Memory allocation (code space): 29
+Memory allocation - compiled block : 165
+Memory allocation - code portion : 29
------------------------------------------------------------------
0 23 Bra
5 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf
-Memory allocation (code space): 29
+Memory allocation - compiled block : 165
+Memory allocation - code portion : 29
------------------------------------------------------------------
0 23 Bra
5 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
------------------------------------------------------------------
/[\x{105}-\x{109}]/i,utf
-Memory allocation (code space): 23
+Memory allocation - compiled block : 159
+Memory allocation - code portion : 23
------------------------------------------------------------------
0 17 Bra
5 [\x{104}-\x{109}]
------------------------------------------------------------------
/( ( (?(1)0|) )* )/x
-Memory allocation (code space): 56
+Memory allocation - compiled block : 192
+Memory allocation - code portion : 56
------------------------------------------------------------------
0 50 Bra
5 40 CBra 1
------------------------------------------------------------------
/( (?(1)0|)* )/x
-Memory allocation (code space): 44
+Memory allocation - compiled block : 180
+Memory allocation - code portion : 44
------------------------------------------------------------------
0 38 Bra
5 28 CBra 1
------------------------------------------------------------------
/[a]/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 a
------------------------------------------------------------------
/[a]/utf
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 a
------------------------------------------------------------------
/[\xaa]/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 \x{aa}
------------------------------------------------------------------
/[\xaa]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 \x{aa}
------------------------------------------------------------------
/[^a]/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 [^a]
------------------------------------------------------------------
/[^a]/utf
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 [^a]
------------------------------------------------------------------
/[^\xaa]/
-Memory allocation (code space): 13
+Memory allocation - compiled block : 149
+Memory allocation - code portion : 13
------------------------------------------------------------------
0 7 Bra
5 [^\x{aa}]
------------------------------------------------------------------
/[^\xaa]/utf
-Memory allocation (code space): 14
+Memory allocation - compiled block : 150
+Memory allocation - code portion : 14
------------------------------------------------------------------
0 8 Bra
5 [^\x{aa}]
--- /dev/null
+$! Configure procedure
+$! (c) Alexey Chupahin 11-APR-2024
+$! alexey@vaxman.de, alexey_chupahin@mail.ru
+$!
+$!
+$ SET NOON
+$SET NOVER
+$WRITE SYS$OUTPUT " "
+$WRITE SYS$OUTPUT "Configuring PCRE2 library for OpenVMS "
+$WRITE SYS$OUTPUT "(c) Alexey Chupahin CHAPG"
+$WRITE SYS$OUTPUT " "
+$! Checking architecture
+$DECC = F$SEARCH("SYS$SYSTEM:DECC$COMPILER.EXE") .NES. ""
+$ IF F$GETSYI("ARCH_TYPE").EQ.1 THEN CPU = "VAX"
+$ IF F$GETSYI("ARCH_TYPE").EQ.2 THEN CPU = "Alpha"
+$ IF F$GETSYI("ARCH_TYPE").EQ.3 THEN CPU = "I64"
+$ IF F$GETSYI("ARCH_TYPE").EQ.4 THEN CPU = "x86"
+$WRITE SYS$OUTPUT "Checking architecture ... ", CPU
+$IF ( (CPU.EQS."Alpha").OR.(CPU.EQS."I64").OR(CPU.EQS."x86") )
+$ THEN
+$ SHARED=64
+$ ELSE
+$ SHARED=32
+$ENDIF
+$!
+$IF (DECC) THEN $WRITE SYS$OUTPUT "Compiler ... DEC C"
+$IF (.NOT. DECC) THEN $WRITE SYS$OUTPUT "BAD compiler" GOTO EXIT
+$MMS = F$SEARCH("SYS$SYSTEM:MMS.EXE") .NES. ""
+$MMK = F$TYPE(MMK)
+$IF (MMS .OR. MMK.NES."") THEN GOTO TEST_LIBRARIES
+$! I cant find any make tool
+$ WRITE SYS$OUTPUT "Install MMS or MMK"
+$GOTO EXIT
+$!PERL = F$TYPE(MMK)
+$!IF (PERL.NES."") THEN GOTO TEST_LIBRARIES
+$!WRITE SYS$OUTPUT "Install PERL"
+$!GOTO EXIT
+$!
+$!
+$! Is it package root directory? If no, go to [-]
+$ IF (F$SEARCH("[]VMS.DIR").EQS."") .AND. (F$SEARCH("[]vms.dir").EQS."")
+$ THEN
+$ SET DEF [-]
+$ ENDIF
+$!
+$TEST_LIBRARIES:
+$! Setting as MAKE utility one of MMS or MMK. I prefer MMS.
+$IF (MMK.NES."") THEN MAKE="MMK"
+$IF (MMS) THEN MAKE="MMS"
+$WRITE SYS$OUTPUT "Checking build utility ... ''MAKE'"
+$!WRITE SYS$OUTPUT "Checking PERL ... found"
+$WRITE SYS$OUTPUT " "
+$!
+$!
+$! Check files and ODS-2. unzip makes files FILE.H.GENERIC like FILE_H.GENERIC. Should rename to FILE.H_GENERIC
+$IF F$SEARCH("[.SRC]PCRE2_H.GENERIC") .NES. ""
+$ THEN
+$ REN [.SRC]PCRE2_H.GENERIC [.SRC]PCRE2.H_GENERIC
+$ ELSE
+$ IF F$SEARCH("[.SRC]PCRE2.H_GENERIC") .EQS. ""
+$ THEN
+$ WRITE SYS$OUTPUT "Not ODS-2 volume, or PCRE2_H.GENERIC not found"
+$ EXIT
+$ ENDIF
+$ENDIF
+$IF F$SEARCH("[.SRC]PCRE2_CHARTABLES_C.DIST") .NES. ""
+$ THEN
+$ REN [.SRC]PCRE2_CHARTABLES_C.DIST [.SRC]PCRE2_CHARTABLES.C_DIST
+$ ELSE
+$ IF F$SEARCH("[.SRC]PCRE2_CHARTABLES.C_DIST") .EQS. ""
+$ THEN
+$ WRITE SYS$OUTPUT "Not ODS-2 volume, or PCRE2_CHARTABLES_C.DIST not found"
+$ EXIT
+$ ENDIF
+$ENDIF
+$WRITE SYS$OUTPUT "Source Files OK"
+$!
+$!
+$I18 = F$SEARCH("SYS$I18N_ICONV:ISO8859-1_UTF-8.ICONV") .NES. ""
+$IF (I18)
+$ THEN
+$ WRITE SYS$OUTPUT "Found I18 extension ICONV codes"
+$!"Checking for iconv "
+$ DEFINE SYS$ERROR _NLA0:
+$ DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ SYS$INPUT
+#include <stdio.h>
+#include <iconv.h>
+#include <errno.h>
+#include <stdlib.h>
+
+int main ()
+{
+ /* */
+ /* Declare variables to be used */
+ /* */
+ char fromcodeset[30];
+ char tocodeset[30];
+ int iconv_opened;
+ iconv_t iconv_struct; /* Iconv descriptor */
+
+ /* */
+ /* Initialize variables */
+ /* */
+ sprintf(fromcodeset,"UTF-8");
+ sprintf(tocodeset,"ISO8859-1");
+ iconv_opened = FALSE;
+
+ /* */
+ /* Attempt to create a conversion descriptor for the codesets */
+ /* specified. If the return value from iconv_open is -1 then */
+ /* an error has occurred. Check value of errno. */
+ /* */
+ if ((iconv_struct = iconv_open (tocodeset, fromcodeset)) == (iconv_t)-1)
+ {
+ /* */
+ /* Check the value of errno */
+ /* */
+ switch (errno)
+ {
+ case EMFILE:
+ case ENFILE:
+ printf("Too many iconv conversion files open\n");
+ exit(2);
+ break;
+
+ case ENOMEM:
+ printf("Not enough memory\n");
+ printf("Checking iconv ..... no\n");
+ exit(2);
+ break;
+
+ case EINVAL:
+ printf("Unsupported conversion\n");
+ exit(2);
+ break;
+
+ default:
+ printf("Unexpected error from iconv_open\n");
+ exit(2);
+ break;
+ }
+ }
+ else
+ /* */
+ /* Successfully allocated a conversion descriptor */
+ /* */
+ iconv_opened = TRUE;
+
+ /* */
+ /* Was a conversion descriptor allocated */
+ /* */
+ if (iconv_opened)
+ {
+ /* */
+ /* Attempt to deallocate the conversion descriptor. If */
+ /* iconv_close returns -1 then an error has occurred. */
+ /* */
+ if (iconv_close (iconv_struct) == -1)
+ {
+ /* */
+ /* An error occurred. Check the value of errno */
+ /* */
+ switch (errno)
+ {
+ case EBADF:
+ printf("Conversion descriptor is invalid\n");
+ exit(2);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ printf("Checking iconv ..... yes\n");
+ }
+ return(1);
+}
+$!
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ HAVE_ICONV=0
+$ GOTO NEXT0
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$LINK/EXE=TEST TEST
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_ICONV=0
+$ GOTO NEXT0
+$ ELSE
+$ HAVE_ICONV=1
+$ENDIF
+$NEXT0:
+$IF (HAVE_ICONV.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for iconv ... Yes"
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for iconv ... No"
+$ENDIF
+$!
+$!
+$! Checking for BZIP2 library
+$!
+$ DEFINE SYS$ERROR _NLA0:
+$ DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ/INCLUDE=(BZ2LIB) SYS$INPUT
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <bzlib.h>
+ int main()
+ {
+ printf("checking version bzip2 library: %s\n",BZ2_bzlibVersion());
+ }
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ HAVE_BZIP2=0
+$ GOTO ERR0
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$!Testing for CHAPG BZIP2
+$!
+$LINK/EXE=TEST TEST,BZ2LIB:BZIP2/OPT
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_BZIP2=0
+$ GOTO ERR0
+$ ELSE
+$ HAVE_BZIP2=1
+$ENDIF
+$ERR0:
+$IF (HAVE_BZIP2.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for CHAPG bzip2 library ... Yes"
+$ RUN TEST
+$ GOTO NEXT4
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for correct bzip2 library ... No"
+$ WRITE SYS$OUTPUT "To get bzip2 archives support, please download"
+$ WRITE SYS$OUTPUT "and install good library ported by Alexey Chupahin"
+$ WRITE SYS$OUTPUT "from openvms clamav site http://vaxvms.org/clamav/"
+$ WRITE SYS$OUTPUT ""
+$ GOTO EXIT
+$ENDIF
+$NEXT4:
+$!
+$!
+$!"Checking for CHAPG zlib library "
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ/INCLUDE=(ZLIB) SYS$INPUT
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <zlib.h>
+ int main()
+ {
+ printf("checking version zlib: %s\n",zlibVersion());
+ // printf("checking zlib is correct ");
+ }
+
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ HAVE_ZLIB=0
+$ GOTO ERR4
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$!
+$LINK/EXE=TEST TEST,ZLIB:ZLIB.OPT/OPT
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_ZLIB=0
+$ GOTO ERR4
+$ ELSE
+$ HAVE_ZLIB=1
+$ENDIF
+$ERR4:
+$IF (HAVE_ZLIB.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for CHAPG zlib library ... Yes"
+$ RUN TEST
+$ GOTO NEXT5
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for CHAPG zlib library ... No"
+$ WRITE SYS$OUTPUT "Please install ZLIB from"
+$ WRITE SYS$OUTPUT "http://vaxvms.org/libsdl/required.html"
+$ GOTO EXIT
+$ENDIF
+$!
+$NEXT5:
+
+$!
+$!WRITING BUILD FILES
+$OPEN/WRITE OUT BUILD.COM
+$ WRITE OUT "$","SET DEF [.SRC]"
+$ WRITE OUT "$",MAKE
+$ WRITE OUT "$ CURRENT = F$ENVIRONMENT (""DEFAULT"") "
+$ WRITE OUT "$","SET DEF [-]"
+$ WRITE OUT "$CLAM=CURRENT"
+$ WRITE OUT "$OPEN/WRITE OUTT PCRE2$STARTUP.COM"
+$ WRITE OUT "$WRITE OUTT ""DEFINE PCRE2 ","'","'","CLAM'"" "
+$ WRITE OUT "$WRITE OUTT ""DEFINE PCRE2$SHR ","'","'","CLAM'PCRE2$SHR.EXE"" "
+$ WRITE OUT "$WRITE OUTT ""PCRE2GREP:==$", "'","'","CLAM'PCRE2GREP.EXE"""
+$ WRITE OUT "$CLOSE OUTT"
+$ WRITE OUT "$WRITE SYS$OUTPUT "" "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""***************************************************************************** "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""Compilation is completed."" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""PCRE2$STARTUP.COM is created. "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""This file setups all logicals needed."" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""It should be executed before using PCRE2 Library. "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""Use PCRE2:PCRE2.OPT to link you program"" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""PCRE2GREP grep utility is installed here for your needs "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""***************************************************************************** "" "
+$CLOSE OUT
+$! BUILD.COM finished
+$ WRITE SYS$OUTPUT "BUILD.COM has been created"
+$!
+$!Creating OPT.OPT file containig external libraries for linker
+$OPEN/WRITE OUT [.SRC]PCRE2.OPT
+$IF (SHARED.GT.0) THEN WRITE OUT "PCRE2:PCRE2$SHR/SHARE"
+$IF (SHARED.EQ.0)
+$ THEN
+$ WRITE OUT "PCRE2:PCRE2/LIB"
+$ENDIF
+$CLOSE OUT
+$WRITE SYS$OUTPUT "PCRE2.OPT has been created"
+$IF (SHARED.EQ.64)
+$ THEN
+$ COPY SYS$INPUT [.SRC]PCRE2$DEF.OPT
+!
+case_sensitive=NO
+symbol_vector = (PCRE2_CONFIG_8 = PROCEDURE)
+symbol_vector = (PCRE2_MAKETABLES_8 = PROCEDURE)
+symbol_vector = (PCRE2_MAKETABLES_FREE_8 = PROCEDURE)
+symbol_vector = (PCRE2_CODE_COPY_8 = PROCEDURE)
+symbol_vector = (PCRE2_CODE_FREE_8 = PROCEDURE)
+symbol_vector = (_PCRE2_CHECK_ESCAPE_8 = PROCEDURE)
+symbol_vector = (PCRE2_COMPILE_8 = PROCEDURE)
+symbol_vector = (PCRE2_CODE_COPY_WITH_TABLES_8 = PROCEDURE)
+symbol_vector = (PCRE2_GET_ERROR_MESSAGE_8 = PROCEDURE)
+symbol_vector = (PCRE2_MATCH_DATA_CREATE_8 = PROCEDURE)
+symbol_vector = (VMS_PCRE2_GET_M_D_HPFRAM_S_8 = PROCEDURE)
+symbol_vector = (PCRE2_GET_MATCH_DATA_SIZE_8 = PROCEDURE)
+symbol_vector = (PCRE2_GET_STARTCHAR_8 = PROCEDURE)
+symbol_vector = (PCRE2_GET_OVECTOR_COUNT_8 = PROCEDURE)
+symbol_vector = (PCRE2_GET_OVECTOR_POINTER_8 = PROCEDURE)
+symbol_vector = (PCRE2_GET_MARK_8 = PROCEDURE)
+symbol_vector = (PCRE2_MATCH_DATA_FREE_8 = PROCEDURE)
+symbol_vector = (VMS_PCRE2_M_D_CRT_FR_PATT_8 = PROCEDURE)
+symbol_vector = (PCRE2_MATCH_8 = PROCEDURE)
+symbol_vector = (PCRE2_PATTERN_INFO_8 = PROCEDURE)
+symbol_vector = (PCRE2_CALLOUT_ENUMERATE_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_GLOB_ESCAPE_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_GLOB_SEPARATOR_8 = PROCEDURE)
+symbol_vector = (VMS_PCRE2_SET_RCRS_MEM_MNG_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_DEPTH_LIMIT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_RECURSION_LIMIT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_OFFSET_LIMIT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_MATCH_LIMIT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_HEAP_LIMIT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_SUBSTITUTE_CALLOUT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_CALLOUT_8 = PROCEDURE)
+symbol_vector = (VMS_PCRE2_SET_CMPL_RCRS_GRD_8 = PROCEDURE)
+symbol_vector = (VMS_PCRE2_SET_CMPL_EXT_OPT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_PARENS_NEST_LIMIT_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_MAX_VARLOOKBEHIND_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_NEWLINE_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_MAX_PATTERN_LENGTH_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_BSR_8 = PROCEDURE)
+symbol_vector = (PCRE2_SET_CHARACTER_TABLES_8 = PROCEDURE)
+symbol_vector = (PCRE2_CONVERT_CONTEXT_FREE_8 = PROCEDURE)
+symbol_vector = (PCRE2_MATCH_CONTEXT_FREE_8 = PROCEDURE)
+symbol_vector = (PCRE2_COMPILE_CONTEXT_FREE_8 = PROCEDURE)
+symbol_vector = (PCRE2_GENERAL_CONTEXT_FREE_8 = PROCEDURE)
+symbol_vector = (PCRE2_CONVERT_CONTEXT_COPY_8 = PROCEDURE)
+symbol_vector = (PCRE2_MATCH_CONTEXT_COPY_8 = PROCEDURE)
+symbol_vector = (PCRE2_COMPILE_CONTEXT_COPY_8 = PROCEDURE)
+symbol_vector = (PCRE2_GENERAL_CONTEXT_COPY_8 = PROCEDURE)
+symbol_vector = (_PCRE2_MEMCTL_MALLOC_8 = PROCEDURE)
+symbol_vector = (PCRE2_CONVERT_CONTEXT_CREATE_8 = PROCEDURE)
+symbol_vector = (PCRE2_MATCH_CONTEXT_CREATE_8 = PROCEDURE)
+symbol_vector = (PCRE2_COMPILE_CONTEXT_CREATE_8 = PROCEDURE)
+symbol_vector = (PCRE2_GENERAL_CONTEXT_CREATE_8 = PROCEDURE)
+symbol_vector = (_PCRE2_AUTO_POSSESSIFY_8 = PROCEDURE)
+symbol_vector = (_PCRE2_CKD_SMUL = PROCEDURE)
+symbol_vector = (_PCRE2_FIND_BRACKET_8 = PROCEDURE)
+symbol_vector = (_PCRE2_IS_NEWLINE_8 = PROCEDURE)
+symbol_vector = (_PCRE2_WAS_NEWLINE_8 = PROCEDURE)
+symbol_vector = (_PCRE2_SCRIPT_RUN_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STRCMP_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STRCPY_C8_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STRLEN_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STRNCMP_C8_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STRNCMP_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STRCMP_C8_8 = PROCEDURE)
+symbol_vector = (_PCRE2_STUDY_8 = PROCEDURE)
+symbol_vector = (_PCRE2_VALID_UTF_8 = PROCEDURE)
+symbol_vector = (VMS_PCRE2_DEF_CMPL_CNTXT_8 = DATA)
+symbol_vector = (VMS_PCRE2_DEF_CNVRT_CNTXT_8 = DATA)
+symbol_vector = (_PCRE2_CALLOUT_END_DELIMS_8 = DATA)
+symbol_vector = (_PCRE2_CALLOUT_START_DELIMS_8 = DATA)
+symbol_vector = (_PCRE2_DEFAULT_MATCH_CONTEXT_8 = DATA)
+symbol_vector = (_PCRE2_DEFAULT_TABLES_8 = DATA)
+symbol_vector = (_PCRE2_HSPACE_LIST_8 = DATA)
+symbol_vector = (_PCRE2_OP_LENGTHS_8 = DATA)
+symbol_vector = (_PCRE2_UCD_CASELESS_SETS_8 = DATA)
+symbol_vector = (_PCRE2_UCD_RECORDS_8 = DATA)
+symbol_vector = (_PCRE2_UCD_STAGE1_8 = DATA)
+symbol_vector = (_PCRE2_UCD_STAGE2_8 = DATA)
+symbol_vector = (_PCRE2_VSPACE_LIST_8 = DATA)
+!
+! ### PSECT list extracted from PCRE2.MAP;1
+!
+$ENDIF
+$!
+$!
+COPY SYS$INPUT [.SRC]CONFIG.H
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+
+/* PCRE2 is written in Standard C, but there are a few non-standard things it
+can cope with, allowing it to run on SunOS4 and other "close to standard"
+systems.
+
+In environments that support the GNU autotools, config.h.in is converted into
+config.h by the "configure" script. In environments that use CMake,
+config-cmake.in is converted into config.h. If you are going to build PCRE2 "by
+hand" without using "configure" or CMake, you should copy the distributed
+config.h.generic to config.h, and edit the macro definitions to be the way you
+need them. You must then add -DHAVE_CONFIG_H to all of your compile commands,
+so that config.h is included at the start of every source.
+
+Alternatively, you can avoid editing by using -D on the compiler command line
+to set the macro values. In this case, you do not have to set -DHAVE_CONFIG_H,
+but if you do, default values will be taken from config.h for non-boolean
+macros that are not defined on the command line.
+
+Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE2_8 should either be
+defined (conventionally to 1) for TRUE, and not defined at all for FALSE. All
+such macros are listed as a commented #undef in config.h.generic. Macros such
+as MATCH_LIMIT, whose actual value is relevant, have defaults defined, but are
+surrounded by #ifndef/#endif lines so that the value can be overridden by -D.
+
+PCRE2 uses memmove() if HAVE_MEMMOVE is defined; otherwise it uses bcopy() if
+HAVE_BCOPY is defined. If your system has neither bcopy() nor memmove(), make
+sure both macros are undefined; an emulation function will then be used. */
+
+/* By default, the \R escape sequence matches any Unicode line ending
+ character or sequence of characters. If BSR_ANYCRLF is defined (to any
+ value), this is changed so that backslash-R matches only CR, LF, or CRLF.
+ The build-time default can be overridden by the user of PCRE2 at runtime.
+ */
+#undef BSR_ANYCRLF
+
+/* Define to any value to disable the use of the z and t modifiers in
+ formatting settings such as %zu or %td (this is rarely needed). */
+#undef DISABLE_PERCENT_ZT
+
+/* If you are compiling for a system that uses EBCDIC instead of ASCII
+ character codes, define this macro to any value. When EBCDIC is set, PCRE2
+ assumes that all input strings are in EBCDIC. If you do not define this
+ macro, PCRE2 will assume input strings are ASCII or UTF-8/16/32 Unicode. It
+ is not possible to build a version of PCRE2 that supports both EBCDIC and
+ UTF-8/16/32. */
+#undef EBCDIC
+
+/* In an EBCDIC environment, define this macro to any value to arrange for the
+ NL character to be 0x25 instead of the default 0x15. NL plays the role that
+ LF does in an ASCII/Unicode environment. */
+#undef EBCDIC_NL25
+
+/* Define this if your compiler supports __attribute__((uninitialized)) */
+#undef HAVE_ATTRIBUTE_UNINITIALIZED
+
+/* Define to 1 if you have the 'bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define this if your compiler provides __builtin_mul_overflow() */
+#undef HAVE_BUILTIN_MUL_OVERFLOW
+
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+#undef HAVE_EDITLINE_READLINE_H
+
+/* Define to 1 if you have the <edit/readline/readline.h> header file. */
+#undef HAVE_EDIT_READLINE_READLINE_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the 'memfd_create' function. */
+#undef HAVE_MEMFD_CREATE
+
+/* Define to 1 if you have the 'memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* 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. */
+#undef HAVE_MKOSTEMP
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#undef HAVE_PTHREAD_PRIO_INHERIT
+
+/* Define to 1 if you have the <readline.h> header file. */
+#undef HAVE_READLINE_H
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+#undef HAVE_READLINE_HISTORY_H
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+#undef HAVE_READLINE_READLINE_H
+
+/* Define to 1 if you have the `realpath' function. */
+#define HAVE_REALPATH 1
+
+/* 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. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the 'strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the compiler supports simple visibility declarations. */
+#undef HAVE_VISIBILITY
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the <zlib.h> header file. */
+
+/* This limits the amount of memory that may be used while matching a pattern.
+ It applies to both pcre2_match() and pcre2_dfa_match(). It does not apply
+ to JIT matching. The value is in kibibytes (units of 1024 bytes). */
+#undef HEAP_LIMIT
+
+/* The value of LINK_SIZE determines the number of bytes used to store links
+ as offsets within the compiled regex. The default is 2, which allows for
+ compiled patterns up to 65535 code units long. This covers the vast
+ majority of cases. However, PCRE2 can also be compiled to use 3 or 4 bytes
+ instead. This allows for longer patterns in extreme cases. */
+#undef LINK_SIZE
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* The value of MATCH_LIMIT determines the default number of times the
+ pcre2_match() function can record a backtrack position during a single
+ 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 forever to determine that they do not match. The default is set very
+ large so that it does not accidentally catch legitimate cases. */
+#undef MATCH_LIMIT
+
+/* The above limit applies to all backtracks, whether or not they are nested.
+ In some environments it is desirable to limit the nesting of backtracking
+ (that is, the depth of tree that is searched) more strictly, in order to
+ restrict the maximum amount of heap memory that is used. The value of
+ MATCH_LIMIT_DEPTH provides this facility. To have any useful effect, it
+ must be less than the value of MATCH_LIMIT. The default is to use the same
+ value as MATCH_LIMIT. There is a runtime method for setting a different
+ limit. In the case of pcre2_dfa_match(), this limit controls the depth of
+ the internal nested function calls that are used for pattern recursions,
+ lookarounds, and atomic groups. */
+#undef MATCH_LIMIT_DEPTH
+
+/* This limit is parameterized just in case anybody ever wants to change it.
+ Care must be taken if it is increased, because it guards against integer
+ overflow caused by enormously large patterns. */
+#undef MAX_NAME_COUNT
+
+/* This limit is parameterized just in case anybody ever wants to change it.
+ Care must be taken if it is increased, because it guards against integer
+ overflow caused by enormously large patterns. */
+#undef MAX_NAME_SIZE
+
+/* The value of MAX_VARLOOKBEHIND specifies the default maximum length, in
+ characters, for a variable-length lookbehind assertion. */
+#undef MAX_VARLOOKBEHIND
+
+/* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */
+#undef NEVER_BACKSLASH_C
+
+/* The value of NEWLINE_DEFAULT determines the default newline character
+ sequence. PCRE2 client programs can override this by selecting other values
+ at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), 5
+ (ANYCRLF), and 6 (NUL). */
+#undef NEWLINE_DEFAULT
+
+/* Name of package */
+#define PACKAGE "pcre2"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PCRE2"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PCRE2 10.43 VMS"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcre2"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#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
+ stack that is used while compiling a pattern. */
+#undef PARENS_NEST_LIMIT
+
+/* The value of PCRE2GREP_BUFSIZE is the starting size of the buffer used by
+ pcre2grep to hold parts of the file it is searching. The buffer will be
+ expanded up to PCRE2GREP_MAX_BUFSIZE if necessary, for files containing
+ very long lines. The actual amount of memory used by pcre2grep is three
+ times this number, because it allows for the buffering of "before" and
+ "after" lines. */
+#define PCRE2GREP_BUFSIZE 20480
+
+/* The value of PCRE2GREP_MAX_BUFSIZE specifies the maximum size of the buffer
+ used by pcre2grep to hold parts of the file it is searching. The actual
+ amount of memory used by pcre2grep is three times this number, because it
+ allows for the buffering of "before" and "after" lines. */
+#define PCRE2GREP_MAX_BUFSIZE 1048576
+
+/* Define to any value to include debugging code. */
+#undef PCRE2_DEBUG
+
+/* to make a symbol visible */
+#undef 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
+ 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. */
+#undef PCRE2_EXP_DEFN
+
+/* Define to any value if linking statically (TODO: make nice with Libtool) */
+#undef PCRE2_STATIC
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* Define to any non-zero number to enable support for SELinux compatible
+ executable memory allocator in JIT. Note that this will have no effect
+ unless SUPPORT_JIT is also defined. */
+#undef SLJIT_PROT_EXECUTABLE_ALLOCATOR
+
+/* 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. */
+#define STDC_HEADERS 1
+
+/* 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
+
+/* Define to any value to allow pcre2grep to be linked with libbz2, so that it
+ is able to handle .bz2 files. */
+
+/* Define to any value to allow pcre2test to be linked with libedit. */
+#undef SUPPORT_LIBEDIT
+
+/* Define to any value to allow pcre2test to be linked with libreadline. */
+#undef SUPPORT_LIBREADLINE
+
+/* Define to any value to allow pcre2grep to be linked with libz, so that it
+ is able to handle .gz files. */
+
+/* Define to any value to enable callout script support in pcre2grep. */
+#undef SUPPORT_PCRE2GREP_CALLOUT
+
+/* Define to any value to enable fork support in pcre2grep callout scripts.
+ This will have no effect unless SUPPORT_PCRE2GREP_CALLOUT is also defined.
+ */
+#undef SUPPORT_PCRE2GREP_CALLOUT_FORK
+
+/* Define to any value to enable JIT support in pcre2grep. Note that this will
+ have no effect unless SUPPORT_JIT is also defined. */
+#undef SUPPORT_PCRE2GREP_JIT
+
+/* Define to any value to enable the 16 bit PCRE2 library. */
+#undef SUPPORT_PCRE2_16
+
+/* Define to any value to enable the 32 bit PCRE2 library. */
+#undef SUPPORT_PCRE2_32
+
+/* Define to any value to enable the 8 bit PCRE2 library. */
+#define SUPPORT_PCRE2_8 1
+
+/* Define to any value to enable support for Unicode and UTF encoding. This
+ will work even in an EBCDIC environment, but it is incompatible with the
+ EBCDIC macro. That is, PCRE2 can support *either* EBCDIC code *or*
+ ASCII/Unicode, but not both at once. */
+#undef SUPPORT_UNICODE
+
+/* Define to any value for valgrind support to find invalid memory reads. */
+#undef SUPPORT_VALGRIND
+
+/* Enable extensions on AIX, Interix, z/OS. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable general extensions on macOS. */
+#ifndef _DARWIN_C_SOURCE
+# undef _DARWIN_C_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable X/Open compliant socket functions that do not require linking
+ with -lxnet on HP-UX 11.11. */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# undef _HPUX_ALT_XOPEN_SOCKET_API
+#endif
+/* Identify the host operating system as Minix.
+ This macro does not affect the system headers' behavior.
+ A future release of Autoconf may stop defining this macro. */
+#ifndef _MINIX
+# undef _MINIX
+#endif
+/* Enable general extensions on NetBSD.
+ Enable NetBSD compatibility extensions on Minix. */
+#ifndef _NETBSD_SOURCE
+# undef _NETBSD_SOURCE
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+ Oddly enough, this does nothing on OpenBSD. */
+#ifndef _OPENBSD_SOURCE
+# undef _OPENBSD_SOURCE
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_SOURCE
+# undef _POSIX_SOURCE
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_1_SOURCE
+# undef _POSIX_1_SOURCE
+#endif
+/* Enable POSIX-compatible threading on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# undef __STDC_WANT_IEC_60559_BFP_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# undef __STDC_WANT_IEC_60559_DFP_EXT__
+#endif
+/* Enable extensions specified by C23 Annex F. */
+#ifndef __STDC_WANT_IEC_60559_EXT__
+# undef __STDC_WANT_IEC_60559_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
+#endif
+/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# undef __STDC_WANT_IEC_60559_TYPES_EXT__
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
+#ifndef __STDC_WANT_LIB_EXT2__
+# undef __STDC_WANT_LIB_EXT2__
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009. */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# undef __STDC_WANT_MATH_SPEC_FUNCS__
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable X/Open extensions. Define to 500 only if necessary
+ to make mbstate_t available. */
+#ifndef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define to 1 on platforms where this makes off_t a 64-bit type. */
+#undef _LARGE_FILES
+
+/* 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 as 'unsigned int' if <stddef.h> doesn't define. */
+#undef size_t
+
+// VMS
+#include <stdint.h>
+#define PCRE2_EXPORT
+#define LINK_SIZE 2
+#define MAX_NAME_COUNT 10000
+#define MAX_NAME_SIZE 32
+#define MATCH_LIMIT 10000000
+#define HEAP_LIMIT 20000000
+#define NEWLINE_DEFAULT 2
+#define PARENS_NEST_LIMIT 250
+#define MATCH_LIMIT_DEPTH MATCH_LIMIT
+#define MAX_VARLOOKBEHIND 255
+
+/*
+#define _pcre2_default_compile_context_ vms_pcre2_def_cmpl_cntxt_
+#define _pcre2_default_convert_context_ vms_pcre2_def_cnvrt_cntxt_
+#define pcre2_set_compile_extra_options_8 vms_pcre2_set_cmpl_ext_opt_8
+#define pcre2_set_compile_recursion_guard_8 vms_pcre2_set_cmpl_rcrs_grd_8
+#define pcre2_set_recursion_memory_management_8 vms_pcre2_set_rcrs_mem_mng_8
+#define pcre2_match_data_create_from_pattern_8 vms_pcre2_m_d_crt_fr_patt_8
+#define pcre2_get_match_data_heapframes_size_8 vms_pcre2_get_m_d_hpfram_s_8
+#define pcre2_serialize_get_number_of_codes_8 vms_pcre2_ser_get_n_of_cod_8
+#define pcre2_substring_nametable_scan_8 vms_pcre2_substr_nmtab_scan_8
+#define pcre2_substring_length_bynumber_8 vms_pcre2_substr_len_bynum_8
+#define pcre2_substring_number_from_name_8 vms_pcre2_substr_num_f_nam_8
+*/
+
+#define HAVE_BZLIB_H 1
+#define SUPPORT_LIBBZ2 1
+
+#define HAVE_ZLIB_H 1
+#define SUPPORT_LIBZ 1
+$!
+$!
+$WRITE SYS$OUTPUT "config.h created"
+$!
+$!Creating Descrip.mms in each directory needed
+$!
+$!
+$COPY SYS$INPUT [.SRC]DESCRIP.MMS
+# (c) Alexey Chupahin 09-APR-2024
+# OpenVMS 7.3-2, DEC 2000 mod.300
+# OpenVMS 8.3, Digital PW 600au
+# OpenVMS 8.4, Compaq DS10L
+# OpenVMS 8.3, HP rx1620
+
+
+.FIRST
+ DEF PCRE2 []
+
+
+CC=cc
+CFLAGS = /INCLUDE=([],[-],[-.VMS],ZLIB,BZ2LIB) \
+ /DEFINE=(HAVE_CONFIG_H,PCRE2_CODE_UNIT_WIDTH=8)\
+ /OPTIMIZE=(INLINE=SPEED) \
+ /DEB
+
+OBJ=\
+PCRE2POSIX.OBJ,\
+PCRE2_AUTO_POSSESS.OBJ,\
+PCRE2_CHKDINT.OBJ,\
+PCRE2_CHARTABLES.OBJ,\
+PCRE2_COMPILE.OBJ,\
+PCRE2_CONFIG.OBJ,\
+PCRE2_CONTEXT.OBJ,\
+PCRE2_CONVERT.OBJ,\
+PCRE2_DFA_MATCH.OBJ,\
+PCRE2_ERROR.OBJ,\
+PCRE2_EXTUNI.OBJ,\
+PCRE2_FIND_BRACKET.OBJ,\
+PCRE2_JIT_COMPILE.OBJ,\
+PCRE2_MAKETABLES.OBJ,\
+PCRE2_MATCH.OBJ,\
+PCRE2_MATCH_DATA.OBJ,\
+PCRE2_NEWLINE.OBJ,\
+PCRE2_ORD2UTF.OBJ,\
+PCRE2_PATTERN_INFO.OBJ,\
+PCRE2_SCRIPT_RUN.OBJ,\
+PCRE2_SERIALIZE.OBJ,\
+PCRE2_STRING_UTILS.OBJ,\
+PCRE2_STUDY.OBJ,\
+PCRE2_SUBSTITUTE.OBJ,\
+PCRE2_SUBSTRING.OBJ,\
+PCRE2_TABLES.OBJ,\
+PCRE2_UCD.OBJ,\
+PCRE2_VALID_UTF.OBJ,\
+PCRE2_XCLASS.OBJ
+
+ALL : PCRE2.H PCRE2.OLB PCRE2$SHR.EXE PCRE2DEMO.EXE PCRE2GREP.EXE
+ $!
+
+PCRE2$SHR.EXE : PCRE2.OLB
+ LINK/SHARE=PCRE2$SHR.EXE PCRE2:PCRE2.OLB/LIB,PCRE2:PCRE2$DEF.OPT/OPT
+
+PCRE2.OLB : $(OBJ)
+ LIB/CREA PCRE2.OLB $(OBJ)
+
+PCRE2DEMO.EXE : PCRE2DEMO.OBJ
+ LINK/EXE=PCRE2DEMO PCRE2DEMO,PCRE2:PCRE2.OPT/OPT
+
+PCRE2GREP.EXE : PCRE2GREP.OBJ
+ LINK/EXE=PCRE2GREP PCRE2GREP,PCRE2:PCRE2.OPT/OPT,ZLIB:ZLIB.OPT/OPT,BZ2LIB:BZIP2.OPT/OPT
+
+PCRE2.H : PCRE2.H_GENERIC
+ WRITE SYS$OUTPUT "Patching PCRE2.H"
+ COPY/CONCAT [-.VMS]PCRE2.H_PATCH,[]PCRE2.H_GENERIC PCRE2.H
+
+PCRE2_CHARTABLES.OBJ : PCRE2_CHARTABLES.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_CHARTABLES.C : PCRE2_CHARTABLES.C_DIST
+ COPY PCRE2_CHARTABLES.C_DIST PCRE2_CHARTABLES.C
+
+PCRE2DEMO.OBJ : PCRE2DEMO.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2GREP.OBJ : PCRE2GREP.C
+ $(CC) $(CFLAGS) /WARN=DIS=ALL $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2POSIX.OBJ : PCRE2POSIX.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2POSIX_TEST.OBJ : PCRE2POSIX_TEST.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2TEST.OBJ : PCRE2TEST.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_AUTO_POSSESS.OBJ : PCRE2_AUTO_POSSESS.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_CHKDINT.OBJ : PCRE2_CHKDINT.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_COMPILE.OBJ : PCRE2_COMPILE.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_CONFIG.OBJ : PCRE2_CONFIG.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_CONTEXT.OBJ : PCRE2_CONTEXT.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_CONVERT.OBJ : PCRE2_CONVERT.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_DFA_MATCH.OBJ : PCRE2_DFA_MATCH.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_DFTABLES.OBJ : PCRE2_DFTABLES.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_ERROR.OBJ : PCRE2_ERROR.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_EXTUNI.OBJ : PCRE2_EXTUNI.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_FIND_BRACKET.OBJ : PCRE2_FIND_BRACKET.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_FUZZSUPPORT.OBJ : PCRE2_FUZZSUPPORT.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_JIT_COMPILE.OBJ : PCRE2_JIT_COMPILE.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_JIT_MATCH.OBJ : PCRE2_JIT_MATCH.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_JIT_MISC.OBJ : PCRE2_JIT_MISC.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_JIT_TEST.OBJ : PCRE2_JIT_TEST.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_MAKETABLES.OBJ : PCRE2_MAKETABLES.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_MATCH.OBJ : PCRE2_MATCH.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_MATCH_DATA.OBJ : PCRE2_MATCH_DATA.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_NEWLINE.OBJ : PCRE2_NEWLINE.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_ORD2UTF.OBJ : PCRE2_ORD2UTF.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_PATTERN_INFO.OBJ : PCRE2_PATTERN_INFO.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_PRINTINT.OBJ : PCRE2_PRINTINT.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_SCRIPT_RUN.OBJ : PCRE2_SCRIPT_RUN.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_SERIALIZE.OBJ : PCRE2_SERIALIZE.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_STRING_UTILS.OBJ : PCRE2_STRING_UTILS.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_STUDY.OBJ : PCRE2_STUDY.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_SUBSTITUTE.OBJ : PCRE2_SUBSTITUTE.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_SUBSTRING.OBJ : PCRE2_SUBSTRING.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_TABLES.OBJ : PCRE2_TABLES.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_UCD.OBJ : PCRE2_UCD.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_UCPTABLES.OBJ : PCRE2_UCPTABLES.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_VALID_UTF.OBJ : PCRE2_VALID_UTF.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+PCRE2_XCLASS.OBJ : PCRE2_XCLASS.C
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+$!
+$!
+$WRITE SYS$OUTPUT "DESCRIP.MMS's have been created"
+$WRITE SYS$OUTPUT " "
+$WRITE SYS$OUTPUT " "
+$WRITE SYS$OUTPUT "Now you can type @BUILD "
+$!
+$EXIT:
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$DEL TEST.C;*
+$DEL TEST.OBJ;*
+$DEL TEST.EXE;*
+$DEL TEST.OPT;*
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+
--- /dev/null
+This is directory for OpenVMS support,
+provided shared and static library,
+pcre2grep utility also.
+
+Requires:
+bzip2 library : http://vaxvms.org/clamav/
+zlib library : http://vaxvms.org/libsdl/required.html
+
+
+To build the library please:
+
+@[.VMS]CONFIGURE.COM
+@BUILD
+
+After build, PCRE2$STARTUP.COM has been created
+it should be started before use (good place from LOGIN.COM)
+
+Feel free to contact:
+alexey@vaxman.de
+Alexey Chupahin
--- /dev/null
+#define _pcre2_default_compile_context_ vms_pcre2_def_cmpl_cntxt_
+#define _pcre2_default_convert_context_ vms_pcre2_def_cnvrt_cntxt_
+#define pcre2_set_compile_extra_options_8 vms_pcre2_set_cmpl_ext_opt_8
+#define pcre2_set_compile_recursion_guard_8 vms_pcre2_set_cmpl_rcrs_grd_8
+#define pcre2_set_recursion_memory_management_8 vms_pcre2_set_rcrs_mem_mng_8
+#define pcre2_match_data_create_from_pattern_8 vms_pcre2_m_d_crt_fr_patt_8
+#define pcre2_get_match_data_heapframes_size_8 vms_pcre2_get_m_d_hpfram_s_8
+#define pcre2_serialize_get_number_of_codes_8 vms_pcre2_ser_get_n_of_cod_8
+#define pcre2_substring_nametable_scan_8 vms_pcre2_substr_nmtab_scan_8
+#define pcre2_substring_length_bynumber_8 vms_pcre2_substr_len_bynum_8
+#define pcre2_substring_number_from_name_8 vms_pcre2_substr_num_f_nam_8
+#define pcre2_set_max_pattern_compiled_length vms_pcre2_set_max_pat_cmpl_len
--- /dev/null
+#ifndef MY_VMS_STDINT
+#define MY_VMS_STDINT
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#define SIZE_MAX UINT_MAX
+#define UINT32_MAX 4294967295u
+#define UINT16_MAX (65535)
+#endif