summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/pcre2
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/pcre2')
-rw-r--r--src/3rdparty/pcre2/CMakeLists.txt2
-rwxr-xr-xsrc/3rdparty/pcre2/import_from_pcre2_tarball.sh3
-rw-r--r--src/3rdparty/pcre2/qt_attribution.json8
-rw-r--r--src/3rdparty/pcre2/src/pcre2.h7
-rw-r--r--src/3rdparty/pcre2/src/pcre2_compile.c27
-rw-r--r--src/3rdparty/pcre2/src/pcre2_context.c10
-rw-r--r--src/3rdparty/pcre2/src/pcre2_error.c3
-rw-r--r--src/3rdparty/pcre2/src/pcre2_extuni.c28
-rw-r--r--src/3rdparty/pcre2/src/pcre2_intmodedep.h3
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_compile.c152
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_misc.c4
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h2
-rw-r--r--src/3rdparty/pcre2/src/pcre2_match.c2
-rw-r--r--src/3rdparty/pcre2/src/pcre2_tables.c12
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c6
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c23
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h76
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c411
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitLir.c301
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitLir.h243
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c521
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c505
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c473
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeLOONGARCH_64.c3765
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c6
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c6
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c288
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c583
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c510
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c437
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c283
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c1673
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c118
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c134
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c992
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitProtExecAllocator.c474
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitSerialize.c516
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitWXExecAllocator.c204
38 files changed, 7669 insertions, 5142 deletions
diff --git a/src/3rdparty/pcre2/CMakeLists.txt b/src/3rdparty/pcre2/CMakeLists.txt
index 22b90a57e1..ec549515d2 100644
--- a/src/3rdparty/pcre2/CMakeLists.txt
+++ b/src/3rdparty/pcre2/CMakeLists.txt
@@ -45,6 +45,8 @@ qt_internal_add_3rdparty_library(BundledPcre2
PCRE2_CODE_UNIT_WIDTH=16
PUBLIC_INCLUDE_DIRECTORIES
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+ CPE_VENDOR "pcre"
+ CPE_PRODUCT "pcre2"
)
qt_disable_warnings(BundledPcre2)
qt_set_symbol_visibility_hidden(BundledPcre2)
diff --git a/src/3rdparty/pcre2/import_from_pcre2_tarball.sh b/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
index 7f97ef8f63..09f2ca9283 100755
--- a/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
+++ b/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
@@ -89,6 +89,7 @@ FILES="
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
@@ -102,6 +103,8 @@ FILES="
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/sljitExecAllocatorPosix.c
src/sljit/allocator_src/sljitProtExecAllocatorPosix.c
src/sljit/allocator_src/sljitWXExecAllocatorPosix.c
diff --git a/src/3rdparty/pcre2/qt_attribution.json b/src/3rdparty/pcre2/qt_attribution.json
index b8862bd163..d9dc1ae697 100644
--- a/src/3rdparty/pcre2/qt_attribution.json
+++ b/src/3rdparty/pcre2/qt_attribution.json
@@ -8,8 +8,8 @@
"Description": "The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5.",
"Homepage": "http://www.pcre.org/",
- "Version": "10.43",
- "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/pcre2-10.43.tar.bz2",
+ "Version": "10.44",
+ "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.44/pcre2-10.44.tar.bz2",
"License": "BSD 3-clause \"New\" or \"Revised\" License with PCRE2 binary-like Packages Exception",
"LicenseId": "LicenseRef-BSD-3-Clause-with-PCRE2-Binary-Like-Packages-Exception",
"LicenseFile": "LICENCE",
@@ -25,8 +25,8 @@
"Path": "src/sljit",
"Description": "The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5.",
"Homepage": "http://www.pcre.org/",
- "Version": "10.43",
- "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/pcre2-10.43.tar.bz2",
+ "Version": "10.44",
+ "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.44/pcre2-10.44.tar.bz2",
"License": "BSD 2-clause \"Simplified\" License",
"LicenseId": "BSD-2-Clause",
"LicenseFile": "LICENCE-SLJIT",
diff --git a/src/3rdparty/pcre2/src/pcre2.h b/src/3rdparty/pcre2/src/pcre2.h
index d7a8ff5201..a322d9f2d5 100644
--- a/src/3rdparty/pcre2/src/pcre2.h
+++ b/src/3rdparty/pcre2/src/pcre2.h
@@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* 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
@@ -604,6 +604,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
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 \
pcre2_set_newline(pcre2_compile_context *, uint32_t); \
@@ -901,6 +903,7 @@ pcre2_compile are called by application code. */
#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_)
diff --git a/src/3rdparty/pcre2/src/pcre2_compile.c b/src/3rdparty/pcre2/src/pcre2_compile.c
index 8b364977c4..8e6787aba3 100644
--- a/src/3rdparty/pcre2/src/pcre2_compile.c
+++ b/src/3rdparty/pcre2/src/pcre2_compile.c
@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-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
@@ -808,7 +808,8 @@ enum { ERR0 = COMPILE_ERROR_BASE,
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
@@ -7549,7 +7550,8 @@ for (;; pptr++)
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;
@@ -7599,7 +7601,7 @@ for (;; pptr++)
{
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;
@@ -9908,7 +9910,7 @@ do
*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
@@ -10601,14 +10603,21 @@ if (length > MAX_PATTERN_SIZE)
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)
diff --git a/src/3rdparty/pcre2/src/pcre2_context.c b/src/3rdparty/pcre2/src/pcre2_context.c
index 0bc2ea0b04..9edbd1b2ae 100644
--- a/src/3rdparty/pcre2/src/pcre2_context.c
+++ b/src/3rdparty/pcre2/src/pcre2_context.c
@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-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
@@ -136,6 +136,7 @@ const pcre2_compile_context PRIV(default_compile_context) = {
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 */
@@ -353,6 +354,13 @@ 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)
{
switch(newline)
diff --git a/src/3rdparty/pcre2/src/pcre2_error.c b/src/3rdparty/pcre2/src/pcre2_error.c
index 1569f6315f..7fa997aa95 100644
--- a/src/3rdparty/pcre2/src/pcre2_error.c
+++ b/src/3rdparty/pcre2/src/pcre2_error.c
@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-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
@@ -189,6 +189,7 @@ static const unsigned char compile_error_texts[] =
"\\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. */
diff --git a/src/3rdparty/pcre2/src/pcre2_extuni.c b/src/3rdparty/pcre2/src/pcre2_extuni.c
index b23946b0d1..4ed9f00c55 100644
--- a/src/3rdparty/pcre2/src/pcre2_extuni.c
+++ b/src/3rdparty/pcre2/src/pcre2_extuni.c
@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-2021 University of Cambridge
+ New API code Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -75,7 +75,11 @@ return NULL;
* 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
@@ -92,6 +96,7 @@ PCRE2_SPTR
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)
@@ -102,6 +107,12 @@ 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. */
@@ -129,12 +140,15 @@ while (eptr < end_subject)
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;
diff --git a/src/3rdparty/pcre2/src/pcre2_intmodedep.h b/src/3rdparty/pcre2/src/pcre2_intmodedep.h
index 5fcddce5fe..9bd9e694a4 100644
--- a/src/3rdparty/pcre2/src/pcre2_intmodedep.h
+++ b/src/3rdparty/pcre2/src/pcre2_intmodedep.h
@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-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
@@ -568,6 +568,7 @@ typedef struct pcre2_real_compile_context {
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;
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_compile.c b/src/3rdparty/pcre2/src/pcre2_jit_compile.c
index 050063ec6d..92f4fb858b 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_compile.c
+++ b/src/3rdparty/pcre2/src/pcre2_jit_compile.c
@@ -8,7 +8,7 @@ and semantics are as close as possible to those of the Perl 5 language.
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
@@ -288,7 +288,7 @@ typedef struct bracket_backtrack {
/* 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;
@@ -5891,7 +5891,7 @@ while (TRUE)
chr++;
}
while (byte != 0);
- chr = (chr + 7) & ~7;
+ chr = (chr + 7) & (sljit_u32)(~7);
}
}
while (chars->count != 255 && bytes < bytes_end);
@@ -5951,7 +5951,10 @@ while (TRUE)
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);
@@ -6183,25 +6186,34 @@ if (max < 1)
/* 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
@@ -6941,7 +6953,7 @@ int i, byte, length = 0;
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; )
{
@@ -6958,7 +6970,7 @@ for (i = 0; i < 256; )
ranges[length] = i;
length++;
bit = cbit;
- all = -cbit;
+ all = (sljit_u8)-cbit; /* sign extend bit into byte */
}
i++;
}
@@ -7102,7 +7114,7 @@ for (i = 0; i < 32; i++)
byte = bits[i];
if (nclass)
- byte = ~byte;
+ byte = (sljit_u8)~byte;
j = 0;
while (byte != 0)
@@ -8003,7 +8015,7 @@ if (unicode_status & XCLASS_NEEDS_UCD)
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;
@@ -8114,7 +8126,7 @@ if (unicode_status & XCLASS_NEEDS_UCD)
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)
@@ -8685,6 +8697,10 @@ return cc;
#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;
@@ -8692,6 +8708,7 @@ PCRE2_SPTR end_subject = args->end;
int lgb, rgb, ricount;
PCRE2_SPTR prevcc, endcc, bptr;
BOOL first = TRUE;
+BOOL was_ep_ZWJ = FALSE;
uint32_t c;
prevcc = cc;
@@ -8712,6 +8729,12 @@ do
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. */
@@ -8736,11 +8759,15 @@ do
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;
@@ -8753,6 +8780,10 @@ return 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;
@@ -8760,6 +8791,7 @@ PCRE2_SPTR end_subject = args->end;
int lgb, rgb, ricount;
PCRE2_SPTR prevcc, endcc, bptr;
BOOL first = TRUE;
+BOOL was_ep_ZWJ = FALSE;
uint32_t c;
prevcc = cc;
@@ -8780,6 +8812,12 @@ do
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. */
@@ -8803,11 +8841,15 @@ do
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;
@@ -8818,6 +8860,10 @@ while (cc < end_subject);
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;
@@ -8825,6 +8871,7 @@ PCRE2_SPTR end_subject = args->end;
int lgb, rgb, ricount;
PCRE2_SPTR bptr;
uint32_t c;
+BOOL was_ep_ZWJ = FALSE;
/* Patch by PH */
/* GETCHARINC(c, cc); */
@@ -8848,6 +8895,12 @@ while (cc < end_subject)
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. */
@@ -8875,11 +8928,15 @@ while (cc < end_subject)
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++;
@@ -9836,7 +9893,7 @@ BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL();
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;
@@ -11227,7 +11284,7 @@ if (has_alternatives)
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();
@@ -11314,17 +11371,22 @@ if (bra == OP_BRAMINZERO)
/* 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;
}
@@ -13005,7 +13067,7 @@ struct sljit_jump *once = NULL;
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)
{
@@ -13166,8 +13228,8 @@ else if (has_alternatives)
{
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
@@ -13320,7 +13382,7 @@ if (has_alternatives)
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)
@@ -13346,7 +13408,7 @@ if (has_alternatives)
}
else
{
- sljit_set_put_label(put_label, LABEL());
+ sljit_set_label(mov_addr, LABEL());
sljit_emit_op0(compiler, SLJIT_ENDBR);
}
}
@@ -13878,7 +13940,7 @@ jump_list *match = NULL;
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;
@@ -13941,7 +14003,7 @@ while (1)
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);
}
@@ -13974,7 +14036,7 @@ while (1)
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
@@ -13985,7 +14047,7 @@ while (1)
}
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
@@ -14303,7 +14365,7 @@ if (common->has_then)
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);
@@ -14718,7 +14780,7 @@ if (common->getucdtype != NULL)
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);
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_misc.c b/src/3rdparty/pcre2/src/pcre2_jit_misc.c
index bb6a5589cb..c3abc0b33b 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_misc.c
+++ b/src/3rdparty/pcre2/src/pcre2_jit_misc.c
@@ -141,8 +141,8 @@ if (startsize == 0 || maxsize == 0 || maxsize > SIZE_MAX - STACK_GROWTH_RATE)
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;
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h b/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h
index 783a85f50e..502977fc32 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h
+++ b/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h
@@ -2176,7 +2176,7 @@ struct sljit_label *restart;
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)
diff --git a/src/3rdparty/pcre2/src/pcre2_match.c b/src/3rdparty/pcre2/src/pcre2_match.c
index b4a970313d..6c422c2e5e 100644
--- a/src/3rdparty/pcre2/src/pcre2_match.c
+++ b/src/3rdparty/pcre2/src/pcre2_match.c
@@ -5862,7 +5862,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
{
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;
diff --git a/src/3rdparty/pcre2/src/pcre2_tables.c b/src/3rdparty/pcre2/src/pcre2_tables.c
index e00252f1eb..097a1acca8 100644
--- a/src/3rdparty/pcre2/src/pcre2_tables.c
+++ b/src/3rdparty/pcre2/src/pcre2_tables.c
@@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
- New API code Copyright (c) 2016-2021 University of Cambridge
+ New API code Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -171,9 +171,9 @@ are implementing).
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
@@ -203,8 +203,8 @@ const uint32_t PRIV(ucp_gbtable)[] = {
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
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c
index 95b9842fa9..9bd2094f46 100644
--- a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c
@@ -41,9 +41,10 @@
#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;
@@ -70,6 +71,9 @@ static SLJIT_INLINE int get_map_jit_flag(void)
}
return map_jit_flag;
}
+#else /* !defined(MAP_JIT) */
+#define SLJIT_MAP_JIT (0)
+#endif
#elif defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c
index 6cd391104c..4e1119bc40 100644
--- a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c
@@ -181,8 +181,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
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;
@@ -230,26 +229,25 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw 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));
@@ -269,8 +267,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
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);
}
@@ -308,7 +305,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
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);
@@ -317,14 +314,14 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
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 */
diff --git a/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h b/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
index ce4e7b04ec..de06dd8e0c 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
@@ -49,8 +49,8 @@ extern "C" {
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
@@ -98,6 +98,10 @@ extern "C" {
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
@@ -132,23 +136,23 @@ extern "C" {
*/
#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
/***************************/
@@ -198,7 +202,7 @@ extern "C" {
/* 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. */
@@ -358,7 +362,8 @@ typedef long int sljit_sw;
#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;
@@ -399,6 +404,10 @@ typedef double sljit_f64;
#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
@@ -522,19 +531,6 @@ typedef double sljit_f64;
#define SLJIT_FUNC
#endif /* !SLJIT_FUNC */
-/* Disable instrumentation for these functions as they may not be sound */
-#ifndef SLJIT_FUNC_ATTRIBUTE
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer)
-#define SLJIT_FUNC_ATTRIBUTE __attribute__((no_sanitize("memory")))
-#endif /* __has_feature(memory_sanitizer) */
-#endif /* defined(__has_feature) */
-#endif
-
-#ifndef SLJIT_FUNC_ATTRIBUTE
-#define SLJIT_FUNC_ATTRIBUTE
-#endif
-
#ifndef SLJIT_INDIRECT_CALL
#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (!defined _CALL_ELF || _CALL_ELF == 1)) \
|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
@@ -570,9 +566,9 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
#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 */
@@ -592,6 +588,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -612,6 +611,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -624,6 +626,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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)
@@ -634,6 +639,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -646,6 +654,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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)
@@ -670,6 +681,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -681,6 +695,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -714,6 +731,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -725,6 +745,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
@@ -738,6 +761,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#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
diff --git a/src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c b/src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c
deleted file mode 100644
index 92d940ddc2..0000000000
--- a/src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * 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.
- */
-
-/*
- This file contains a simple executable memory allocator
-
- It is assumed, that executable code blocks are usually medium (or sometimes
- large) memory blocks, and the allocator is not too frequently called (less
- optimized than other allocators). Thus, using it as a generic allocator is
- not suggested.
-
- How does it work:
- Memory is allocated in continuous memory areas called chunks by alloc_chunk()
- Chunk format:
- [ block ][ block ] ... [ block ][ block terminator ]
-
- All blocks and the block terminator is started with block_header. The block
- header contains the size of the previous and the next block. These sizes
- can also contain special values.
- Block size:
- 0 - The block is a free_block, with a different size member.
- 1 - The block is a block terminator.
- n - The block is used at the moment, and the value contains its size.
- Previous block size:
- 0 - This is the first block of the memory chunk.
- n - The size of the previous block.
-
- Using these size values we can go forward or backward on the block chain.
- The unused blocks are stored in a chain list pointed by free_blocks. This
- list is useful if we need to find a suitable memory area when the allocator
- is called.
-
- When a block is freed, the new free block is connected to its adjacent free
- blocks if possible.
-
- [ free block ][ used block ][ free block ]
- and "used block" is freed, the three blocks are connected together:
- [ one big free block ]
-*/
-
-/* --------------------------------------------------------------------- */
-/* System (OS) functions */
-/* --------------------------------------------------------------------- */
-
-/* 64 KByte. */
-#define CHUNK_SIZE (sljit_uw)0x10000u
-
-/*
- alloc_chunk / free_chunk :
- * allocate executable system memory chunks
- * the size is always divisible by CHUNK_SIZE
- SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
- * provided as part of sljitUtils
- * only the allocator requires this lock, sljit is fully thread safe
- as it only uses local variables
-*/
-
-#ifdef _WIN32
-#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
-
-static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
-{
- return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
-}
-
-static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
-{
- SLJIT_UNUSED_ARG(size);
- VirtualFree(chunk, 0, MEM_RELEASE);
-}
-
-#else /* POSIX */
-
-#if defined(__APPLE__) && defined(MAP_JIT)
-/*
- On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a
- version where it's OK to have more than one JIT block or where MAP_JIT is
- required.
- On non-macOS systems, returns MAP_JIT if it is defined.
-*/
-#include <TargetConditionals.h>
-#if TARGET_OS_OSX
-#if defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86
-#ifdef MAP_ANON
-#include <sys/utsname.h>
-#include <stdlib.h>
-
-#define SLJIT_MAP_JIT (get_map_jit_flag())
-
-static SLJIT_INLINE int get_map_jit_flag()
-{
- size_t page_size;
- void *ptr;
- struct utsname name;
- static int map_jit_flag = -1;
-
- if (map_jit_flag < 0) {
- map_jit_flag = 0;
- uname(&name);
-
- /* Kernel version for 10.14.0 (Mojave) or later */
- if (atoi(name.release) >= 18) {
- page_size = get_page_alignment() + 1;
- /* Only use MAP_JIT if a hardened runtime is used */
- ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON, -1, 0);
-
- if (ptr != MAP_FAILED)
- munmap(ptr, page_size);
- else
- map_jit_flag = MAP_JIT;
- }
- }
- return map_jit_flag;
-}
-#endif /* MAP_ANON */
-#else /* !SLJIT_CONFIG_X86 */
-#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
-#error "Unsupported architecture"
-#endif /* SLJIT_CONFIG_ARM */
-#include <AvailabilityMacros.h>
-#include <pthread.h>
-
-#define SLJIT_MAP_JIT (MAP_JIT)
-#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
- apple_update_wx_flags(enable_exec)
-
-static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
-{
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000
- pthread_jit_write_protect_np(enable_exec);
-#else
-#error "Must target Big Sur or newer"
-#endif /* BigSur */
-}
-#endif /* SLJIT_CONFIG_X86 */
-#else /* !TARGET_OS_OSX */
-#define SLJIT_MAP_JIT (MAP_JIT)
-#endif /* TARGET_OS_OSX */
-#endif /* __APPLE__ && MAP_JIT */
-#ifndef SLJIT_UPDATE_WX_FLAGS
-#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
-#endif /* !SLJIT_UPDATE_WX_FLAGS */
-#ifndef SLJIT_MAP_JIT
-#define SLJIT_MAP_JIT (0)
-#endif /* !SLJIT_MAP_JIT */
-
-static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
-{
- void *retval;
- int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- int flags = MAP_PRIVATE;
- int fd = -1;
-
-#ifdef PROT_MAX
- prot |= PROT_MAX(prot);
-#endif
-
-#ifdef MAP_ANON
- flags |= MAP_ANON | SLJIT_MAP_JIT;
-#else /* !MAP_ANON */
- if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
- return NULL;
-
- fd = dev_zero;
-#endif /* MAP_ANON */
-
- retval = mmap(NULL, size, prot, flags, fd, 0);
- if (retval == MAP_FAILED)
- return NULL;
-
-#ifdef __FreeBSD__
- /* HardenedBSD's mmap lies, so check permissions again */
- if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
- munmap(retval, size);
- return NULL;
- }
-#endif /* FreeBSD */
-
- SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0);
-
- return retval;
-}
-
-static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
-{
- munmap(chunk, size);
-}
-
-#endif /* windows */
-
-/* --------------------------------------------------------------------- */
-/* Common functions */
-/* --------------------------------------------------------------------- */
-
-#define CHUNK_MASK (~(CHUNK_SIZE - 1))
-
-struct block_header {
- sljit_uw size;
- sljit_uw prev_size;
-};
-
-struct free_block {
- struct block_header header;
- struct free_block *next;
- struct free_block *prev;
- sljit_uw size;
-};
-
-#define AS_BLOCK_HEADER(base, offset) \
- ((struct block_header*)(((sljit_u8*)base) + offset))
-#define AS_FREE_BLOCK(base, offset) \
- ((struct free_block*)(((sljit_u8*)base) + offset))
-#define MEM_START(base) ((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
-#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7)
-
-static struct free_block* free_blocks;
-static sljit_uw allocated_size;
-static sljit_uw total_size;
-
-static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
-{
- free_block->header.size = 0;
- free_block->size = size;
-
- free_block->next = free_blocks;
- free_block->prev = NULL;
- if (free_blocks)
- free_blocks->prev = free_block;
- free_blocks = free_block;
-}
-
-static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
-{
- if (free_block->next)
- free_block->next->prev = free_block->prev;
-
- if (free_block->prev)
- free_block->prev->next = free_block->next;
- else {
- SLJIT_ASSERT(free_blocks == free_block);
- free_blocks = free_block->next;
- }
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
-{
- struct block_header *header;
- struct block_header *next_header;
- struct free_block *free_block;
- sljit_uw chunk_size;
-
- SLJIT_ALLOCATOR_LOCK();
- if (size < (64 - sizeof(struct block_header)))
- size = (64 - sizeof(struct block_header));
- size = ALIGN_SIZE(size);
-
- free_block = free_blocks;
- while (free_block) {
- if (free_block->size >= size) {
- chunk_size = free_block->size;
- SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
- if (chunk_size > size + 64) {
- /* We just cut a block from the end of the free block. */
- chunk_size -= size;
- free_block->size = chunk_size;
- header = AS_BLOCK_HEADER(free_block, chunk_size);
- header->prev_size = chunk_size;
- AS_BLOCK_HEADER(header, size)->prev_size = size;
- }
- else {
- sljit_remove_free_block(free_block);
- header = (struct block_header*)free_block;
- size = chunk_size;
- }
- allocated_size += size;
- header->size = size;
- SLJIT_ALLOCATOR_UNLOCK();
- return MEM_START(header);
- }
- free_block = free_block->next;
- }
-
- chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
- header = (struct block_header*)alloc_chunk(chunk_size);
- if (!header) {
- SLJIT_ALLOCATOR_UNLOCK();
- return NULL;
- }
-
- chunk_size -= sizeof(struct block_header);
- total_size += chunk_size;
-
- header->prev_size = 0;
- if (chunk_size > size + 64) {
- /* Cut the allocated space into a free and a used block. */
- allocated_size += size;
- header->size = size;
- chunk_size -= size;
-
- free_block = AS_FREE_BLOCK(header, size);
- free_block->header.prev_size = size;
- sljit_insert_free_block(free_block, chunk_size);
- next_header = AS_BLOCK_HEADER(free_block, chunk_size);
- }
- else {
- /* All space belongs to this allocation. */
- allocated_size += chunk_size;
- header->size = chunk_size;
- next_header = AS_BLOCK_HEADER(header, chunk_size);
- }
- next_header->size = 1;
- next_header->prev_size = chunk_size;
- SLJIT_ALLOCATOR_UNLOCK();
- return MEM_START(header);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
-{
- struct block_header *header;
- struct free_block* free_block;
-
- SLJIT_ALLOCATOR_LOCK();
- header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
- allocated_size -= header->size;
-
- /* Connecting free blocks together if possible. */
- SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
-
- /* If header->prev_size == 0, free_block will equal to header.
- In this case, free_block->header.size will be > 0. */
- free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
- if (SLJIT_UNLIKELY(!free_block->header.size)) {
- free_block->size += header->size;
- header = AS_BLOCK_HEADER(free_block, free_block->size);
- header->prev_size = free_block->size;
- }
- else {
- free_block = (struct free_block*)header;
- sljit_insert_free_block(free_block, header->size);
- }
-
- header = AS_BLOCK_HEADER(free_block, free_block->size);
- if (SLJIT_UNLIKELY(!header->size)) {
- free_block->size += ((struct free_block*)header)->size;
- sljit_remove_free_block((struct free_block*)header);
- header = AS_BLOCK_HEADER(free_block, free_block->size);
- header->prev_size = free_block->size;
- }
-
- /* The whole chunk is free. */
- if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
- /* If this block is freed, we still have (allocated_size / 2) free space. */
- if (total_size - free_block->size > (allocated_size * 3 / 2)) {
- total_size -= free_block->size;
- sljit_remove_free_block(free_block);
- free_chunk(free_block, free_block->size + sizeof(struct block_header));
- }
- }
-
- SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
- SLJIT_ALLOCATOR_UNLOCK();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
-{
- struct free_block* free_block;
- struct free_block* next_free_block;
-
- SLJIT_ALLOCATOR_LOCK();
- SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
-
- free_block = free_blocks;
- while (free_block) {
- next_free_block = free_block->next;
- if (!free_block->header.prev_size &&
- AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
- total_size -= free_block->size;
- sljit_remove_free_block(free_block);
- free_chunk(free_block, free_block->size + sizeof(struct block_header));
- }
- free_block = next_free_block;
- }
-
- SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
- SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
- SLJIT_ALLOCATOR_UNLOCK();
-}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitLir.c b/src/3rdparty/pcre2/src/sljit/sljitLir.c
index 6f19300081..2dca17cd6f 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitLir.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitLir.c
@@ -152,28 +152,43 @@
#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
@@ -181,25 +196,30 @@
# 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)
@@ -210,8 +230,12 @@
#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)
@@ -253,8 +277,11 @@
# 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 */
@@ -268,6 +295,8 @@
# 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. */
@@ -289,6 +318,14 @@
/* 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)
@@ -417,7 +454,7 @@ static sljit_s32 compiler_initialized = 0;
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)
@@ -428,10 +465,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo
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);
@@ -442,7 +480,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo
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);
@@ -537,37 +574,17 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compi
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;
}
}
@@ -575,18 +592,11 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sl
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)
@@ -681,31 +691,66 @@ static SLJIT_INLINE void reverse_buf(struct sljit_compiler *compiler)
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,
@@ -746,8 +791,9 @@ static SLJIT_INLINE void set_set_context(struct sljit_compiler *compiler,
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;
@@ -758,7 +804,21 @@ static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler
{
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;
@@ -769,26 +829,13 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp
{
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))
@@ -1106,6 +1153,10 @@ static const char* op2_names[] = {
"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",
@@ -1187,13 +1238,19 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_generate_code(struct sljit_com
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)
@@ -1202,9 +1259,9 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compil
#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);
@@ -1238,11 +1295,17 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compil
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);
@@ -1259,9 +1322,9 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compi
#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);
@@ -1295,11 +1358,17 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compi
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);
@@ -1308,6 +1377,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compi
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)) {
@@ -1636,6 +1707,33 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler
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,
@@ -1721,11 +1819,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 t
#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;
@@ -2927,14 +3025,14 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compil
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");
}
@@ -3058,6 +3156,8 @@ static sljit_s32 sljit_emit_fmem_unaligned(struct sljit_compiler *compiler, slji
# 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)
@@ -3288,7 +3388,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler
#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,
diff --git a/src/3rdparty/pcre2/src/sljit/sljitLir.h b/src/3rdparty/pcre2/src/sljit/sljitLir.h
index 2ba6683c74..8b6fa69a0a 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitLir.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitLir.h
@@ -427,7 +427,10 @@ struct sljit_memory_fragment {
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;
};
@@ -443,36 +446,35 @@ struct sljit_jump {
} 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. */
@@ -492,15 +494,16 @@ struct sljit_compiler {
#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. */
@@ -511,7 +514,7 @@ struct sljit_compiler {
/* 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. */
@@ -520,40 +523,45 @@ struct sljit_compiler {
#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)
@@ -564,7 +572,7 @@ struct sljit_compiler {
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) \
@@ -572,7 +580,7 @@ struct sljit_compiler {
/* 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 */
};
/* --------------------------------------------------------------------- */
@@ -583,12 +591,10 @@ struct sljit_compiler {
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);
@@ -619,20 +625,31 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compi
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. */
@@ -708,6 +725,11 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler
#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,
@@ -777,17 +799,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type);
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,
@@ -855,7 +882,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c
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.
@@ -913,6 +940,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c
#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
@@ -1084,7 +1118,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
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) */
@@ -1251,6 +1285,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
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.
@@ -1298,7 +1345,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
/* 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
@@ -1350,7 +1397,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
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)
@@ -1395,7 +1442,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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)
@@ -1416,7 +1463,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
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)
@@ -2138,17 +2185,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
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; }
@@ -2222,6 +2267,98 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *com
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 */
/* --------------------------------------------------------------------- */
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
index d44616d800..a253c06f01 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
@@ -120,6 +120,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1)
#define LDREX 0xe1900f9f
#define LDREXB 0xe1d00f9f
#define LDREXH 0xe1f00f9f
+#define MLA 0xe0200090
#define MOV 0xe1a00000
#define MUL 0xe0000090
#define MVN 0xe1e00000
@@ -482,11 +483,12 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
#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));
}
@@ -494,6 +496,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
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);
@@ -508,20 +511,8 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
}
}
#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;
}
@@ -529,7 +520,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
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;
@@ -628,7 +619,7 @@ static sljit_uw get_imm(sljit_uw imm);
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;
@@ -720,18 +711,120 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off
#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;
@@ -744,22 +837,22 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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)
@@ -773,33 +866,24 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
}
@@ -807,59 +891,59 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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)
@@ -879,14 +963,20 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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);
@@ -901,7 +991,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
}
@@ -914,43 +1004,64 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
}
@@ -967,30 +1078,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
@@ -1113,7 +1208,7 @@ static const sljit_ins data_transfer_insts[16] = {
/* 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). */
@@ -1498,7 +1593,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c
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) {
@@ -1515,7 +1610,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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) {
@@ -1527,7 +1622,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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) {
@@ -1543,11 +1638,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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 */
@@ -1563,9 +1658,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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:
@@ -1601,10 +1696,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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)
@@ -1654,6 +1750,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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;
@@ -1973,6 +2072,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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;
@@ -1982,7 +2082,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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));
@@ -2068,17 +2168,6 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
}
} 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;
@@ -2088,21 +2177,44 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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 {
@@ -2122,8 +2234,8 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
}
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;
@@ -2368,7 +2480,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
+ return sljit_emit_op2(compiler, op, 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,
@@ -2533,8 +2663,8 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags,
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;
}
@@ -2547,25 +2677,25 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags,
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,
@@ -2675,7 +2805,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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;
@@ -2745,7 +2875,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
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;
@@ -2974,27 +3104,25 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
#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;
}
@@ -3264,14 +3392,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
#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;
}
@@ -3425,7 +3556,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
}
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;
@@ -3488,8 +3619,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com
}
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);
@@ -4444,6 +4575,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
@@ -4454,22 +4589,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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;
@@ -4478,24 +4609,28 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct slj
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);
}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
index b268582f42..5331ebdf42 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
@@ -71,6 +71,8 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#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
@@ -202,77 +204,263 @@ static SLJIT_INLINE sljit_s32 emit_imm64_const(struct sljit_compiler *compiler,
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;
@@ -280,67 +468,73 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_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++;
@@ -350,7 +544,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)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;
}
@@ -358,61 +552,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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);
@@ -693,7 +840,6 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
imm = (flags & ARG2_IMM) ? arg2 : arg1;
switch (op) {
- case SLJIT_MUL:
case SLJIT_CLZ:
case SLJIT_CTZ:
case SLJIT_REV:
@@ -703,6 +849,8 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
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;
@@ -957,6 +1105,9 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
/* 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;
@@ -1031,14 +1182,20 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s
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));
@@ -1422,7 +1579,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
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) {
@@ -1472,7 +1629,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
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);
@@ -1534,7 +1691,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
mem_flags = INT_SIZE;
}
- if (dst == TMP_REG1)
+ if (dst == TMP_REG2)
flags |= UNUSED_RETURN;
if (src1 & SLJIT_MEM) {
@@ -1572,7 +1729,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, op, TMP_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,
@@ -1753,18 +1927,18 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags,
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) {
@@ -1772,18 +1946,18 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags,
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,
@@ -1910,7 +2084,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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;
@@ -2180,14 +2354,14 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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;
}
@@ -2236,9 +2410,11 @@ static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compi
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;
}
@@ -2252,8 +2428,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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));
}
@@ -2264,9 +2440,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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,
@@ -2314,7 +2491,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
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);
}
@@ -2361,11 +2538,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
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);
@@ -2386,8 +2563,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com
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);
@@ -2554,13 +2731,13 @@ static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, slj
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;
@@ -2570,11 +2747,11 @@ static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, slj
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;
@@ -2585,16 +2762,16 @@ static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, slj
}
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,
@@ -2802,8 +2979,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
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));
@@ -2872,8 +3049,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
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) {
@@ -3030,7 +3207,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c
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) {
@@ -3040,8 +3217,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c
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;
}
@@ -3264,26 +3441,28 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
index c27c50ddb3..799954a859 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
@@ -157,6 +157,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1)
#define LSRSI 0x0800
#define LSR_W 0xfa20f000
#define LSR_WI 0xea4f0010
+#define MLA 0xfb000000
#define MOV 0x4600
#define MOVS 0x0000
#define MOVSI 0x2000
@@ -292,7 +293,7 @@ static sljit_s32 push_inst32(struct sljit_compiler *compiler, sljit_ins inst)
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)));
@@ -300,137 +301,262 @@ static SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler,
| 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;
@@ -438,64 +564,74 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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++;
@@ -505,7 +641,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
} 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;
}
@@ -513,21 +649,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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);
@@ -657,10 +786,11 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst,
/* 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;
@@ -686,6 +816,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
case SLJIT_REV_U32:
case SLJIT_REV_S32:
case SLJIT_MUL:
+ case SLJIT_MULADD:
/* No form with immediate operand. */
break;
case SLJIT_MOV:
@@ -921,17 +1052,17 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
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));
@@ -966,10 +1097,10 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
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));
@@ -985,37 +1116,44 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
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();
@@ -1779,14 +1917,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
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) {
@@ -1826,35 +1963,37 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
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;
}
@@ -1863,7 +2002,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
- sljit_s32 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));
@@ -1871,36 +2010,34 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
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,
@@ -1914,6 +2051,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
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,
@@ -2228,7 +2382,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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;
@@ -2519,7 +2673,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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);
@@ -2535,6 +2688,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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;
}
@@ -2800,8 +2955,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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));
}
@@ -2968,7 +3124,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
}
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;
@@ -3040,8 +3196,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com
}
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));
@@ -4106,25 +4262,26 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeLOONGARCH_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeLOONGARCH_64.c
new file mode 100644
index 0000000000..2e1d742aee
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeLOONGARCH_64.c
@@ -0,0 +1,3765 @@
+/*
+ * 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 const char* sljit_get_platform_name(void)
+{
+ return "LOONGARCH" SLJIT_CPUINFO;
+}
+
+typedef sljit_u32 sljit_ins;
+
+#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
+#define TMP_ZERO 0
+
+/* Flags are kept in volatile registers. */
+#define EQUAL_FLAG (SLJIT_NUMBER_OF_REGISTERS + 5)
+#define RETURN_ADDR_REG TMP_REG2
+#define OTHER_FLAG (SLJIT_NUMBER_OF_REGISTERS + 6)
+
+#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 22, 31, 30, 29, 28, 27, 26, 25, 24, 23, 3, 13, 1, 14, 12, 15
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+ 0, 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 31, 30, 29, 28, 27, 26, 25, 24, 8, 9
+};
+
+/* --------------------------------------------------------------------- */
+/* Instrucion forms */
+/* --------------------------------------------------------------------- */
+
+/*
+LoongArch instructions are 32 bits wide, belonging to 9 basic instruction formats (and variants of them):
+
+| Format name | Composition |
+| 2R | Opcode + Rj + Rd |
+| 3R | Opcode + Rk + Rj + Rd |
+| 4R | Opcode + Ra + Rk + Rj + Rd |
+| 2RI8 | Opcode + I8 + Rj + Rd |
+| 2RI12 | Opcode + I12 + Rj + Rd |
+| 2RI14 | Opcode + I14 + Rj + Rd |
+| 2RI16 | Opcode + I16 + Rj + Rd |
+| 1RI21 | Opcode + I21L + Rj + I21H |
+| I26 | Opcode + I26L + I26H |
+
+Rd is the destination register operand, while Rj, Rk and Ra (“a” stands for “additional”) are the source register operands.
+I8/I12/I14/I16/I21/I26 are immediate operands of respective width. The longer I21 and I26 are stored in separate higher and
+lower parts in the instruction word, denoted by the “L” and “H” suffixes. */
+
+#define RD(rd) ((sljit_ins)reg_map[rd])
+#define RJ(rj) ((sljit_ins)reg_map[rj] << 5)
+#define RK(rk) ((sljit_ins)reg_map[rk] << 10)
+#define RA(ra) ((sljit_ins)reg_map[ra] << 15)
+
+#define FD(fd) ((sljit_ins)reg_map[fd])
+#define FRD(fd) ((sljit_ins)freg_map[fd])
+#define FRJ(fj) ((sljit_ins)freg_map[fj] << 5)
+#define FRK(fk) ((sljit_ins)freg_map[fk] << 10)
+#define FRA(fa) ((sljit_ins)freg_map[fa] << 15)
+
+#define IMM_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 OPC_I26(opc) ((sljit_ins)(opc) << 26)
+#define OPC_1RI21(opc) ((sljit_ins)(opc) << 26)
+#define OPC_2RI16(opc) ((sljit_ins)(opc) << 26)
+#define OPC_2RI14(opc) ((sljit_ins)(opc) << 24)
+#define OPC_2RI12(opc) ((sljit_ins)(opc) << 22)
+#define OPC_2RI8(opc) ((sljit_ins)(opc) << 18)
+#define OPC_4R(opc) ((sljit_ins)(opc) << 20)
+#define OPC_3R(opc) ((sljit_ins)(opc) << 15)
+#define OPC_2R(opc) ((sljit_ins)(opc) << 10)
+#define OPC_1RI20(opc) ((sljit_ins)(opc) << 25)
+
+/* Arithmetic operation instructions */
+#define ADD_W OPC_3R(0x20)
+#define ADD_D OPC_3R(0x21)
+#define SUB_W OPC_3R(0x22)
+#define SUB_D OPC_3R(0x23)
+#define ADDI_W OPC_2RI12(0xa)
+#define ADDI_D OPC_2RI12(0xb)
+#define ANDI OPC_2RI12(0xd)
+#define ORI OPC_2RI12(0xe)
+#define XORI OPC_2RI12(0xf)
+#define ADDU16I_D OPC_2RI16(0x4)
+#define LU12I_W OPC_1RI20(0xa)
+#define LU32I_D OPC_1RI20(0xb)
+#define LU52I_D OPC_2RI12(0xc)
+#define SLT OPC_3R(0x24)
+#define SLTU OPC_3R(0x25)
+#define SLTI OPC_2RI12(0x8)
+#define SLTUI OPC_2RI12(0x9)
+#define PCADDI OPC_1RI20(0xc)
+#define PCALAU12I OPC_1RI20(0xd)
+#define PCADDU12I OPC_1RI20(0xe)
+#define PCADDU18I OPC_1RI20(0xf)
+#define NOR OPC_3R(0x28)
+#define AND OPC_3R(0x29)
+#define OR OPC_3R(0x2a)
+#define XOR OPC_3R(0x2b)
+#define ORN OPC_3R(0x2c)
+#define ANDN OPC_3R(0x2d)
+#define MUL_W OPC_3R(0x38)
+#define MULH_W OPC_3R(0x39)
+#define MULH_WU OPC_3R(0x3a)
+#define MUL_D OPC_3R(0x3b)
+#define MULH_D OPC_3R(0x3c)
+#define MULH_DU OPC_3R(0x3d)
+#define MULW_D_W OPC_3R(0x3e)
+#define MULW_D_WU OPC_3R(0x3f)
+#define DIV_W OPC_3R(0x40)
+#define MOD_W OPC_3R(0x41)
+#define DIV_WU OPC_3R(0x42)
+#define MOD_WU OPC_3R(0x43)
+#define DIV_D OPC_3R(0x44)
+#define MOD_D OPC_3R(0x45)
+#define DIV_DU OPC_3R(0x46)
+#define MOD_DU OPC_3R(0x47)
+
+/* Bit-shift instructions */
+#define SLL_W OPC_3R(0x2e)
+#define SRL_W OPC_3R(0x2f)
+#define SRA_W OPC_3R(0x30)
+#define SLL_D OPC_3R(0x31)
+#define SRL_D OPC_3R(0x32)
+#define SRA_D OPC_3R(0x33)
+#define ROTR_W OPC_3R(0x36)
+#define ROTR_D OPC_3R(0x37)
+#define SLLI_W OPC_3R(0x81)
+#define SLLI_D ((sljit_ins)(0x41) << 16)
+#define SRLI_W OPC_3R(0x89)
+#define SRLI_D ((sljit_ins)(0x45) << 16)
+#define SRAI_W OPC_3R(0x91)
+#define SRAI_D ((sljit_ins)(0x49) << 16)
+#define ROTRI_W OPC_3R(0x99)
+#define ROTRI_D ((sljit_ins)(0x4d) << 16)
+
+/* Bit-manipulation instructions */
+#define CLO_W OPC_2R(0x4)
+#define CLZ_W OPC_2R(0x5)
+#define CTO_W OPC_2R(0x6)
+#define CTZ_W OPC_2R(0x7)
+#define CLO_D OPC_2R(0x8)
+#define CLZ_D OPC_2R(0x9)
+#define CTO_D OPC_2R(0xa)
+#define CTZ_D OPC_2R(0xb)
+#define REVB_2H OPC_2R(0xc)
+#define REVB_4H OPC_2R(0xd)
+#define REVB_2W OPC_2R(0xe)
+#define REVB_D OPC_2R(0xf)
+#define REVH_2W OPC_2R(0x10)
+#define REVH_D OPC_2R(0x11)
+#define BITREV_4B OPC_2R(0x12)
+#define BITREV_8B OPC_2R(0x13)
+#define BITREV_W OPC_2R(0x14)
+#define BITREV_D OPC_2R(0x15)
+#define EXT_W_H OPC_2R(0x16)
+#define EXT_W_B OPC_2R(0x17)
+#define BSTRINS_W (0x1 << 22 | 1 << 21)
+#define BSTRPICK_W (0x1 << 22 | 1 << 21 | 1 << 15)
+#define BSTRINS_D (0x2 << 22)
+#define BSTRPICK_D (0x3 << 22)
+
+/* Branch instructions */
+#define BEQZ OPC_1RI21(0x10)
+#define BNEZ OPC_1RI21(0x11)
+#define JIRL OPC_2RI16(0x13)
+#define B OPC_I26(0x14)
+#define BL OPC_I26(0x15)
+#define BEQ OPC_2RI16(0x16)
+#define BNE OPC_2RI16(0x17)
+#define BLT OPC_2RI16(0x18)
+#define BGE OPC_2RI16(0x19)
+#define BLTU OPC_2RI16(0x1a)
+#define BGEU OPC_2RI16(0x1b)
+
+/* Memory access instructions */
+#define LD_B OPC_2RI12(0xa0)
+#define LD_H OPC_2RI12(0xa1)
+#define LD_W OPC_2RI12(0xa2)
+#define LD_D OPC_2RI12(0xa3)
+
+#define ST_B OPC_2RI12(0xa4)
+#define ST_H OPC_2RI12(0xa5)
+#define ST_W OPC_2RI12(0xa6)
+#define ST_D OPC_2RI12(0xa7)
+
+#define LD_BU OPC_2RI12(0xa8)
+#define LD_HU OPC_2RI12(0xa9)
+#define LD_WU OPC_2RI12(0xaa)
+
+#define LDX_B OPC_3R(0x7000)
+#define LDX_H OPC_3R(0x7008)
+#define LDX_W OPC_3R(0x7010)
+#define LDX_D OPC_3R(0x7018)
+
+#define STX_B OPC_3R(0x7020)
+#define STX_H OPC_3R(0x7028)
+#define STX_W OPC_3R(0x7030)
+#define STX_D OPC_3R(0x7038)
+
+#define LDX_BU OPC_3R(0x7040)
+#define LDX_HU OPC_3R(0x7048)
+#define LDX_WU OPC_3R(0x7050)
+
+#define PRELD OPC_2RI12(0xab)
+
+/* Atomic memory access instructions */
+#define LL_W OPC_2RI14(0x20)
+#define SC_W OPC_2RI14(0x21)
+#define LL_D OPC_2RI14(0x22)
+#define SC_D OPC_2RI14(0x23)
+
+/* LoongArch V1.10 Instructions */
+#define AMCAS_B OPC_3R(0x70B0)
+#define AMCAS_H OPC_3R(0x70B1)
+#define AMCAS_W OPC_3R(0x70B2)
+#define AMCAS_D OPC_3R(0x70B3)
+
+/* Other instructions */
+#define BREAK OPC_3R(0x54)
+#define DBGCALL OPC_3R(0x55)
+#define SYSCALL OPC_3R(0x56)
+
+/* Basic Floating-Point Instructions */
+/* Floating-Point Arithmetic Operation Instructions */
+#define FADD_S OPC_3R(0x201)
+#define FADD_D OPC_3R(0x202)
+#define FSUB_S OPC_3R(0x205)
+#define FSUB_D OPC_3R(0x206)
+#define FMUL_S OPC_3R(0x209)
+#define FMUL_D OPC_3R(0x20a)
+#define FDIV_S OPC_3R(0x20d)
+#define FDIV_D OPC_3R(0x20e)
+#define FCMP_COND_S OPC_4R(0xc1)
+#define FCMP_COND_D OPC_4R(0xc2)
+#define FCOPYSIGN_S OPC_3R(0x225)
+#define FCOPYSIGN_D OPC_3R(0x226)
+#define FSEL OPC_4R(0xd0)
+#define FABS_S OPC_2R(0x4501)
+#define FABS_D OPC_2R(0x4502)
+#define FNEG_S OPC_2R(0x4505)
+#define FNEG_D OPC_2R(0x4506)
+#define FMOV_S OPC_2R(0x4525)
+#define FMOV_D OPC_2R(0x4526)
+
+/* Floating-Point Conversion Instructions */
+#define FCVT_S_D OPC_2R(0x4646)
+#define FCVT_D_S OPC_2R(0x4649)
+#define FTINTRZ_W_S OPC_2R(0x46a1)
+#define FTINTRZ_W_D OPC_2R(0x46a2)
+#define FTINTRZ_L_S OPC_2R(0x46a9)
+#define FTINTRZ_L_D OPC_2R(0x46aa)
+#define FFINT_S_W OPC_2R(0x4744)
+#define FFINT_S_L OPC_2R(0x4746)
+#define FFINT_D_W OPC_2R(0x4748)
+#define FFINT_D_L OPC_2R(0x474a)
+
+/* Floating-Point Move Instructions */
+#define FMOV_S OPC_2R(0x4525)
+#define FMOV_D OPC_2R(0x4526)
+#define MOVGR2FR_W OPC_2R(0x4529)
+#define MOVGR2FR_D OPC_2R(0x452a)
+#define MOVGR2FRH_W OPC_2R(0x452b)
+#define MOVFR2GR_S OPC_2R(0x452d)
+#define MOVFR2GR_D OPC_2R(0x452e)
+#define MOVFRH2GR_S OPC_2R(0x452f)
+#define MOVGR2FCSR OPC_2R(0x4530)
+#define MOVFCSR2GR OPC_2R(0x4532)
+#define MOVFR2CF OPC_2R(0x4534)
+#define MOVCF2FR OPC_2R(0x4535)
+#define MOVGR2CF OPC_2R(0x4536)
+#define MOVCF2GR OPC_2R(0x4537)
+
+/* Floating-Point Branch Instructions */
+#define BCEQZ OPC_I26(0x12)
+#define BCNEZ OPC_I26(0x12)
+
+/* Floating-Point Common Memory Access Instructions */
+#define FLD_S OPC_2RI12(0xac)
+#define FLD_D OPC_2RI12(0xae)
+#define FST_S OPC_2RI12(0xad)
+#define FST_D OPC_2RI12(0xaf)
+
+#define FLDX_S OPC_3R(0x7060)
+#define FLDX_D OPC_3R(0x7068)
+#define FSTX_S OPC_3R(0x7070)
+#define FSTX_D OPC_3R(0x7078)
+
+/* 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)
+#define BRANCH16_MIN (-(0x8000 << 2))
+#define BRANCH21_MAX (0xfffff << 2)
+#define BRANCH21_MIN (-(0x100000 << 2))
+#define JUMP_MAX (0x1ffffff << 2)
+#define JUMP_MIN (-(0x2000000 << 2))
+#define JIRL_MAX (0x7fff << 2)
+#define JIRL_MIN (-(0x8000 << 2))
+
+#define S32_MAX (0x7fffffffl)
+#define S32_MIN (-0x80000000l)
+#define S52_MAX (0x7ffffffffffffl)
+
+#define INST(inst, type) ((sljit_ins)((type & SLJIT_32) ? inst##_W : inst##_D))
+
+/* LoongArch CPUCFG register for feature detection */
+#define LOONGARCH_CFG2 0x02
+#define LOONGARCH_CFG2_LAMCAS (1 << 28)
+
+static sljit_u32 cfg2_feature_list = 0;
+
+/* 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)
+{
+ sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+ FAIL_IF(!ptr);
+ *ptr = ins;
+ compiler->size++;
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset)
+{
+ sljit_sw diff;
+ sljit_uw target_addr;
+ sljit_ins *inst;
+
+ inst = (sljit_ins *)jump->addr;
+
+ if (jump->flags & SLJIT_REWRITABLE_JUMP)
+ goto exit;
+
+ if (jump->flags & JUMP_ADDR)
+ target_addr = jump->u.target;
+ else {
+ SLJIT_ASSERT(jump->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) {
+ diff += SSIZE_OF(ins);
+
+ if (diff >= BRANCH16_MIN && diff <= BRANCH16_MAX) {
+ inst--;
+ inst[0] = (inst[0] & 0xfc0003ff) ^ 0x4000000;
+ jump->flags |= PATCH_B;
+ jump->addr = (sljit_uw)inst;
+ return inst;
+ }
+
+ diff -= SSIZE_OF(ins);
+ }
+
+ if (diff >= JUMP_MIN && diff <= JUMP_MAX) {
+ if (jump->flags & IS_COND) {
+ inst[-1] |= (sljit_ins)IMM_I16(2);
+ }
+
+ jump->flags |= PATCH_J;
+ return inst;
+ }
+
+ if (diff >= S32_MIN && diff <= S32_MAX) {
+ if (jump->flags & IS_COND)
+ inst[-1] |= (sljit_ins)IMM_I16(3);
+
+ jump->flags |= PATCH_REL32;
+ inst[1] = inst[0];
+ return inst + 1;
+ }
+
+ if (target_addr <= (sljit_uw)S32_MAX) {
+ if (jump->flags & IS_COND)
+ inst[-1] |= (sljit_ins)IMM_I16(3);
+
+ jump->flags |= PATCH_ABS32;
+ inst[1] = inst[0];
+ return inst + 1;
+ }
+
+ if (target_addr <= S52_MAX) {
+ if (jump->flags & IS_COND)
+ inst[-1] |= (sljit_ins)IMM_I16(4);
+
+ jump->flags |= PATCH_ABS52;
+ inst[2] = inst[0];
+ return inst + 2;
+ }
+
+exit:
+ if (jump->flags & IS_COND)
+ inst[-1] |= (sljit_ins)IMM_I16(5);
+ inst[3] = inst[0];
+ return inst + 3;
+}
+
+static SLJIT_INLINE sljit_sw 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);
+
+ 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 (addr <= S52_MAX) {
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)2 << JUMP_SIZE_SHIFT));
+ jump->flags |= PATCH_ABS52;
+ return 2;
+ }
+
+ SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));
+ return 3;
+}
+
+static SLJIT_INLINE void load_addr_to_reg(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_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : TMP_REG1;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ 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);
+ ins[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5);
+ } else if (flags & PATCH_ABS52) {
+ 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 {
+ 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 (!(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] = 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_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 word_count;
+ SLJIT_NEXT_DEFINE_TYPES;
+ sljit_sw executable_offset;
+ sljit_uw addr;
+
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+ struct sljit_const *const_;
+
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_generate_code(compiler));
+
+ 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;
+ label = compiler->labels;
+ jump = compiler->jumps;
+ const_ = compiler->consts;
+ 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_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);
+
+ /* These structures are ordered by their address. */
+ 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 (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;
+ 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_);
+ }
+
+ SLJIT_GET_NEXT_MIN();
+ }
+ code_ptr++;
+ word_count++;
+ } while (buf_ptr < buf_end);
+
+ buf = buf->next;
+ } while (buf);
+
+ if (label && label->size == word_count) {
+ 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(code_ptr - code <= (sljit_sw)compiler->size);
+
+ jump = compiler->jumps;
+ while (jump) {
+ do {
+ if (!(jump->flags & (PATCH_B | PATCH_J)) || (jump->flags & JUMP_MOV_ADDR)) {
+ load_addr_to_reg(jump, executable_offset);
+ break;
+ }
+
+ 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);
+
+ if (jump->flags & PATCH_B) {
+ SLJIT_ASSERT((sljit_sw)addr >= BRANCH16_MIN && (sljit_sw)addr <= BRANCH16_MAX);
+ buf_ptr[0] |= (sljit_ins)IMM_I16(addr >> 2);
+ break;
+ }
+
+ SLJIT_ASSERT((sljit_sw)addr >= JUMP_MIN && (sljit_sw)addr <= JUMP_MAX);
+ if (jump->flags & IS_CALL)
+ buf_ptr[0] = BL | (sljit_ins)IMM_I26(addr >> 2);
+ else
+ buf_ptr[0] = B | (sljit_ins)IMM_I26(addr >> 2);
+ } while (0);
+ jump = jump->next;
+ }
+
+ compiler->error = SLJIT_ERR_COMPILED;
+ compiler->executable_offset = executable_offset;
+ compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
+
+ code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+ code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+ SLJIT_CACHE_FLUSH(code, code_ptr);
+ SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+ return code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+ switch (feature_type)
+ {
+ case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
+#else
+ /* Available by default. */
+ return 1;
+#endif
+
+ case SLJIT_HAS_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_CFG2_LAMCAS & get_cpu_features(GET_CFG2));
+
+ case SLJIT_HAS_CLZ:
+ case SLJIT_HAS_CTZ:
+ case SLJIT_HAS_REV:
+ case SLJIT_HAS_ROT:
+ case SLJIT_HAS_PREFETCH:
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
+{
+ SLJIT_UNUSED_ARG(type);
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/* Entry, exit */
+/* --------------------------------------------------------------------- */
+
+/* Creates an index in data_transfer_insts array. */
+#define LOAD_DATA 0x01
+#define WORD_DATA 0x00
+#define BYTE_DATA 0x02
+#define HALF_DATA 0x04
+#define INT_DATA 0x06
+#define SIGNED_DATA 0x08
+/* Separates integer and floating point registers */
+#define GPR_REG 0x0f
+#define DOUBLE_DATA 0x10
+#define SINGLE_DATA 0x12
+
+#define MEM_MASK 0x1f
+
+#define ARG_TEST 0x00020
+#define ALT_KEEP_CACHE 0x00040
+#define CUMULATIVE_OP 0x00080
+#define IMM_OP 0x00100
+#define MOVE_OP 0x00200
+#define SRC2_IMM 0x00400
+
+#define UNUSED_DEST 0x00800
+#define REG_DEST 0x01000
+#define REG1_SOURCE 0x02000
+#define REG2_SOURCE 0x04000
+#define SLOW_SRC1 0x08000
+#define SLOW_SRC2 0x10000
+#define SLOW_DEST 0x20000
+#define MEM_USE_TMP2 0x40000
+
+#define STACK_STORE ST_D
+#define STACK_LOAD LD_D
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm)
+{
+ if (imm <= I12_MAX && imm >= I12_MIN)
+ return push_inst(compiler, ADDI_D | RD(dst_r) | RJ(TMP_ZERO) | IMM_I12(imm));
+
+ if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
+ FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
+ return push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm));
+ } else if (imm <= 0x7ffffffffffffl && imm >= -0x8000000000000l) {
+ FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
+ FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
+ return push_inst(compiler, LU32I_D | RD(dst_r) | (sljit_ins)(((imm >> 32) & 0xfffff) << 5));
+ }
+ FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
+ FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
+ FAIL_IF(push_inst(compiler, LU32I_D | RD(dst_r) | (sljit_ins)(((imm >> 32) & 0xfffff) << 5)));
+ return push_inst(compiler, LU52I_D | RD(dst_r) | RJ(dst_r) | IMM_I12(imm >> 52));
+}
+
+#define STACK_MAX_DISTANCE (-I12_MIN)
+
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw);
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+ sljit_s32 i, tmp, offset;
+ sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+ set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1);
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
+
+ local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
+ compiler->local_size = local_size;
+
+ if (local_size <= STACK_MAX_DISTANCE) {
+ /* Frequent case. */
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(-local_size)));
+ offset = local_size - SSIZE_OF(sw);
+ local_size = 0;
+ } else {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(STACK_MAX_DISTANCE)));
+ local_size -= STACK_MAX_DISTANCE;
+
+ if (local_size > STACK_MAX_DISTANCE)
+ FAIL_IF(load_immediate(compiler, TMP_REG1, local_size));
+ offset = STACK_MAX_DISTANCE - SSIZE_OF(sw);
+ }
+
+ FAIL_IF(push_inst(compiler, STACK_STORE | RD(RETURN_ADDR_REG) | RJ(SLJIT_SP) | IMM_I12(offset)));
+
+ tmp = SLJIT_S0 - saveds;
+ for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) {
+ offset -= SSIZE_OF(sw);
+ FAIL_IF(push_inst(compiler, STACK_STORE | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+ offset -= SSIZE_OF(sw);
+ FAIL_IF(push_inst(compiler, STACK_STORE | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ tmp = SLJIT_FS0 - fsaveds;
+ for (i = SLJIT_FS0; i > tmp; i--) {
+ offset -= SSIZE_OF(f64);
+ FAIL_IF(push_inst(compiler, FST_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
+ offset -= SSIZE_OF(f64);
+ FAIL_IF(push_inst(compiler, FST_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ if (local_size > STACK_MAX_DISTANCE)
+ FAIL_IF(push_inst(compiler, SUB_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | RK(TMP_REG1)));
+ else if (local_size > 0)
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(-local_size)));
+
+ if (options & SLJIT_ENTER_REG_ARG)
+ return SLJIT_SUCCESS;
+
+ arg_types >>= SLJIT_ARG_SHIFT;
+ saved_arg_count = 0;
+ tmp = SLJIT_R0;
+
+ while (arg_types > 0) {
+ if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) {
+ if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_S0 - saved_arg_count) | RJ(tmp) | IMM_I12(0)));
+ saved_arg_count++;
+ }
+ tmp++;
+ }
+
+ arg_types >>= SLJIT_ARG_SHIFT;
+ }
+
+ return SLJIT_SUCCESS;
+}
+
+#undef STACK_MAX_DISTANCE
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+ sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+ sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+ set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1);
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
+
+ compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
+
+ return SLJIT_SUCCESS;
+}
+
+#define STACK_MAX_DISTANCE (-I12_MIN - 16)
+
+static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to)
+{
+ sljit_s32 i, tmp, offset;
+ sljit_s32 local_size = compiler->local_size;
+
+ if (local_size > STACK_MAX_DISTANCE) {
+ local_size -= STACK_MAX_DISTANCE;
+
+ if (local_size > STACK_MAX_DISTANCE) {
+ FAIL_IF(load_immediate(compiler, TMP_REG2, local_size));
+ FAIL_IF(push_inst(compiler, ADD_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | RK(TMP_REG2)));
+ } else
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(local_size)));
+
+ local_size = STACK_MAX_DISTANCE;
+ }
+
+ SLJIT_ASSERT(local_size > 0);
+
+ offset = local_size - SSIZE_OF(sw);
+ if (!is_return_to)
+ FAIL_IF(push_inst(compiler, STACK_LOAD | RD(RETURN_ADDR_REG) | RJ(SLJIT_SP) | IMM_I12(offset)));
+
+ tmp = SLJIT_S0 - compiler->saveds;
+ for (i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); i > tmp; i--) {
+ offset -= SSIZE_OF(sw);
+ FAIL_IF(push_inst(compiler, STACK_LOAD | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+ offset -= SSIZE_OF(sw);
+ FAIL_IF(push_inst(compiler, STACK_LOAD | RD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ tmp = SLJIT_FS0 - compiler->fsaveds;
+ for (i = SLJIT_FS0; i > tmp; i--) {
+ offset -= SSIZE_OF(f64);
+ FAIL_IF(push_inst(compiler, FLD_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
+ offset -= SSIZE_OF(f64);
+ FAIL_IF(push_inst(compiler, FLD_D | FRD(i) | RJ(SLJIT_SP) | IMM_I12(offset)));
+ }
+
+ return push_inst(compiler, ADDI_D | RD(SLJIT_SP) | RJ(SLJIT_SP) | IMM_I12(local_size));
+}
+
+#undef STACK_MAX_DISTANCE
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_return_void(compiler));
+
+ FAIL_IF(emit_stack_frame_release(compiler, 0));
+ return push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
+ sljit_s32 src, sljit_sw srcw)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_return_to(compiler, src, srcw));
+
+ if (src & SLJIT_MEM) {
+ ADJUST_LOCAL_OFFSET(src, srcw);
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+ src = TMP_REG1;
+ srcw = 0;
+ } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(src) | IMM_I12(0)));
+ src = TMP_REG1;
+ srcw = 0;
+ }
+
+ FAIL_IF(emit_stack_frame_release(compiler, 1));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw);
+}
+
+/* --------------------------------------------------------------------- */
+/* Operators */
+/* --------------------------------------------------------------------- */
+
+static const sljit_ins data_transfer_insts[16 + 4] = {
+/* u w s */ ST_D /* st.d */,
+/* u w l */ LD_D /* ld.d */,
+/* u b s */ ST_B /* st.b */,
+/* u b l */ LD_BU /* ld.bu */,
+/* u h s */ ST_H /* st.h */,
+/* u h l */ LD_HU /* ld.hu */,
+/* u i s */ ST_W /* st.w */,
+/* u i l */ LD_WU /* ld.wu */,
+
+/* s w s */ ST_D /* st.d */,
+/* s w l */ LD_D /* ld.d */,
+/* s b s */ ST_B /* st.b */,
+/* s b l */ LD_B /* ld.b */,
+/* s h s */ ST_H /* st.h */,
+/* s h l */ LD_H /* ld.h */,
+/* s i s */ ST_W /* st.w */,
+/* s i l */ LD_W /* ld.w */,
+
+/* d s */ FST_D /* fst.d */,
+/* d l */ FLD_D /* fld.d */,
+/* s s */ FST_S /* fst.s */,
+/* s l */ FLD_S /* fld.s */,
+};
+
+static const sljit_ins data_transfer_insts_x[16 + 4] = {
+/* u w s */ STX_D /* stx.d */,
+/* u w l */ LDX_D /* ldx.d */,
+/* u b s */ STX_B /* stx.b */,
+/* u b l */ LDX_BU /* ldx.bu */,
+/* u h s */ STX_H /* stx.h */,
+/* u h l */ LDX_HU /* ldx.hu */,
+/* u i s */ STX_W /* stx.w */,
+/* u i l */ LDX_WU /* ldx.wu */,
+
+/* s w s */ STX_D /* stx.d */,
+/* s w l */ LDX_D /* ldx.d */,
+/* s b s */ STX_B /* stx.b */,
+/* s b l */ LDX_B /* ldx.b */,
+/* s h s */ STX_H /* stx.h */,
+/* s h l */ LDX_H /* ldx.h */,
+/* s i s */ STX_W /* stx.w */,
+/* s i l */ LDX_W /* ldx.w */,
+
+/* d s */ FSTX_D /* fstx.d */,
+/* d l */ FLDX_D /* fldx.d */,
+/* s s */ FSTX_S /* fstx.s */,
+/* s l */ FLDX_S /* fldx.s */,
+};
+
+static sljit_s32 push_mem_inst(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+ sljit_ins ins;
+ sljit_s32 base = arg & REG_MASK;
+
+ SLJIT_ASSERT(arg & SLJIT_MEM);
+
+ if (arg & OFFS_REG_MASK) {
+ sljit_s32 offs = OFFS_REG(arg);
+
+ SLJIT_ASSERT(!argw);
+ ins = data_transfer_insts_x[flags & MEM_MASK] |
+ ((flags & MEM_MASK) <= GPR_REG ? RD(reg) : FRD(reg)) |
+ RJ(base) | RK(offs);
+ } else {
+ SLJIT_ASSERT(argw <= 0xfff && argw >= I12_MIN);
+
+ ins = data_transfer_insts[flags & MEM_MASK] |
+ ((flags & MEM_MASK) <= GPR_REG ? RD(reg) : FRD(reg)) |
+ RJ(base) | IMM_I12(argw);
+ }
+ return push_inst(compiler, ins);
+}
+
+/* Can perform an operation using at most 1 instruction. */
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+ SLJIT_ASSERT(arg & SLJIT_MEM);
+
+ /* argw == 0 (ldx/stx rd, rj, rk) can be used.
+ * argw in [-2048, 2047] (ld/st rd, rj, imm) can be used. */
+ if (!argw || (!(arg & OFFS_REG_MASK) && (argw <= I12_MAX && argw >= I12_MIN))) {
+ /* Works for both absolute and relative addresses. */
+ if (SLJIT_UNLIKELY(flags & ARG_TEST))
+ return 1;
+
+ FAIL_IF(push_mem_inst(compiler, flags, reg, arg, argw));
+ return -1;
+ }
+ return 0;
+}
+
+#define TO_ARGW_HI(argw) (((argw) & ~0xfff) + (((argw) & 0x800) ? 0x1000 : 0))
+
+/* See getput_arg below.
+ Note: can_cache is called only for binary operators. */
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+ SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
+
+ if (arg & OFFS_REG_MASK)
+ return 0;
+
+ if (arg == next_arg) {
+ if (((next_argw - argw) <= I12_MAX && (next_argw - argw) >= I12_MIN)
+ || TO_ARGW_HI(argw) == TO_ARGW_HI(next_argw))
+ return 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Emit the necessary instructions. See can_cache above. */
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+ sljit_s32 base = arg & REG_MASK;
+ sljit_s32 tmp_r = (flags & MEM_USE_TMP2) ? TMP_REG2 : TMP_REG1;
+ sljit_sw offset;
+
+ SLJIT_ASSERT(arg & SLJIT_MEM);
+ if (!(next_arg & SLJIT_MEM)) {
+ next_arg = 0;
+ next_argw = 0;
+ }
+
+ if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+ argw &= 0x3;
+
+ if (SLJIT_UNLIKELY(argw))
+ FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG3) | RJ(OFFS_REG(arg)) | IMM_I12(argw)));
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, TMP_REG3), 0);
+ }
+
+ if (compiler->cache_arg == arg && argw - compiler->cache_argw <= I12_MAX && argw - compiler->cache_argw >= I12_MIN)
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(TMP_REG3), argw - compiler->cache_argw);
+
+ if (compiler->cache_arg == SLJIT_MEM && (argw - compiler->cache_argw <= I12_MAX) && (argw - compiler->cache_argw >= I12_MIN)) {
+ offset = argw - compiler->cache_argw;
+ } else {
+ sljit_sw argw_hi=TO_ARGW_HI(argw);
+ compiler->cache_arg = SLJIT_MEM;
+
+ if (next_arg && next_argw - argw <= I12_MAX && next_argw - argw >= I12_MIN && argw_hi != TO_ARGW_HI(next_argw)) {
+ FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
+ compiler->cache_argw = argw;
+ offset = 0;
+ } else {
+ FAIL_IF(load_immediate(compiler, TMP_REG3, argw_hi));
+ compiler->cache_argw = argw_hi;
+ offset = argw & 0xfff;
+ argw = argw_hi;
+ }
+ }
+
+ if (!base)
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(TMP_REG3), offset);
+
+ if (arg == next_arg && next_argw - argw <= I12_MAX && next_argw - argw >= I12_MIN) {
+ compiler->cache_arg = arg;
+ FAIL_IF(push_inst(compiler, ADD_D | RD(TMP_REG3) | RJ(TMP_REG3) | RK(base)));
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(TMP_REG3), offset);
+ }
+
+ if (!offset)
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, TMP_REG3), 0);
+
+ FAIL_IF(push_inst(compiler, ADD_D | RD(tmp_r) | RJ(TMP_REG3) | RK(base)));
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(tmp_r), offset);
+}
+
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+ sljit_s32 base = arg & REG_MASK;
+ sljit_s32 tmp_r = TMP_REG1;
+
+ if (getput_arg_fast(compiler, flags, reg, arg, argw))
+ return compiler->error;
+
+ if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA))
+ tmp_r = reg;
+
+ if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+ argw &= 0x3;
+
+ if (SLJIT_UNLIKELY(argw))
+ FAIL_IF(push_inst(compiler, SLLI_D | RD(tmp_r) | RJ(OFFS_REG(arg)) | IMM_I12(argw)));
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, tmp_r), 0);
+ } else {
+ FAIL_IF(load_immediate(compiler, tmp_r, argw));
+
+ if (base != 0)
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM2(base, tmp_r), 0);
+ return push_mem_inst(compiler, flags, reg, SLJIT_MEM1(tmp_r), 0);
+ }
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
+{
+ if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
+ return compiler->error;
+ return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
+}
+
+#define IMM_EXTEND(v) (IMM_I12((op & SLJIT_32) ? (v) : (32 + (v))))
+
+/* andi/ori/xori are zero-extended */
+#define EMIT_LOGICAL(op_imm, op_reg) \
+ if (flags & SRC2_IMM) { \
+ if (op & SLJIT_SET_Z) {\
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(EQUAL_FLAG) | RJ(TMP_ZERO) | IMM_I12(src2))); \
+ FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG))); \
+ } \
+ if (!(flags & UNUSED_DEST)) { \
+ if (dst == src1) { \
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(TMP_ZERO) | IMM_I12(src2))); \
+ FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(TMP_REG1))); \
+ } else { \
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(dst) | RJ(TMP_ZERO) | IMM_I12(src2))); \
+ FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(dst))); \
+ } \
+ } \
+ } else { \
+ if (op & SLJIT_SET_Z) \
+ FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); \
+ if (!(flags & UNUSED_DEST)) \
+ FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(src2))); \
+ } \
+ while (0)
+
+#define EMIT_SHIFT(imm, reg) \
+ op_imm = (imm); \
+ op_reg = (reg)
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+ sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
+{
+ sljit_s32 is_overflow, is_carry, carry_src_r, is_handled, 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_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_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_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_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_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_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_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_ZERO && !(flags & SRC2_IMM));
+ return push_inst(compiler, INST(CLZ, op) | RD(dst) | RJ(src2));
+
+ case SLJIT_CTZ:
+ 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_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_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_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_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_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));
+
+ case SLJIT_ADD:
+ /* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */
+ is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+ carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+ if (flags & SRC2_IMM) {
+ if (is_overflow) {
+ if (src2 >= 0)
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
+ else {
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(TMP_ZERO) | IMM_I12(-1)));
+ FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG)));
+ }
+ } else if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+ /* Only the zero flag is needed. */
+ if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(src2)));
+ } else {
+ if (is_overflow)
+ FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+ else if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(ADD, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+ if (is_overflow || carry_src_r != 0) {
+ if (src1 != dst)
+ carry_src_r = (sljit_s32)src1;
+ else if (src2 != dst)
+ carry_src_r = (sljit_s32)src2;
+ else {
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(0)));
+ carry_src_r = OTHER_FLAG;
+ }
+ }
+
+ /* Only the zero flag is needed. */
+ if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+ FAIL_IF(push_inst(compiler, INST(ADD, op) | RD(dst) | RJ(src1) | RK(src2)));
+ }
+
+ /* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */
+ if (is_overflow || carry_src_r != 0) {
+ if (flags & SRC2_IMM)
+ FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(dst) | IMM_I12(src2)));
+ else
+ FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(dst) | RK(carry_src_r)));
+ }
+
+ if (!is_overflow)
+ return SLJIT_SUCCESS;
+
+ FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RJ(dst) | RK(EQUAL_FLAG)));
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(ADD, op) | RD(EQUAL_FLAG) | RJ(dst) | IMM_I12(0)));
+ FAIL_IF(push_inst(compiler, INST(SRLI, op) | RD(TMP_REG1) | RJ(TMP_REG1) | IMM_EXTEND(31)));
+ return push_inst(compiler, XOR | RD(OTHER_FLAG) | RJ(TMP_REG1) | RK(OTHER_FLAG));
+
+ case SLJIT_ADDC:
+ carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+ if (flags & SRC2_IMM) {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(dst) | RJ(src1) | IMM_I12(src2)));
+ } else {
+ if (carry_src_r != 0) {
+ if (src1 != dst)
+ carry_src_r = (sljit_s32)src1;
+ else if (src2 != dst)
+ carry_src_r = (sljit_s32)src2;
+ else {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
+ carry_src_r = EQUAL_FLAG;
+ }
+ }
+
+ FAIL_IF(push_inst(compiler, ADD_D | RD(dst) | RJ(src1) | RK(src2)));
+ }
+
+ /* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */
+ if (carry_src_r != 0) {
+ if (flags & SRC2_IMM)
+ FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(dst) | IMM_I12(src2)));
+ else
+ FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RJ(dst) | RK(carry_src_r)));
+ }
+
+ FAIL_IF(push_inst(compiler, ADD_D | RD(dst) | RJ(dst) | RK(OTHER_FLAG)));
+
+ if (carry_src_r == 0)
+ return SLJIT_SUCCESS;
+
+ /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
+ FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(dst) | RK(OTHER_FLAG)));
+ /* Set carry flag. */
+ return push_inst(compiler, OR | RD(OTHER_FLAG) | RJ(OTHER_FLAG) | RK(EQUAL_FLAG));
+
+ case SLJIT_SUB:
+ if ((flags & SRC2_IMM) && src2 == I12_MIN) {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(src2)));
+ src2 = TMP_REG2;
+ flags &= ~SRC2_IMM;
+ }
+
+ is_handled = 0;
+
+ if (flags & SRC2_IMM) {
+ if (GET_FLAG_TYPE(op) == SLJIT_LESS) {
+ FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2)));
+ is_handled = 1;
+ } else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) {
+ FAIL_IF(push_inst(compiler, SLTI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2)));
+ is_handled = 1;
+ }
+ }
+
+ if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+ is_handled = 1;
+
+ if (flags & SRC2_IMM) {
+ 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;
+ }
+
+ switch (GET_FLAG_TYPE(op)) {
+ case SLJIT_LESS:
+ FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+ break;
+ case SLJIT_GREATER:
+ FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(src2) | RK(src1)));
+ break;
+ case SLJIT_SIG_LESS:
+ FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+ break;
+ case SLJIT_SIG_GREATER:
+ FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RJ(src2) | RK(src1)));
+ break;
+ }
+ }
+
+ if (is_handled) {
+ if (flags & SRC2_IMM) {
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-src2)));
+ if (!(flags & UNUSED_DEST))
+ return push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2));
+ } else {
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+ if (!(flags & UNUSED_DEST))
+ return push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(src1) | RK(src2));
+ }
+ return SLJIT_SUCCESS;
+ }
+
+ is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+ is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+ if (flags & SRC2_IMM) {
+ if (is_overflow) {
+ if (src2 >= 0)
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
+ else {
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-1)));
+ FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG)));
+ }
+ } else if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-src2)));
+
+ if (is_overflow || is_carry)
+ FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+ /* Only the zero flag is needed. */
+ if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2)));
+ } else {
+ if (is_overflow)
+ FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+ else if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+ if (is_overflow || is_carry)
+ FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+
+ /* Only the zero flag is needed. */
+ if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+ FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(src1) | RK(src2)));
+ }
+
+ if (!is_overflow)
+ return SLJIT_SUCCESS;
+
+ FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RJ(dst) | RK(EQUAL_FLAG)));
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(dst) | IMM_I12(0)));
+ FAIL_IF(push_inst(compiler, INST(SRLI, op) | RD(TMP_REG1) | RJ(TMP_REG1) | IMM_EXTEND(31)));
+ return push_inst(compiler, XOR | RD(OTHER_FLAG) | RJ(TMP_REG1) | RK(OTHER_FLAG));
+
+ case SLJIT_SUBC:
+ if ((flags & SRC2_IMM) && src2 == I12_MIN) {
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(src2)));
+ src2 = TMP_REG2;
+ flags &= ~SRC2_IMM;
+ }
+
+ is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
+
+ if (flags & SRC2_IMM) {
+ if (is_carry)
+ FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2)));
+ } else {
+ if (is_carry)
+ FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+ FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(src1) | RK(src2)));
+ }
+
+ if (is_carry)
+ FAIL_IF(push_inst(compiler, SLTU | RD(TMP_REG1) | RJ(dst) | RK(OTHER_FLAG)));
+
+ FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(dst) | RJ(dst) | RK(OTHER_FLAG)));
+
+ if (!is_carry)
+ return SLJIT_SUCCESS;
+
+ return push_inst(compiler, OR | RD(OTHER_FLAG) | RJ(EQUAL_FLAG) | RK(TMP_REG1));
+
+ case SLJIT_MUL:
+ SLJIT_ASSERT(!(flags & SRC2_IMM));
+
+ if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW)
+ return push_inst(compiler, INST(MUL, op) | RD(dst) | RJ(src1) | RK(src2));
+
+ if (op & SLJIT_32) {
+ FAIL_IF(push_inst(compiler, MUL_D | RD(OTHER_FLAG) | RJ(src1) | RK(src2)));
+ FAIL_IF(push_inst(compiler, MUL_W | RD(dst) | RJ(src1) | RK(src2)));
+ return push_inst(compiler, SUB_D | RD(OTHER_FLAG) | RJ(dst) | RK(OTHER_FLAG));
+ }
+
+ FAIL_IF(push_inst(compiler, MULH_D | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+ FAIL_IF(push_inst(compiler, MUL_D | RD(dst) | RJ(src1) | RK(src2)));
+ FAIL_IF(push_inst(compiler, SRAI_D | RD(OTHER_FLAG) | RJ(dst) | IMM_I12((63))));
+ return push_inst(compiler, SUB_D | RD(OTHER_FLAG) | RJ(EQUAL_FLAG) | RK(OTHER_FLAG));
+
+ case SLJIT_AND:
+ EMIT_LOGICAL(ANDI, AND);
+ return SLJIT_SUCCESS;
+
+ case SLJIT_OR:
+ EMIT_LOGICAL(ORI, OR);
+ return SLJIT_SUCCESS;
+
+ case SLJIT_XOR:
+ EMIT_LOGICAL(XORI, XOR);
+ return SLJIT_SUCCESS;
+
+ case SLJIT_SHL:
+ case SLJIT_MSHL:
+ if (op & SLJIT_32) {
+ EMIT_SHIFT(SLLI_W, SLL_W);
+ } else {
+ EMIT_SHIFT(SLLI_D, SLL_D);
+ }
+ break;
+
+ case SLJIT_LSHR:
+ case SLJIT_MLSHR:
+ if (op & SLJIT_32) {
+ EMIT_SHIFT(SRLI_W, SRL_W);
+ } else {
+ EMIT_SHIFT(SRLI_D, SRL_D);
+ }
+ break;
+
+ case SLJIT_ASHR:
+ case SLJIT_MASHR:
+ if (op & SLJIT_32) {
+ EMIT_SHIFT(SRAI_W, SRA_W);
+ } else {
+ EMIT_SHIFT(SRAI_D, SRA_D);
+ }
+ break;
+
+ case SLJIT_ROTL:
+ case SLJIT_ROTR:
+ if (flags & SRC2_IMM) {
+ SLJIT_ASSERT(src2 != 0);
+
+ if (GET_OPCODE(op) == SLJIT_ROTL)
+ src2 = word_size - src2;
+ return push_inst(compiler, INST(ROTRI, op) | RD(dst) | RJ(src1) | IMM_I12(src2));
+ }
+
+ if (src2 == TMP_ZERO) {
+ if (dst != src1)
+ return push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(0));
+ return SLJIT_SUCCESS;
+ }
+
+ if (GET_OPCODE(op) == SLJIT_ROTL) {
+ FAIL_IF(push_inst(compiler, INST(SUB, op)| RD(OTHER_FLAG) | RJ(TMP_ZERO) | RK(src2)));
+ src2 = OTHER_FLAG;
+ }
+ return push_inst(compiler, INST(ROTR, op) | RD(dst) | RJ(src1) | RK(src2));
+
+ default:
+ SLJIT_UNREACHABLE();
+ return SLJIT_SUCCESS;
+ }
+
+ if (flags & SRC2_IMM) {
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, op_imm | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2)));
+
+ if (flags & UNUSED_DEST)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, op_imm | RD(dst) | RJ(src1) | IMM_I12(src2));
+ }
+
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(src2)));
+
+ if (flags & UNUSED_DEST)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(src2));
+}
+
+#undef IMM_EXTEND
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ /* arg1 goes to TMP_REG1 or src reg
+ arg2 goes to TMP_REG2, imm or src reg
+ TMP_REG3 can be used for caching
+ result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
+ sljit_s32 dst_r = TMP_REG2;
+ sljit_s32 src1_r;
+ sljit_sw src2_r = 0;
+ sljit_s32 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;
+ compiler->cache_argw = 0;
+ }
+
+ if (dst == 0) {
+ SLJIT_ASSERT(HAS_FLAGS(op));
+ flags |= UNUSED_DEST;
+ dst = TMP_REG2;
+ } else if (FAST_IS_REG(dst)) {
+ dst_r = dst;
+ flags |= REG_DEST;
+ if (flags & MOVE_OP)
+ 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) {
+ flags |= SRC2_IMM;
+ src2_r = src1w;
+
+ /* And swap arguments. */
+ src1 = src2;
+ src1w = src2w;
+ src2 = SLJIT_IMM;
+ /* src2w = src2_r unneeded. */
+ }
+ }
+
+ /* Source 1. */
+ if (FAST_IS_REG(src1)) {
+ src1_r = src1;
+ flags |= REG1_SOURCE;
+ } else if (src1 == SLJIT_IMM) {
+ if (src1w) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+ src1_r = TMP_REG1;
+ }
+ else
+ src1_r = TMP_ZERO;
+ } else {
+ if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w))
+ FAIL_IF(compiler->error);
+ else
+ flags |= SLOW_SRC1;
+ src1_r = TMP_REG1;
+ }
+
+ /* Source 2. */
+ if (FAST_IS_REG(src2)) {
+ src2_r = src2;
+ flags |= REG2_SOURCE;
+ if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP)
+ dst_r = (sljit_s32)src2_r;
+ } else if (src2 == SLJIT_IMM) {
+ if (!(flags & SRC2_IMM)) {
+ if (src2w) {
+ FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w));
+ src2_r = src2_tmp_reg;
+ } else {
+ src2_r = TMP_ZERO;
+ if (flags & MOVE_OP) {
+ if (dst & SLJIT_MEM)
+ dst_r = 0;
+ else
+ op = SLJIT_MOV;
+ }
+ }
+ }
+ } else {
+ if (getput_arg_fast(compiler, flags | LOAD_DATA, src2_tmp_reg, src2, src2w))
+ FAIL_IF(compiler->error);
+ else
+ flags |= SLOW_SRC2;
+
+ src2_r = src2_tmp_reg;
+ }
+
+ if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+ SLJIT_ASSERT(src2_r == TMP_REG2);
+ 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 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 | ((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));
+
+ if (dst & SLJIT_MEM) {
+ if (!(flags & SLOW_DEST)) {
+ getput_arg_fast(compiler, flags, dst_r, dst, dstw);
+ return compiler->error;
+ }
+ return getput_arg(compiler, flags, dst_r, dst, dstw, 0, 0);
+ }
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op0(compiler, op));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_BREAKPOINT:
+ return push_inst(compiler, BREAK);
+ case SLJIT_NOP:
+ return push_inst(compiler, ANDI | RD(TMP_ZERO) | RJ(TMP_ZERO) | IMM_I12(0));
+ case SLJIT_LMUL_UW:
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(SLJIT_R1) | IMM_I12(0)));
+ FAIL_IF(push_inst(compiler, MULH_DU | RD(SLJIT_R1) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+ return push_inst(compiler, MUL_D | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(TMP_REG1));
+ case SLJIT_LMUL_SW:
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(SLJIT_R1) | IMM_I12(0)));
+ FAIL_IF(push_inst(compiler, MULH_D | RD(SLJIT_R1) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+ return push_inst(compiler, MUL_D | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(TMP_REG1));
+ case SLJIT_DIVMOD_UW:
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(TMP_REG1) | RJ(SLJIT_R0) | IMM_I12(0)));
+ FAIL_IF(push_inst(compiler, ((op & SLJIT_32)? DIV_WU: DIV_DU) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+ return push_inst(compiler, ((op & SLJIT_32)? MOD_WU: MOD_DU) | RD(SLJIT_R1) | RJ(TMP_REG1) | RK(SLJIT_R1));
+ case SLJIT_DIVMOD_SW:
+ FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(TMP_REG1) | RJ(SLJIT_R0) | IMM_I12(0)));
+ FAIL_IF(push_inst(compiler, INST(DIV, op) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
+ return push_inst(compiler, INST(MOD, op) | RD(SLJIT_R1) | RJ(TMP_REG1) | RK(SLJIT_R1));
+ case SLJIT_DIV_UW:
+ return push_inst(compiler, ((op & SLJIT_32)? DIV_WU: DIV_DU) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1));
+ case SLJIT_DIV_SW:
+ return push_inst(compiler, INST(DIV, op) | RD(SLJIT_R0) | RJ(SLJIT_R0) | RK(SLJIT_R1));
+ case SLJIT_ENDBR:
+ case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+ return SLJIT_SUCCESS;
+ }
+
+ SLJIT_UNREACHABLE();
+ return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 flags = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (op & SLJIT_32)
+ flags = INT_DATA | SIGNED_DATA;
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV:
+ case SLJIT_MOV_P:
+ return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, srcw);
+
+ case SLJIT_MOV_U32:
+ 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_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_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_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_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_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_ZERO, 0, src, srcw);
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ 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_ZERO, 0, src, srcw);
+ }
+
+ SLJIT_UNREACHABLE();
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_s32 flags = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ if (op & SLJIT_32) {
+ flags |= INT_DATA | SIGNED_DATA;
+ if (src1 == SLJIT_IMM)
+ src1w = (sljit_s32)src1w;
+ if (src2 == SLJIT_IMM)
+ src2w = (sljit_s32)src2w;
+ }
+
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_ADD:
+ case SLJIT_ADDC:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
+ return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+ case SLJIT_SUB:
+ case SLJIT_SUBC:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
+ return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+ case SLJIT_MUL:
+ compiler->status_flags_state = 0;
+ return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
+
+ case SLJIT_AND:
+ case SLJIT_OR:
+ case SLJIT_XOR:
+ return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+ case SLJIT_SHL:
+ case SLJIT_MSHL:
+ case SLJIT_LSHR:
+ case SLJIT_MLSHR:
+ case SLJIT_ASHR:
+ case SLJIT_MASHR:
+ case SLJIT_ROTL:
+ case SLJIT_ROTR:
+ if (src2 == SLJIT_IMM) {
+ if (op & SLJIT_32)
+ src2w &= 0x1f;
+ else
+ src2w &= 0x3f;
+ }
+
+ return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+ }
+
+ SLJIT_UNREACHABLE();
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_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,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
+{
+ sljit_s32 is_left;
+ sljit_ins ins1, ins2, ins3;
+ sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+ sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64;
+
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
+
+ is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
+
+ if (src1_reg == src2_reg) {
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
+ }
+
+ ADJUST_LOCAL_OFFSET(src3, src3w);
+
+ if (src3 == SLJIT_IMM) {
+ src3w &= bit_length - 1;
+
+ if (src3w == 0)
+ return SLJIT_SUCCESS;
+
+ if (is_left) {
+ ins1 = INST(SLLI, op) | IMM_I12(src3w);
+ src3w = bit_length - src3w;
+ ins2 = INST(SRLI, op) | IMM_I12(src3w);
+ } else {
+ ins1 = INST(SRLI, op) | IMM_I12(src3w);
+ src3w = bit_length - src3w;
+ ins2 = INST(SLLI, op) | IMM_I12(src3w);
+ }
+
+ FAIL_IF(push_inst(compiler, ins1 | RD(dst_reg) | RJ(src1_reg)));
+ FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RJ(src2_reg)));
+ return push_inst(compiler, OR | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG1));
+ }
+
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src3, src3w));
+ src3 = TMP_REG2;
+ } else if (dst_reg == src3) {
+ push_inst(compiler, INST(ADDI, op) | RD(TMP_REG2) | RJ(src3) | IMM_I12(0));
+ src3 = TMP_REG2;
+ }
+
+ if (is_left) {
+ ins1 = INST(SLL, op);
+ ins2 = INST(SRLI, op);
+ ins3 = INST(SRL, op);
+ } else {
+ ins1 = INST(SRL, op);
+ ins2 = INST(SLLI, op);
+ ins3 = INST(SLL, op);
+ }
+
+ FAIL_IF(push_inst(compiler, ins1 | RD(dst_reg) | RJ(src1_reg) | RK(src3)));
+
+ if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
+ FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RJ(src2_reg) | IMM_I12(1)));
+ FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RJ(src3) | IMM_I12((sljit_ins)bit_length - 1)));
+ src2_reg = TMP_REG1;
+ } else
+ FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(TMP_REG2) | RJ(TMP_ZERO) | RK(src3)));
+
+ FAIL_IF(push_inst(compiler, ins3 | RD(TMP_REG1) | RJ(src2_reg) | RK(TMP_REG2)));
+ return push_inst(compiler, OR | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 base = src & REG_MASK;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ switch (op) {
+ case SLJIT_FAST_RETURN:
+ if (FAST_IS_REG(src))
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(RETURN_ADDR_REG) | RJ(src) | IMM_I12(0)));
+ else
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw));
+
+ return push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
+ case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+ return SLJIT_SUCCESS;
+ case SLJIT_PREFETCH_L1:
+ case SLJIT_PREFETCH_L2:
+ case SLJIT_PREFETCH_L3:
+ case SLJIT_PREFETCH_ONCE:
+ if (SLJIT_UNLIKELY(src & OFFS_REG_MASK)) {
+ srcw &= 0x3;
+ if (SLJIT_UNLIKELY(srcw))
+ FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG1) | RJ(OFFS_REG(src)) | IMM_I12(srcw)));
+ FAIL_IF(push_inst(compiler, ADD_D | RD(TMP_REG1) | RJ(base) | RK(TMP_REG1)));
+ } else {
+ if (base && srcw <= I12_MAX && srcw >= I12_MIN)
+ return push_inst(compiler,PRELD | RJ(base) | IMM_I12(srcw));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ if (base != 0)
+ FAIL_IF(push_inst(compiler, ADD_D | RD(TMP_REG1) | RJ(base) | RK(TMP_REG1)));
+ }
+ return push_inst(compiler, PRELD | RD(0) | RJ(TMP_REG1));
+ }
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, ADDI_D | RD(dst) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
+
+ SLJIT_ASSERT(RETURN_ADDR_REG == TMP_REG2);
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size - SSIZE_OF(sw)));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
+{
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type != SLJIT_FLOAT_REGISTER && type != SLJIT_SIMD_REG_128 && type != SLJIT_SIMD_REG_256)
+ return -1;
+
+ return freg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+ void *instruction, sljit_u32 size)
+{
+ SLJIT_UNUSED_ARG(size);
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+ return push_inst(compiler, *(sljit_ins*)instruction);
+}
+
+/* --------------------------------------------------------------------- */
+/* Floating point operators */
+/* --------------------------------------------------------------------- */
+#define SET_COND(cond) (sljit_ins)(cond << 15)
+
+#define COND_CUN SET_COND(0x8) /* UN */
+#define COND_CEQ SET_COND(0x4) /* EQ */
+#define COND_CUEQ SET_COND(0xc) /* UN EQ */
+#define COND_CLT SET_COND(0x2) /* LT */
+#define COND_CULT SET_COND(0xa) /* UN LT */
+#define COND_CLE SET_COND(0x6) /* LT EQ */
+#define COND_CULE SET_COND(0xe) /* UN LT EQ */
+#define COND_CNE SET_COND(0x10) /* GT LT */
+#define COND_CUNE SET_COND(0x18) /* UN GT LT */
+#define COND_COR SET_COND(0x14) /* GT LT EQ */
+
+#define FINST(inst, type) (sljit_ins)((type & SLJIT_32) ? inst##_S : inst##_D)
+#define FCD(cd) (sljit_ins)(cd & 0x7)
+#define FCJ(cj) (sljit_ins)((cj & 0x7) << 5)
+#define FCA(ca) (sljit_ins)((ca & 0x7) << 15)
+#define F_OTHER_FLAG 1
+
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 7))
+
+/* convert to inter exact toward zero */
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins inst;
+ sljit_u32 word_data = 0;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+
+ switch (GET_OPCODE(op))
+ {
+ case SLJIT_CONV_SW_FROM_F64:
+ word_data = 1;
+ inst = FINST(FTINTRZ_L, op);
+ break;
+ case SLJIT_CONV_S32_FROM_F64:
+ inst = FINST(FTINTRZ_W, op);
+ break;
+ default:
+ inst = BREAK;
+ SLJIT_UNREACHABLE();
+ }
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
+ src = TMP_FREG1;
+ }
+
+ FAIL_IF(push_inst(compiler, inst | FRD(TMP_FREG1) | FRJ(src)));
+ FAIL_IF(push_inst(compiler, FINST(MOVFR2GR, word_data) | RD(dst_r) | FRJ(TMP_FREG1)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, word_data ? WORD_DATA : INT_DATA, TMP_REG2, dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins inst;
+ sljit_u32 word_data = 0;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ switch (GET_OPCODE(op))
+ {
+ case SLJIT_CONV_F64_FROM_SW:
+ word_data = 1;
+ inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_L : FFINT_D_L);
+ break;
+ case SLJIT_CONV_F64_FROM_S32:
+ inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_W : FFINT_D_W);
+ break;
+ default:
+ inst = BREAK;
+ SLJIT_UNREACHABLE();
+ }
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, (word_data ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
+ src = TMP_REG1;
+ } else if (src == SLJIT_IMM) {
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ src = TMP_REG1;
+ }
+ FAIL_IF(push_inst(compiler, (word_data ? MOVGR2FR_D : MOVGR2FR_W) | FRD(dst_r) | RJ(src)));
+ FAIL_IF(push_inst(compiler, inst | FRD(dst_r) | FRJ(dst_r)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ return sljit_emit_fop1_conv_f64_from_w(compiler, op, dst, dstw, src, srcw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins inst;
+ sljit_u32 word_data = 0;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ switch (GET_OPCODE(op))
+ {
+ case SLJIT_CONV_F64_FROM_UW:
+ word_data = 1;
+ inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_L : FFINT_D_L);
+ break;
+ case SLJIT_CONV_F64_FROM_U32:
+ inst = (sljit_ins)((op & SLJIT_32) ? FFINT_S_W : FFINT_D_W);
+ break;
+ default:
+ inst = BREAK;
+ SLJIT_UNREACHABLE();
+ }
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, (word_data ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
+ src = TMP_REG1;
+ } else if (src == SLJIT_IMM) {
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32)
+ srcw = (sljit_u32)srcw;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ src = TMP_REG1;
+ }
+
+ if (!word_data)
+ FAIL_IF(push_inst(compiler, SRLI_W | RD(src) | RJ(src) | IMM_I12(0)));
+
+ FAIL_IF(push_inst(compiler, BLT | RJ(src) | RD(TMP_ZERO) | IMM_I16(4)));
+
+ FAIL_IF(push_inst(compiler, (word_data ? MOVGR2FR_D : MOVGR2FR_W) | FRD(dst_r) | RJ(src)));
+ FAIL_IF(push_inst(compiler, inst | FRD(dst_r) | FRJ(dst_r)));
+ FAIL_IF(push_inst(compiler, B | IMM_I26(7)));
+
+ FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG2) | RJ(src) | IMM_I12(1)));
+ FAIL_IF(push_inst(compiler, (word_data ? SRLI_D : SRLI_W) | RD(TMP_REG1) | RJ(src) | IMM_I12(1)));
+ FAIL_IF(push_inst(compiler, OR | RD(TMP_REG1) | RJ(TMP_REG1) | RK(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, INST(MOVGR2FR, (!word_data)) | FRD(dst_r) | RJ(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, inst | FRD(dst_r) | FRJ(dst_r)));
+ FAIL_IF(push_inst(compiler, FINST(FADD, op) | FRD(dst_r) | FRJ(dst_r) | FRK(dst_r)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
+ src1 = TMP_FREG1;
+ }
+
+ if (src2 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0));
+ src2 = TMP_FREG2;
+ }
+
+ FAIL_IF(push_inst(compiler, XOR | RD(OTHER_FLAG) | RJ(OTHER_FLAG) | RK(OTHER_FLAG)));
+
+ switch (GET_FLAG_TYPE(op)) {
+ case SLJIT_F_EQUAL:
+ case SLJIT_ORDERED_EQUAL:
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CEQ | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+ break;
+ case SLJIT_F_LESS:
+ case SLJIT_ORDERED_LESS:
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CLT | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+ break;
+ case SLJIT_F_GREATER:
+ case SLJIT_ORDERED_GREATER:
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CLT | FCD(F_OTHER_FLAG) | FRJ(src2) | FRK(src1)));
+ break;
+ case SLJIT_UNORDERED_OR_GREATER:
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CULT | FCD(F_OTHER_FLAG) | FRJ(src2) | FRK(src1)));
+ break;
+ case SLJIT_UNORDERED_OR_LESS:
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CULT | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+ break;
+ case SLJIT_UNORDERED_OR_EQUAL:
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CUEQ | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+ break;
+ default: /* SLJIT_UNORDERED */
+ FAIL_IF(push_inst(compiler, FINST(FCMP_COND, op) | COND_CUN | FCD(F_OTHER_FLAG) | FRJ(src1) | FRK(src2)));
+ }
+ return push_inst(compiler, MOVCF2GR | RD(OTHER_FLAG) | FCJ(F_OTHER_FLAG));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ compiler->cache_arg = 0;
+ compiler->cache_argw = 0;
+
+ SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
+ SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+ op ^= SLJIT_32;
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, dst, dstw));
+ src = dst_r;
+ }
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV_F64:
+ if (src != dst_r) {
+ if (!(dst & SLJIT_MEM))
+ FAIL_IF(push_inst(compiler, FINST(FMOV, op) | FRD(dst_r) | FRJ(src)));
+ else
+ dst_r = src;
+ }
+ break;
+ case SLJIT_NEG_F64:
+ FAIL_IF(push_inst(compiler, FINST(FNEG, op) | FRD(dst_r) | FRJ(src)));
+ break;
+ case SLJIT_ABS_F64:
+ FAIL_IF(push_inst(compiler, FINST(FABS, op) | FRD(dst_r) | FRJ(src)));
+ break;
+ case SLJIT_CONV_F64_FROM_F32:
+ /* The SLJIT_32 bit is inverted because sljit_f32 needs to be loaded from the memory. */
+ FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? FCVT_D_S : FCVT_S_D) | FRD(dst_r) | FRJ(src)));
+ op ^= SLJIT_32;
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, FLOAT_DATA(op), dst_r, dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_s32 dst_r, flags = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ compiler->cache_arg = 0;
+ compiler->cache_argw = 0;
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
+
+ if (src1 & SLJIT_MEM) {
+ if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) {
+ FAIL_IF(compiler->error);
+ src1 = TMP_FREG1;
+ } else
+ flags |= SLOW_SRC1;
+ }
+
+ if (src2 & SLJIT_MEM) {
+ if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) {
+ FAIL_IF(compiler->error);
+ src2 = TMP_FREG2;
+ } else
+ flags |= SLOW_SRC2;
+ }
+
+ if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+ if ((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 {
+ FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
+ FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
+ }
+ }
+ else if (flags & SLOW_SRC1)
+ FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
+ else if (flags & SLOW_SRC2)
+ FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
+
+ if (flags & SLOW_SRC1)
+ src1 = TMP_FREG1;
+ if (flags & SLOW_SRC2)
+ src2 = TMP_FREG2;
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_ADD_F64:
+ FAIL_IF(push_inst(compiler, FINST(FADD, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+ break;
+ case SLJIT_SUB_F64:
+ FAIL_IF(push_inst(compiler, FINST(FSUB, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+ break;
+ case SLJIT_MUL_F64:
+ FAIL_IF(push_inst(compiler, FINST(FMUL, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+ break;
+ case SLJIT_DIV_F64:
+ FAIL_IF(push_inst(compiler, FINST(FDIV, op) | FRD(dst_r) | FRJ(src1) | FRK(src2)));
+ break;
+ }
+
+ if (dst_r != dst)
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_s32 reg;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fop2r(compiler, op, dst_freg, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ if (src2 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src2, src2w, 0, 0));
+ src2 = TMP_FREG1;
+ }
+
+ if (src1 & SLJIT_MEM) {
+ reg = (dst_freg == src2) ? TMP_FREG1 : dst_freg;
+ FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, reg, src1, src1w, 0, 0));
+ src1 = reg;
+ }
+
+ return push_inst(compiler, FINST(FCOPYSIGN, op) | FRD(dst_freg) | FRJ(src1) | FRK(src2));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm == 0)
+ return push_inst(compiler, MOVGR2FR_W | RJ(TMP_ZERO) | FRD(freg));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+ return push_inst(compiler, MOVGR2FR_W | RJ(TMP_REG1) | FRD(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_sw imm;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm == 0)
+ return push_inst(compiler, MOVGR2FR_D | RJ(TMP_ZERO) | FRD(freg));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+ return push_inst(compiler, MOVGR2FR_D | RJ(TMP_REG1) | FRD(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_ins inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+ inst = ((op & SLJIT_32) ? MOVGR2FR_W : MOVGR2FR_D) | FRD(freg) | RJ(reg);
+ else
+ inst = ((op & SLJIT_32) ? MOVFR2GR_S : MOVFR2GR_D) | RD(reg) | FRJ(freg);
+ return push_inst(compiler, inst);
+}
+
+/* --------------------------------------------------------------------- */
+/* Conditional instructions */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+ struct sljit_label *label;
+
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_emit_label(compiler));
+
+ if (compiler->last_label && compiler->last_label->size == compiler->size)
+ return compiler->last_label;
+
+ label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+ PTR_FAIL_IF(!label);
+ set_label(label, compiler);
+ return label;
+}
+
+static sljit_ins get_jump_instruction(sljit_s32 type)
+{
+ switch (type) {
+ case SLJIT_EQUAL:
+ case SLJIT_ATOMIC_NOT_STORED:
+ return BNE | RJ(EQUAL_FLAG) | RD(TMP_ZERO);
+ case SLJIT_NOT_EQUAL:
+ case SLJIT_ATOMIC_STORED:
+ return BEQ | RJ(EQUAL_FLAG) | RD(TMP_ZERO);
+ case SLJIT_LESS:
+ case SLJIT_GREATER:
+ case SLJIT_SIG_LESS:
+ case SLJIT_SIG_GREATER:
+ case SLJIT_OVERFLOW:
+ case SLJIT_CARRY:
+ return BEQ | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+ case SLJIT_GREATER_EQUAL:
+ case SLJIT_LESS_EQUAL:
+ case SLJIT_SIG_GREATER_EQUAL:
+ case SLJIT_SIG_LESS_EQUAL:
+ case SLJIT_NOT_OVERFLOW:
+ case SLJIT_NOT_CARRY:
+ return BNE | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+ case SLJIT_F_EQUAL:
+ case SLJIT_ORDERED_EQUAL:
+ case SLJIT_F_LESS:
+ case SLJIT_ORDERED_LESS:
+ case SLJIT_ORDERED_GREATER:
+ case SLJIT_UNORDERED_OR_GREATER:
+ case SLJIT_F_GREATER:
+ case SLJIT_UNORDERED_OR_LESS:
+ case SLJIT_UNORDERED_OR_EQUAL:
+ case SLJIT_UNORDERED:
+ return BEQ | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+ case SLJIT_ORDERED_NOT_EQUAL:
+ case SLJIT_ORDERED_LESS_EQUAL:
+ case SLJIT_ORDERED_GREATER_EQUAL:
+ case SLJIT_F_NOT_EQUAL:
+ case SLJIT_UNORDERED_OR_NOT_EQUAL:
+ case SLJIT_UNORDERED_OR_GREATER_EQUAL:
+ case SLJIT_UNORDERED_OR_LESS_EQUAL:
+ case SLJIT_F_LESS_EQUAL:
+ case SLJIT_F_GREATER_EQUAL:
+ case SLJIT_ORDERED:
+ return BNE | RJ(OTHER_FLAG) | RD(TMP_ZERO);
+ default:
+ /* Not conditional branch. */
+ return 0;
+ }
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+ struct sljit_jump *jump;
+ sljit_ins inst;
+
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+ type &= 0xff;
+
+ inst = get_jump_instruction(type);
+
+ if (inst != 0) {
+ PTR_FAIL_IF(push_inst(compiler, inst));
+ jump->flags |= IS_COND;
+ }
+
+ jump->addr = compiler->size;
+ inst = JIRL | RJ(TMP_REG1) | IMM_I16(0);
+
+ if (type >= SLJIT_FAST_CALL) {
+ jump->flags |= IS_CALL;
+ inst |= RD(RETURN_ADDR_REG);
+ }
+
+ PTR_FAIL_IF(push_inst(compiler, inst));
+
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
+ return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 arg_types)
+{
+ SLJIT_UNUSED_ARG(arg_types);
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+ if (type & SLJIT_CALL_RETURN) {
+ PTR_FAIL_IF(emit_stack_frame_release(compiler, 0));
+ type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP);
+ }
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_jump(compiler, type);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ struct sljit_jump *jump;
+ sljit_s32 flags;
+ sljit_ins inst;
+ 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));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ compiler->cache_arg = 0;
+ compiler->cache_argw = 0;
+
+ flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+
+ if (src1 & SLJIT_MEM) {
+ PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG1, src1, src1w, src2, src2w));
+ src1 = TMP_REG1;
+ }
+
+ if (src2 & SLJIT_MEM) {
+ PTR_FAIL_IF(emit_op_mem2(compiler, flags, src2_tmp_reg, src2, src2w, 0, 0));
+ src2 = src2_tmp_reg;
+ }
+
+ if (src1 == SLJIT_IMM) {
+ if (src1w != 0) {
+ PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+ src1 = TMP_REG1;
+ }
+ else
+ src1 = TMP_ZERO;
+ }
+
+ if (src2 == SLJIT_IMM) {
+ if (src2w != 0) {
+ PTR_FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w));
+ src2 = src2_tmp_reg;
+ }
+ else
+ src2 = TMP_ZERO;
+ }
+
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_jump(jump, compiler, (sljit_u32)((type & SLJIT_REWRITABLE_JUMP) | IS_COND));
+ type &= 0xff;
+
+ switch (type) {
+ case SLJIT_EQUAL:
+ inst = BNE | RJ(src1) | RD(src2);
+ break;
+ case SLJIT_NOT_EQUAL:
+ inst = BEQ | RJ(src1) | RD(src2);
+ break;
+ case SLJIT_LESS:
+ inst = BGEU | RJ(src1) | RD(src2);
+ break;
+ case SLJIT_GREATER_EQUAL:
+ inst = BLTU | RJ(src1) | RD(src2);
+ break;
+ case SLJIT_GREATER:
+ inst = BGEU | RJ(src2) | RD(src1);
+ break;
+ case SLJIT_LESS_EQUAL:
+ inst = BLTU | RJ(src2) | RD(src1);
+ break;
+ case SLJIT_SIG_LESS:
+ inst = BGE | RJ(src1) | RD(src2);
+ break;
+ case SLJIT_SIG_GREATER_EQUAL:
+ inst = BLT | RJ(src1) | RD(src2);
+ break;
+ case SLJIT_SIG_GREATER:
+ inst = BGE | RJ(src2) | RD(src1);
+ break;
+ case SLJIT_SIG_LESS_EQUAL:
+ inst = BLT | RJ(src2) | RD(src1);
+ break;
+ default:
+ inst = BREAK;
+ SLJIT_UNREACHABLE();
+ }
+
+ PTR_FAIL_IF(push_inst(compiler, inst));
+
+ jump->addr = compiler->size;
+ PTR_FAIL_IF(push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(TMP_REG1) | IMM_I12(0)));
+
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
+
+ return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+ struct sljit_jump *jump;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+
+ if (src != SLJIT_IMM) {
+ if (src & SLJIT_MEM) {
+ ADJUST_LOCAL_OFFSET(src, srcw);
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+ src = TMP_REG1;
+ }
+ return push_inst(compiler, JIRL | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RJ(src) | IMM_I12(0));
+ }
+
+ /* These jumps are converted to jump/call instructions when possible. */
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ FAIL_IF(!jump);
+ set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_CALL : 0));
+ jump->u.target = (sljit_uw)srcw;
+
+ jump->addr = compiler->size;
+ FAIL_IF(push_inst(compiler, JIRL | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RJ(TMP_REG1) | IMM_I12(0)));
+
+ /* Maximum number of instructions required for generating a constant. */
+ compiler->size += JUMP_MAX_SIZE - 1;
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 arg_types,
+ sljit_s32 src, sljit_sw srcw)
+{
+ SLJIT_UNUSED_ARG(arg_types);
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+ if (src & SLJIT_MEM) {
+ ADJUST_LOCAL_OFFSET(src, srcw);
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+ src = TMP_REG1;
+ }
+
+ if (type & SLJIT_CALL_RETURN) {
+ if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(src) | IMM_I12(0)));
+ src = TMP_REG1;
+ }
+
+ FAIL_IF(emit_stack_frame_release(compiler, 0));
+ type = SLJIT_JUMP;
+ }
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_ijump(compiler, type, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 type)
+{
+ sljit_s32 src_r, dst_r, invert;
+ sljit_s32 saved_op = op;
+ sljit_s32 mem_type = ((op & SLJIT_32) || op == SLJIT_MOV32) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ op = GET_OPCODE(op);
+ dst_r = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
+
+ compiler->cache_arg = 0;
+ compiler->cache_argw = 0;
+
+ if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
+ FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
+
+ if (type < SLJIT_F_EQUAL) {
+ src_r = OTHER_FLAG;
+ invert = type & 0x1;
+
+ switch (type) {
+ case SLJIT_EQUAL:
+ case SLJIT_NOT_EQUAL:
+ FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(EQUAL_FLAG) | IMM_I12(1)));
+ src_r = dst_r;
+ break;
+ case SLJIT_ATOMIC_STORED:
+ case SLJIT_ATOMIC_NOT_STORED:
+ FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(EQUAL_FLAG) | IMM_I12(1)));
+ src_r = dst_r;
+ invert ^= 0x1;
+ break;
+ case SLJIT_OVERFLOW:
+ case SLJIT_NOT_OVERFLOW:
+ if (compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)) {
+ src_r = OTHER_FLAG;
+ break;
+ }
+ FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(OTHER_FLAG) | IMM_I12(1)));
+ src_r = dst_r;
+ invert ^= 0x1;
+ break;
+ }
+ } else {
+ invert = 0;
+ src_r = OTHER_FLAG;
+
+ switch (type) {
+ case SLJIT_ORDERED_NOT_EQUAL:
+ case SLJIT_ORDERED_LESS_EQUAL:
+ case SLJIT_ORDERED_GREATER_EQUAL:
+ case SLJIT_F_NOT_EQUAL:
+ case SLJIT_UNORDERED_OR_NOT_EQUAL:
+ case SLJIT_UNORDERED_OR_GREATER_EQUAL:
+ case SLJIT_UNORDERED_OR_LESS_EQUAL:
+ case SLJIT_F_LESS_EQUAL:
+ case SLJIT_F_GREATER_EQUAL:
+ case SLJIT_ORDERED:
+ invert = 1;
+ break;
+ }
+ }
+
+ if (invert) {
+ FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RJ(src_r) | IMM_I12(1)));
+ src_r = dst_r;
+ }
+
+ if (op < SLJIT_ADD) {
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, mem_type, src_r, dst, dstw);
+
+ if (src_r != dst_r)
+ return push_inst(compiler, ADDI_D | RD(dst_r) | RJ(src_r) | IMM_I12(0));
+ return SLJIT_SUCCESS;
+ }
+
+ mem_type |= CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE;
+
+ if (dst & SLJIT_MEM)
+ return emit_op(compiler, saved_op, mem_type, dst, dstw, TMP_REG1, 0, src_r, 0);
+ return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, src_r, 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
+{
+ sljit_ins *ptr;
+ sljit_uw size;
+ sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(dst_reg) | IMM_I12(0)));
+
+ if ((src1 & REG_MASK) == dst_reg)
+ src1 = (src1 & ~REG_MASK) | TMP_REG1;
+
+ if (OFFS_REG(src1) == dst_reg)
+ 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)));
+ }
+ }
+
+ size = compiler->size;
+
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+ FAIL_IF(!ptr);
+ compiler->size++;
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w));
+ } else if (src1 == SLJIT_IMM) {
+ if (type & SLJIT_32)
+ src1w = (sljit_s32)src1w;
+ FAIL_IF(load_immediate(compiler, dst_reg, src1w));
+ } else
+ FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_reg) | RJ(src1) | IMM_I12(0)));
+
+ *ptr = get_jump_instruction(type & ~SLJIT_32) | IMM_I16(compiler->size - size);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+ sljit_s32 invert = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if ((type & ~SLJIT_32) == SLJIT_EQUAL || (type & ~SLJIT_32) == SLJIT_NOT_EQUAL) {
+ if ((type & ~SLJIT_32) == SLJIT_EQUAL)
+ invert = 1;
+ FAIL_IF(push_inst(compiler, MOVGR2CF | FCD(F_OTHER_FLAG) | RJ(EQUAL_FLAG)));
+ } else {
+ 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, TMP_FREG2, src1, src1w));
+ if (invert)
+ 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));
+ return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src2_freg) | FRK(src1) | FCA(F_OTHER_FLAG));
+ }
+}
+
+#undef FLOAT_DATA
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 reg,
+ sljit_s32 mem, sljit_sw memw)
+{
+ sljit_s32 flags;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+ if (!(reg & REG_PAIR_MASK))
+ return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw);
+
+ if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+ memw &= 0x3;
+
+ if (SLJIT_UNLIKELY(memw != 0)) {
+ FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG1) | RJ(OFFS_REG(mem)) | IMM_I12(memw)));
+ FAIL_IF(push_inst(compiler, ADD_D| RD(TMP_REG1) | RJ(TMP_REG1) | RK(mem & REG_MASK)));
+ } else
+ FAIL_IF(push_inst(compiler, ADD_D| RD(TMP_REG1) | RJ(mem & REG_MASK) | RK(OFFS_REG(mem))));
+
+ mem = TMP_REG1;
+ memw = 0;
+ } else if (memw > I12_MAX - SSIZE_OF(sw) || memw < I12_MIN) {
+ if (((memw + 0x800) & 0xfff) <= 0xfff - SSIZE_OF(sw)) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, TO_ARGW_HI(memw)));
+ memw &= 0xfff;
+ } else {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, memw));
+ memw = 0;
+ }
+
+ if (mem & REG_MASK)
+ FAIL_IF(push_inst(compiler, ADD_D| RD(TMP_REG1) | RJ(TMP_REG1) | RK(mem & REG_MASK)));
+
+ mem = TMP_REG1;
+ } else {
+ mem &= REG_MASK;
+ memw &= 0xfff;
+ }
+
+ SLJIT_ASSERT((memw >= 0 && memw <= I12_MAX - SSIZE_OF(sw)) || (memw > I12_MAX && memw <= 0xfff));
+
+ if (!(type & SLJIT_MEM_STORE) && mem == REG_PAIR_FIRST(reg)) {
+ FAIL_IF(push_mem_inst(compiler, WORD_DATA | LOAD_DATA, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), (memw + SSIZE_OF(sw)) & 0xfff));
+ return push_mem_inst(compiler, WORD_DATA | LOAD_DATA, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw);
+ }
+
+ flags = WORD_DATA | (!(type & SLJIT_MEM_STORE) ? LOAD_DATA : 0);
+
+ FAIL_IF(push_mem_inst(compiler, flags, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw));
+ return push_mem_inst(compiler, flags, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), (memw + SSIZE_OF(sw)) & 0xfff);
+}
+
+#undef TO_ARGW_HI
+
+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,
+ sljit_s32 mem_reg)
+{
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+ switch(GET_OPCODE(op)) {
+ case SLJIT_MOV_U8:
+ ins = LD_BU;
+ break;
+ case SLJIT_MOV_U16:
+ ins = LD_HU;
+ break;
+ case SLJIT_MOV32:
+ ins = LD_W;
+ break;
+ case SLJIT_MOV_U32:
+ ins = LD_WU;
+ break;
+ default:
+ ins = LD_D;
+ break;
+ }
+
+ return push_inst(compiler, ins | RD(dst_reg) | RJ(mem_reg) | IMM_I12(0));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler,
+ sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ sljit_ins ins = 0;
+ sljit_ins unsign = 0;
+ sljit_s32 tmp = temp_reg;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV_U8:
+ ins = AMCAS_B;
+ unsign = BSTRPICK_D | (7 << 16);
+ break;
+ case SLJIT_MOV_U16:
+ ins = AMCAS_H;
+ unsign = BSTRPICK_D | (15 << 16);
+ break;
+ case SLJIT_MOV32:
+ ins = AMCAS_W;
+ break;
+ case SLJIT_MOV_U32:
+ ins = AMCAS_W;
+ unsign = BSTRPICK_D | (31 << 16);
+ break;
+ default:
+ ins = AMCAS_D;
+ break;
+ }
+
+ if (op & SLJIT_SET_ATOMIC_STORED) {
+ FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RJ(temp_reg) | RK(TMP_ZERO)));
+ tmp = TMP_REG1;
+ }
+ FAIL_IF(push_inst(compiler, ins | RD(tmp) | RJ(mem_reg) | RK(src_reg)));
+ if (!(op & SLJIT_SET_ATOMIC_STORED))
+ return SLJIT_SUCCESS;
+
+ if (unsign)
+ FAIL_IF(push_inst(compiler, unsign | RD(tmp) | RJ(tmp)));
+
+ FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(tmp) | RK(temp_reg)));
+ return push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(EQUAL_FLAG) | IMM_I12(1));
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
+{
+ SLJIT_UNUSED_ARG(last_ins);
+
+ FAIL_IF(push_inst(compiler, LU12I_W | RD(dst) | (sljit_ins)(((init_value & 0xffffffff) >> 12) << 5)));
+ FAIL_IF(push_inst(compiler, LU32I_D | RD(dst) | (sljit_ins)(((init_value >> 32) & 0xfffff) << 5)));
+ FAIL_IF(push_inst(compiler, LU52I_D | RD(dst) | RJ(dst) | (sljit_ins)(IMM_I12(init_value >> 52))));
+ return push_inst(compiler, ORI | RD(dst) | RJ(dst) | IMM_I12(init_value));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+ sljit_ins *inst = (sljit_ins*)addr;
+ SLJIT_UNUSED_ARG(executable_offset);
+
+ SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0);
+
+ SLJIT_ASSERT((inst[0] & OPC_1RI20(0x7f)) == LU12I_W);
+ inst[0] = (inst[0] & (OPC_1RI20(0x7f) | 0x1f)) | (sljit_ins)(((new_target & 0xffffffff) >> 12) << 5);
+
+ SLJIT_ASSERT((inst[1] & OPC_1RI20(0x7f)) == LU32I_D);
+ inst[1] = (inst[1] & (OPC_1RI20(0x7f) | 0x1f)) | (sljit_ins)(sljit_ins)(((new_target >> 32) & 0xfffff) << 5);
+
+ SLJIT_ASSERT((inst[2] & OPC_2RI12(0x3ff)) == LU52I_D);
+ inst[2] = (inst[2] & (OPC_2RI12(0x3ff) | 0x3ff)) | IMM_I12(new_target >> 52);
+
+ SLJIT_ASSERT((inst[3] & OPC_2RI12(0x3ff)) == ORI || (inst[3] & OPC_2RI16(0x3f)) == JIRL);
+ if ((inst[3] & OPC_2RI12(0x3ff)) == ORI)
+ inst[3] = (inst[3] & (OPC_2RI12(0x3ff) | 0x3ff)) | IMM_I12(new_target);
+ else
+ inst[3] = (inst[3] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I12((new_target & 0xfff) >> 2);
+
+ SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1);
+
+ inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ SLJIT_CACHE_FLUSH(inst, inst + 4);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+ struct sljit_const *const_;
+ sljit_s32 dst_r;
+
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+ PTR_FAIL_IF(!const_);
+ set_const(const_, compiler);
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ PTR_FAIL_IF(emit_const(compiler, dst_r, init_value, 0));
+
+ if (dst & SLJIT_MEM)
+ PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+
+ return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+ struct sljit_jump *jump;
+ sljit_s32 dst_r;
+
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ 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 += JUMP_MAX_SIZE - 1;
+
+ if (dst & SLJIT_MEM)
+ PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+
+ return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+ sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
+}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
index 9620b945f6..91153e5f25 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
@@ -225,7 +225,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
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;
@@ -370,7 +370,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compile
} 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;
@@ -441,7 +441,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
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));
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
index 52a0d3fb7a..b9f03a7bd2 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
@@ -225,7 +225,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
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;
@@ -309,7 +309,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compile
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;
@@ -366,7 +366,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
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));
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
index 807b3474ea..88eb30b7f1 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
@@ -83,7 +83,7 @@ typedef sljit_u32 sljit_ins;
#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
@@ -95,7 +95,7 @@ typedef sljit_u32 sljit_ins;
#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)
@@ -504,7 +504,7 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
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;
}
@@ -635,75 +635,66 @@ static __attribute__ ((noinline)) void sljit_cache_flush(void* code, void* code_
#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;
@@ -711,77 +702,76 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_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++;
@@ -791,7 +781,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)code_ptr;
+ label->u.addr = (sljit_uw)code_ptr;
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
}
@@ -799,13 +789,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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) {
@@ -821,15 +810,10 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
@@ -932,9 +916,9 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s
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)
@@ -1001,9 +985,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
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;
@@ -1212,8 +1196,8 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
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;
}
@@ -1711,7 +1695,7 @@ static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit
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;
@@ -1963,8 +1947,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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;
}
@@ -2283,7 +2268,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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;
@@ -2299,7 +2284,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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;
@@ -2351,8 +2336,8 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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;
@@ -2366,16 +2351,16 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
}
}
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));
}
@@ -2387,7 +2372,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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));
@@ -2659,12 +2644,28 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
#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,
@@ -2718,18 +2719,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
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)));
@@ -2739,14 +2740,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
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)
@@ -3103,7 +3103,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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;
@@ -3162,11 +3162,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
}
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));
}
@@ -3361,10 +3360,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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;
@@ -3392,8 +3391,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
#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; \
@@ -3406,6 +3405,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
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));
@@ -3426,8 +3426,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
}
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));
@@ -3515,7 +3515,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
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));
@@ -3553,11 +3553,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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)
@@ -3755,8 +3755,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
#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)
@@ -3784,13 +3784,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
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)));
@@ -3847,8 +3847,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com
#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);
@@ -4231,18 +4231,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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));
@@ -4255,5 +4255,5 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct slj
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw));
- return put_label;
+ return jump;
}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
index 54977f02e3..1f17d90423 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
@@ -98,7 +98,7 @@ static void ppc_cache_flush(sljit_ins *from, sljit_ins *to)
#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)
@@ -310,24 +310,23 @@ static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, 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;
}
@@ -336,101 +335,256 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_in
goto keep_address;
#endif
- diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - 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;
@@ -438,18 +592,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_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 */
@@ -459,93 +612,64 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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++;
@@ -555,7 +679,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)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;
}
@@ -563,7 +687,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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))));
@@ -573,84 +696,10 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
@@ -671,11 +720,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
#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
}
@@ -937,14 +984,16 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
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;
}
}
@@ -986,7 +1035,7 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
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));
}
@@ -1253,7 +1302,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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. */
@@ -1264,24 +1313,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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. */
@@ -1291,17 +1323,30 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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));
@@ -1757,7 +1802,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
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);
@@ -1772,7 +1817,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
}
- 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);
@@ -1911,13 +1956,31 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
+ return sljit_emit_op2(compiler, op, 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,
@@ -2228,7 +2291,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
/* 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;
@@ -2268,7 +2331,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
}
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;
}
@@ -2451,7 +2514,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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)
@@ -2461,10 +2524,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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;
}
@@ -2498,18 +2562,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- if (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);
@@ -2521,8 +2574,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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));
@@ -2530,8 +2599,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
}
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));
}
@@ -2748,13 +2815,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
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)));
@@ -3061,31 +3128,31 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
index 64bd411d9d..d86100a80c 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
@@ -181,24 +181,23 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i
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);
}
@@ -265,83 +264,109 @@ exit:
#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;
@@ -350,30 +375,128 @@ static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
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;
@@ -381,77 +504,78 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
sljit_ins *buf_ptr;
sljit_ins *buf_end;
sljit_uw word_count;
- sljit_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++;
@@ -461,7 +585,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
} while (buf);
if (label && label->size == word_count) {
- label->addr = (sljit_uw)code_ptr;
+ label->u.addr = (sljit_uw)code_ptr;
label->size = (sljit_uw)(code_ptr - code);
label = label->next;
}
@@ -469,18 +593,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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);
@@ -491,31 +614,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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;
@@ -599,6 +703,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
#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
@@ -883,7 +988,6 @@ static sljit_s32 push_mem_inst(struct sljit_compiler *compiler, sljit_s32 flags,
/* 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) {
@@ -928,7 +1032,7 @@ static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, slj
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);
@@ -937,11 +1041,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
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;
@@ -1187,7 +1286,7 @@ static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit
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;
@@ -1197,20 +1296,20 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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));
@@ -1219,7 +1318,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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));
@@ -1228,7 +1327,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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));
@@ -1238,7 +1337,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
#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));
@@ -1247,7 +1346,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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);
@@ -1256,7 +1355,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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:
@@ -1264,17 +1363,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
#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;
@@ -1402,8 +1501,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
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;
}
@@ -1631,7 +1731,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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;
@@ -1647,7 +1747,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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;
@@ -1673,16 +1773,14 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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
@@ -1696,14 +1794,12 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
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)
@@ -1713,30 +1809,28 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
}
}
}
- }
- 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));
@@ -1819,42 +1913,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
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();
@@ -1941,6 +2035,30 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
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,
@@ -2292,7 +2410,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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;
@@ -2351,11 +2469,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
}
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));
}
@@ -2391,7 +2508,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
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;
@@ -2522,11 +2639,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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;
}
@@ -2553,6 +2666,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
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));
@@ -2573,8 +2687,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
}
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) {
@@ -2588,8 +2702,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
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;
@@ -2639,11 +2753,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
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;
}
@@ -2675,11 +2785,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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;
}
@@ -2826,13 +2932,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
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)));
@@ -2856,7 +2962,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
} 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;
}
@@ -2895,7 +3002,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com
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;
}
@@ -2980,31 +3088,31 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c b/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c
index 67516f9b32..99e846350f 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c
@@ -38,12 +38,9 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
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)
@@ -140,50 +137,21 @@ static SLJIT_INLINE sljit_gpr gpr(sljit_s32 r)
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;
}
@@ -1424,97 +1392,60 @@ static sljit_s32 emit_non_commutative(struct sljit_compiler *compiler, const str
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
@@ -1523,130 +1454,166 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
*/
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;
@@ -2497,7 +2464,7 @@ static sljit_s32 sljit_emit_sub(struct sljit_compiler *compiler, sljit_s32 op,
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;
@@ -2597,7 +2564,7 @@ done:
- 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)
@@ -2759,7 +2726,7 @@ static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 o
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;
@@ -2775,13 +2742,13 @@ static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 o
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);
@@ -3002,11 +2969,31 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
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,
@@ -3415,12 +3402,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
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) \
@@ -3491,7 +3476,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
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;
}
@@ -3738,8 +3722,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
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
@@ -3837,8 +3822,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
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);
@@ -4474,9 +4459,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)));
}
@@ -4503,20 +4488,18 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta
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;
@@ -4530,7 +4513,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label *sljit_emit_put_label(
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 */
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
deleted file mode 100644
index 218992b355..0000000000
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * 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.
- */
-
-static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw imm)
-{
- if (imm <= SIMM_MAX && imm >= SIMM_MIN)
- return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
-
- FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((imm >> 10) & 0x3fffff), DR(dst)));
- return (imm & 0x3ff) ? push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (imm & 0x3ff), DR(dst)) : SLJIT_SUCCESS;
-}
-
-#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
-
-static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_u32 flags,
- sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
-{
- SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
-
- switch (op) {
- case SLJIT_MOV:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
- if (dst != src2)
- return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
- return SLJIT_SUCCESS;
-
- case SLJIT_MOV_U8:
- case SLJIT_MOV_S8:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
- if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- if (op == SLJIT_MOV_U8)
- return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
- FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
- return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
- }
- SLJIT_ASSERT(dst == src2);
- return SLJIT_SUCCESS;
-
- case SLJIT_MOV_U16:
- case SLJIT_MOV_S16:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
- if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
- FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
- return push_inst(compiler, (op == SLJIT_MOV_S16 ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
- }
- SLJIT_ASSERT(dst == src2);
- return SLJIT_SUCCESS;
-
- case SLJIT_NOT:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
- return push_inst(compiler, XNOR | (flags & SET_FLAGS) | D(dst) | S1(0) | S2(src2), DRF(dst, flags));
-
- case SLJIT_CLZ:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
- FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
- FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
- FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
- FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS));
- FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
-
- /* Loop. */
- FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
- FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
- FAIL_IF(push_inst(compiler, BICC | DA(0xe) | ((sljit_ins)-2 & DISP_MASK), UNMOVABLE_INS));
- return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS);
-
- case SLJIT_ADD:
- compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
- return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_ADDC:
- compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
- return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_SUB:
- compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
- return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_SUBC:
- compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
- return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_MUL:
- compiler->status_flags_state = 0;
- FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
- if (!(flags & SET_FLAGS))
- return SLJIT_SUCCESS;
- FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(dst) | IMM(31), DR(TMP_REG1)));
- FAIL_IF(push_inst(compiler, RDY | D(TMP_LINK), DR(TMP_LINK)));
- return push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(TMP_LINK), MOVABLE_INS | SET_FLAGS);
-
- case SLJIT_AND:
- return push_inst(compiler, AND | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_OR:
- return push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_XOR:
- return push_inst(compiler, XOR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DRF(dst, flags));
-
- case SLJIT_SHL:
- FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
- return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
-
- case SLJIT_LSHR:
- FAIL_IF(push_inst(compiler, SRL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
- return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
-
- case SLJIT_ASHR:
- FAIL_IF(push_inst(compiler, SRA | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
- return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
- }
-
- SLJIT_UNREACHABLE();
- return SLJIT_SUCCESS;
-}
-
-static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
-{
- sljit_s32 reg_index = 8;
- sljit_s32 word_reg_index = 8;
- sljit_s32 float_arg_index = 1;
- sljit_s32 double_arg_count = 0;
- sljit_u32 float_offset = (16 + 6) * sizeof(sljit_sw);
- sljit_s32 types = 0;
- sljit_s32 reg = 0;
- sljit_s32 move_to_tmp2 = 0;
-
- if (src)
- reg = reg_map[*src & REG_MASK];
-
- arg_types >>= SLJIT_ARG_SHIFT;
-
- while (arg_types) {
- types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK);
-
- switch (arg_types & SLJIT_ARG_MASK) {
- case SLJIT_ARG_TYPE_F64:
- float_arg_index++;
- double_arg_count++;
- if (reg_index == reg || reg_index + 1 == reg)
- move_to_tmp2 = 1;
- reg_index += 2;
- break;
- case SLJIT_ARG_TYPE_F32:
- float_arg_index++;
- if (reg_index == reg)
- move_to_tmp2 = 1;
- reg_index++;
- break;
- default:
- if (reg_index != word_reg_index && reg_index == reg)
- move_to_tmp2 = 1;
- reg_index++;
- word_reg_index++;
- break;
- }
-
- arg_types >>= SLJIT_ARG_SHIFT;
- }
-
- if (move_to_tmp2) {
- if (reg < 14)
- FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2A(reg), DR(TMP_REG1)));
- *src = TMP_REG1;
- }
-
- arg_types = types;
-
- while (arg_types) {
- switch (arg_types & SLJIT_ARG_MASK) {
- case SLJIT_ARG_TYPE_F64:
- float_arg_index--;
- if (float_arg_index == 4 && double_arg_count == 4) {
- /* The address is not doubleword aligned, so two instructions are required to store the double. */
- FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | S1(SLJIT_SP) | IMM((16 + 7) * sizeof(sljit_sw)), MOVABLE_INS));
- FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | (1 << 25) | S1(SLJIT_SP) | IMM((16 + 8) * sizeof(sljit_sw)), MOVABLE_INS));
- }
- else
- FAIL_IF(push_inst(compiler, STDF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- float_offset -= sizeof(sljit_f64);
- break;
- case SLJIT_ARG_TYPE_F32:
- float_arg_index--;
- FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- float_offset -= sizeof(sljit_f64);
- break;
- default:
- break;
- }
-
- arg_types >>= SLJIT_ARG_SHIFT;
- }
-
- float_offset = (16 + 6) * sizeof(sljit_sw);
-
- while (types) {
- switch (types & SLJIT_ARG_MASK) {
- case SLJIT_ARG_TYPE_F64:
- reg_index -= 2;
- if (reg_index < 14) {
- if ((reg_index & 0x1) != 0) {
- FAIL_IF(push_inst(compiler, LDUW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
- if (reg_index < 8 + 6 - 1)
- FAIL_IF(push_inst(compiler, LDUW | DA(reg_index + 1) | S1(SLJIT_SP) | IMM(float_offset + sizeof(sljit_sw)), reg_index + 1));
- }
- else
- FAIL_IF(push_inst(compiler, LDD | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
- }
- float_offset -= sizeof(sljit_f64);
- break;
- case SLJIT_ARG_TYPE_F32:
- reg_index--;
- if (reg_index < 8 + 6)
- FAIL_IF(push_inst(compiler, LDUW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
- float_offset -= sizeof(sljit_f64);
- break;
- default:
- reg_index--;
- word_reg_index--;
-
- if (reg_index != word_reg_index) {
- if (reg_index < 14)
- FAIL_IF(push_inst(compiler, OR | DA(reg_index) | S1(0) | S2A(word_reg_index), reg_index));
- else
- FAIL_IF(push_inst(compiler, STW | DA(word_reg_index) | S1(SLJIT_SP) | IMM(92), word_reg_index));
- }
- break;
- }
-
- types >>= SLJIT_ARG_SHIFT;
- }
-
- return SLJIT_SUCCESS;
-}
-
-static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
-{
- FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
- return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
-{
- sljit_ins *inst = (sljit_ins *)addr;
- SLJIT_UNUSED_ARG(executable_offset);
-
- SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
- SLJIT_ASSERT(((inst[0] & 0xc1c00000) == 0x01000000) && ((inst[1] & 0xc1f82000) == 0x80102000));
- inst[0] = (inst[0] & 0xffc00000) | ((new_target >> 10) & 0x3fffff);
- inst[1] = (inst[1] & 0xfffffc00) | (new_target & 0x3ff);
- SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
- inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
- SLJIT_CACHE_FLUSH(inst, inst + 2);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
-{
- sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
-}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
deleted file mode 100644
index c8d19e16c6..0000000000
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
+++ /dev/null
@@ -1,1673 +0,0 @@
-/*
- * 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 const char* sljit_get_platform_name(void)
-{
- return "SPARC" SLJIT_CPUINFO;
-}
-
-/* Length of an instruction word
- Both for sparc-32 and sparc-64 */
-typedef sljit_u32 sljit_ins;
-
-#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
-
-static void sparc_cache_flush(sljit_ins *from, sljit_ins *to)
-{
-#if defined(__SUNPRO_C) && __SUNPRO_C < 0x590
- __asm (
- /* if (from == to) return */
- "cmp %i0, %i1\n"
- "be .leave\n"
- "nop\n"
-
- /* loop until from >= to */
- ".mainloop:\n"
- "flush %i0\n"
- "add %i0, 8, %i0\n"
- "cmp %i0, %i1\n"
- "bcs .mainloop\n"
- "nop\n"
-
- /* The comparison was done above. */
- "bne .leave\n"
- /* nop is not necessary here, since the
- sub operation has no side effect. */
- "sub %i0, 4, %i0\n"
- "flush %i0\n"
- ".leave:"
- );
-#else
- if (SLJIT_UNLIKELY(from == to))
- return;
-
- do {
- __asm__ volatile (
- "flush %0\n"
- : : "r"(from)
- );
- /* Operates at least on doubleword. */
- from += 2;
- } while (from < to);
-
- if (from == to) {
- /* Flush the last word. */
- from --;
- __asm__ volatile (
- "flush %0\n"
- : : "r"(from)
- );
- }
-#endif
-}
-
-#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
-
-/* TMP_REG2 is not used by getput_arg */
-#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
-#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
-#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
-/* This register is modified by calls, which affects the instruction
- in the delay slot if it is used as a source register. */
-#define TMP_LINK (SLJIT_NUMBER_OF_REGISTERS + 5)
-
-#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
-#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
-
-static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
- 0, 8, 9, 10, 11, 23, 22, 21, 20, 19, 18, 17, 16, 29, 28, 27, 26, 25, 24, 14, 1, 12, 13, 15
-};
-
-static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
- 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
-};
-
-/* --------------------------------------------------------------------- */
-/* Instrucion forms */
-/* --------------------------------------------------------------------- */
-
-#define D(d) ((sljit_ins)reg_map[d] << 25)
-#define FD(d) ((sljit_ins)freg_map[d] << 25)
-#define FDN(d) (((sljit_ins)freg_map[d] | 0x1) << 25)
-#define DA(d) ((sljit_ins)(d) << 25)
-#define S1(s1) ((sljit_ins)reg_map[s1] << 14)
-#define FS1(s1) ((sljit_ins)freg_map[s1] << 14)
-#define S1A(s1) ((sljit_ins)(s1) << 14)
-#define S2(s2) ((sljit_ins)reg_map[s2])
-#define FS2(s2) ((sljit_ins)freg_map[s2])
-#define FS2N(s2) ((sljit_ins)freg_map[s2] | 0x1)
-#define S2A(s2) ((sljit_ins)(s2))
-#define IMM_ARG 0x2000
-#define DOP(op) ((sljit_ins)(op) << 5)
-#define IMM(imm) (((sljit_ins)(imm) & 0x1fff) | IMM_ARG)
-
-#define DR(dr) (reg_map[dr])
-#define DRF(dr, flags) ((sljit_s32)(reg_map[dr] | ((flags) & SET_FLAGS)))
-#define OPC1(opcode) ((sljit_ins)(opcode) << 30)
-#define OPC2(opcode) ((sljit_ins)(opcode) << 22)
-#define OPC3(opcode) ((sljit_ins)(opcode) << 19)
-#define SET_FLAGS OPC3(0x10)
-
-#define ADD (OPC1(0x2) | OPC3(0x00))
-#define ADDC (OPC1(0x2) | OPC3(0x08))
-#define AND (OPC1(0x2) | OPC3(0x01))
-#define ANDN (OPC1(0x2) | OPC3(0x05))
-#define CALL (OPC1(0x1))
-#define FABSS (OPC1(0x2) | OPC3(0x34) | DOP(0x09))
-#define FADDD (OPC1(0x2) | OPC3(0x34) | DOP(0x42))
-#define FADDS (OPC1(0x2) | OPC3(0x34) | DOP(0x41))
-#define FCMPD (OPC1(0x2) | OPC3(0x35) | DOP(0x52))
-#define FCMPS (OPC1(0x2) | OPC3(0x35) | DOP(0x51))
-#define FDIVD (OPC1(0x2) | OPC3(0x34) | DOP(0x4e))
-#define FDIVS (OPC1(0x2) | OPC3(0x34) | DOP(0x4d))
-#define FDTOI (OPC1(0x2) | OPC3(0x34) | DOP(0xd2))
-#define FDTOS (OPC1(0x2) | OPC3(0x34) | DOP(0xc6))
-#define FITOD (OPC1(0x2) | OPC3(0x34) | DOP(0xc8))
-#define FITOS (OPC1(0x2) | OPC3(0x34) | DOP(0xc4))
-#define FMOVS (OPC1(0x2) | OPC3(0x34) | DOP(0x01))
-#define FMULD (OPC1(0x2) | OPC3(0x34) | DOP(0x4a))
-#define FMULS (OPC1(0x2) | OPC3(0x34) | DOP(0x49))
-#define FNEGS (OPC1(0x2) | OPC3(0x34) | DOP(0x05))
-#define FSTOD (OPC1(0x2) | OPC3(0x34) | DOP(0xc9))
-#define FSTOI (OPC1(0x2) | OPC3(0x34) | DOP(0xd1))
-#define FSUBD (OPC1(0x2) | OPC3(0x34) | DOP(0x46))
-#define FSUBS (OPC1(0x2) | OPC3(0x34) | DOP(0x45))
-#define JMPL (OPC1(0x2) | OPC3(0x38))
-#define LDD (OPC1(0x3) | OPC3(0x03))
-#define LDDF (OPC1(0x3) | OPC3(0x23))
-#define LDF (OPC1(0x3) | OPC3(0x20))
-#define LDUW (OPC1(0x3) | OPC3(0x00))
-#define NOP (OPC1(0x0) | OPC2(0x04))
-#define OR (OPC1(0x2) | OPC3(0x02))
-#define ORN (OPC1(0x2) | OPC3(0x06))
-#define RDY (OPC1(0x2) | OPC3(0x28) | S1A(0))
-#define RESTORE (OPC1(0x2) | OPC3(0x3d))
-#define SAVE (OPC1(0x2) | OPC3(0x3c))
-#define SETHI (OPC1(0x0) | OPC2(0x04))
-#define SLL (OPC1(0x2) | OPC3(0x25))
-#define SLLX (OPC1(0x2) | OPC3(0x25) | (1 << 12))
-#define SRA (OPC1(0x2) | OPC3(0x27))
-#define SRAX (OPC1(0x2) | OPC3(0x27) | (1 << 12))
-#define SRL (OPC1(0x2) | OPC3(0x26))
-#define SRLX (OPC1(0x2) | OPC3(0x26) | (1 << 12))
-#define STD (OPC1(0x3) | OPC3(0x07))
-#define STDF (OPC1(0x3) | OPC3(0x27))
-#define STF (OPC1(0x3) | OPC3(0x24))
-#define STW (OPC1(0x3) | OPC3(0x04))
-#define SUB (OPC1(0x2) | OPC3(0x04))
-#define SUBC (OPC1(0x2) | OPC3(0x0c))
-#define TA (OPC1(0x2) | OPC3(0x3a) | (8 << 25))
-#define WRY (OPC1(0x2) | OPC3(0x30) | DA(0))
-#define XOR (OPC1(0x2) | OPC3(0x03))
-#define XNOR (OPC1(0x2) | OPC3(0x07))
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
-#define MAX_DISP (0x1fffff)
-#define MIN_DISP (-0x200000)
-#define DISP_MASK ((sljit_ins)0x3fffff)
-
-#define BICC (OPC1(0x0) | OPC2(0x2))
-#define FBFCC (OPC1(0x0) | OPC2(0x6))
-#define SLL_W SLL
-#define SDIV (OPC1(0x2) | OPC3(0x0f))
-#define SMUL (OPC1(0x2) | OPC3(0x0b))
-#define UDIV (OPC1(0x2) | OPC3(0x0e))
-#define UMUL (OPC1(0x2) | OPC3(0x0a))
-#else
-#define SLL_W SLLX
-#endif
-
-#define SIMM_MAX (0x0fff)
-#define SIMM_MIN (-0x1000)
-
-/* dest_reg is the absolute name of the register
- Useful for reordering instructions in the delay slot. */
-static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot)
-{
- sljit_ins *ptr;
- SLJIT_ASSERT((delay_slot & DST_INS_MASK) == UNMOVABLE_INS
- || (delay_slot & DST_INS_MASK) == MOVABLE_INS
- || (delay_slot & DST_INS_MASK) == ((ins >> 25) & 0x1f));
- ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
- FAIL_IF(!ptr);
- *ptr = ins;
- compiler->size++;
- compiler->delay_slot = delay_slot;
- return SLJIT_SUCCESS;
-}
-
-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_ins *inst;
- sljit_ins saved_inst;
-
- if (jump->flags & SLJIT_REWRITABLE_JUMP)
- return code_ptr;
-
- if (jump->flags & JUMP_ADDR)
- target_addr = jump->u.target;
- else {
- SLJIT_ASSERT(jump->flags & JUMP_LABEL);
- target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
- }
- inst = (sljit_ins*)jump->addr;
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- if (jump->flags & IS_CALL) {
- /* Call is always patchable on sparc 32. */
- jump->flags |= PATCH_CALL;
- if (jump->flags & IS_MOVABLE) {
- inst[0] = inst[-1];
- inst[-1] = CALL;
- jump->addr -= sizeof(sljit_ins);
- return inst;
- }
- inst[0] = CALL;
- inst[1] = NOP;
- return inst + 1;
- }
-#else
- /* Both calls and BPr instructions shall not pass this point. */
-#error "Implementation required"
-#endif
-
- if (jump->flags & IS_COND)
- inst--;
-
- diff = ((sljit_sw)target_addr - (sljit_sw)(inst - 1) - executable_offset) >> 2;
-
- if (jump->flags & IS_MOVABLE) {
- if (diff <= MAX_DISP && diff >= MIN_DISP) {
- jump->flags |= PATCH_B;
- inst--;
- if (jump->flags & IS_COND) {
- saved_inst = inst[0];
- inst[0] = inst[1] ^ (1 << 28);
- inst[1] = saved_inst;
- } else {
- inst[1] = inst[0];
- inst[0] = BICC | DA(0x8);
- }
- jump->addr = (sljit_uw)inst;
- return inst + 1;
- }
- }
-
- diff += SSIZE_OF(ins);
-
- if (diff <= MAX_DISP && diff >= MIN_DISP) {
- jump->flags |= PATCH_B;
- if (jump->flags & IS_COND)
- inst[0] ^= (1 << 28);
- else
- inst[0] = BICC | DA(0x8);
- inst[1] = NOP;
- jump->addr = (sljit_uw)inst;
- return inst + 1;
- }
-
- return code_ptr;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
-{
- struct sljit_memory_fragment *buf;
- sljit_ins *code;
- sljit_ins *code_ptr;
- sljit_ins *buf_ptr;
- sljit_ins *buf_end;
- sljit_uw word_count;
- sljit_uw next_addr;
- sljit_sw executable_offset;
- sljit_sw addr;
-
- struct sljit_label *label;
- struct sljit_jump *jump;
- struct sljit_const *const_;
- struct sljit_put_label *put_label;
-
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_generate_code(compiler));
- reverse_buf(compiler);
-
- code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
- PTR_FAIL_WITH_EXEC_IF(code);
- buf = compiler->buf;
-
- code_ptr = code;
- word_count = 0;
- next_addr = 0;
- executable_offset = SLJIT_EXEC_OFFSET(code);
-
- label = compiler->labels;
- jump = compiler->jumps;
- const_ = compiler->consts;
- put_label = compiler->put_labels;
-
- do {
- buf_ptr = (sljit_ins*)buf->memory;
- buf_end = buf_ptr + (buf->used_size >> 2);
- do {
- *code_ptr = *buf_ptr++;
- if (next_addr == word_count) {
- SLJIT_ASSERT(!label || label->size >= word_count);
- SLJIT_ASSERT(!jump || jump->addr >= word_count);
- SLJIT_ASSERT(!const_ || const_->addr >= word_count);
- SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
-
- /* These structures are ordered by their address. */
- if (label && label->size == word_count) {
- /* Just recording the address. */
- label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
- label->size = (sljit_uw)(code_ptr - code);
- label = label->next;
- }
- if (jump && jump->addr == word_count) {
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- jump->addr = (sljit_uw)(code_ptr - 3);
-#else
- jump->addr = (sljit_uw)(code_ptr - 6);
-#endif
- code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
- jump = jump->next;
- }
- if (const_ && const_->addr == word_count) {
- /* Just recording the address. */
- const_->addr = (sljit_uw)code_ptr;
- const_ = const_->next;
- }
- if (put_label && put_label->addr == word_count) {
- SLJIT_ASSERT(put_label->label);
- put_label->addr = (sljit_uw)code_ptr;
- put_label = put_label->next;
- }
- next_addr = compute_next_addr(label, jump, const_, put_label);
- }
- code_ptr ++;
- word_count ++;
- } while (buf_ptr < buf_end);
-
- buf = buf->next;
- } while (buf);
-
- if (label && label->size == word_count) {
- label->addr = (sljit_uw)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_s32)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_CALL) {
- addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
- SLJIT_ASSERT(addr <= 0x1fffffff && addr >= -0x20000000);
- buf_ptr[0] = CALL | ((sljit_ins)addr & 0x3fffffff);
- break;
- }
- if (jump->flags & PATCH_B) {
- addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
- SLJIT_ASSERT(addr <= MAX_DISP && addr >= MIN_DISP);
- buf_ptr[0] = (buf_ptr[0] & ~DISP_MASK) | ((sljit_ins)addr & DISP_MASK);
- break;
- }
-
- /* Set the fields of immediate loads. */
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- SLJIT_ASSERT(((buf_ptr[0] & 0xc1cfffff) == 0x01000000) && ((buf_ptr[1] & 0xc1f83fff) == 0x80102000));
- buf_ptr[0] |= (sljit_ins)(addr >> 10) & 0x3fffff;
- buf_ptr[1] |= (sljit_ins)addr & 0x3ff;
-#else
-#error "Implementation required"
-#endif
- } while (0);
- 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;
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- SLJIT_ASSERT(((buf_ptr[0] & 0xc1cfffff) == 0x01000000) && ((buf_ptr[1] & 0xc1f83fff) == 0x80102000));
- buf_ptr[0] |= (addr >> 10) & 0x3fffff;
- buf_ptr[1] |= addr & 0x3ff;
-#else
-#error "Implementation required"
-#endif
- put_label = put_label->next;
- }
-
- compiler->error = SLJIT_ERR_COMPILED;
- compiler->executable_offset = executable_offset;
- compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
-
- code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
- code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
-
- SLJIT_CACHE_FLUSH(code, code_ptr);
- SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
- return code;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
-{
- switch (feature_type) {
- case SLJIT_HAS_FPU:
-#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
-#else
- /* Available by default. */
- return 1;
-#endif
-
- case SLJIT_HAS_ZERO_REGISTER:
- return 1;
-
-#if (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
- case SLJIT_HAS_CMOV:
- return 1;
-#endif
-
- default:
- return 0;
- }
-}
-
-/* --------------------------------------------------------------------- */
-/* Entry, exit */
-/* --------------------------------------------------------------------- */
-
-/* Creates an index in data_transfer_insts array. */
-#define LOAD_DATA 0x01
-#define WORD_DATA 0x00
-#define BYTE_DATA 0x02
-#define HALF_DATA 0x04
-#define INT_DATA 0x06
-#define SIGNED_DATA 0x08
-/* Separates integer and floating point registers */
-#define GPR_REG 0x0f
-#define DOUBLE_DATA 0x10
-#define SINGLE_DATA 0x12
-
-#define MEM_MASK 0x1f
-
-#define ARG_TEST 0x00020
-#define ALT_KEEP_CACHE 0x00040
-#define CUMULATIVE_OP 0x00080
-#define IMM_OP 0x00100
-#define MOVE_OP 0x00200
-#define SRC2_IMM 0x00400
-
-#define REG_DEST 0x00800
-#define REG2_SOURCE 0x01000
-#define SLOW_SRC1 0x02000
-#define SLOW_SRC2 0x04000
-#define SLOW_DEST 0x08000
-
-/* SET_FLAGS (0x10 << 19) also belong here! */
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
-#include "sljitNativeSPARC_32.c"
-#else
-#include "sljitNativeSPARC_64.c"
-#endif
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
- sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
-{
- sljit_s32 reg_index, types, tmp;
- sljit_u32 float_offset, args_offset;
- sljit_s32 saved_arg_index, scratch_arg_index, float_arg_index;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
- set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
-
- local_size = (local_size + SLJIT_LOCALS_OFFSET + 7) & ~0x7;
- compiler->local_size = local_size;
-
- if (local_size <= -SIMM_MIN) {
- FAIL_IF(push_inst(compiler, SAVE | D(SLJIT_SP) | S1(SLJIT_SP) | IMM(-local_size), UNMOVABLE_INS));
- }
- else {
- FAIL_IF(load_immediate(compiler, TMP_REG1, -local_size));
- FAIL_IF(push_inst(compiler, SAVE | D(SLJIT_SP) | S1(SLJIT_SP) | S2(TMP_REG1), UNMOVABLE_INS));
- }
-
- arg_types >>= SLJIT_ARG_SHIFT;
-
- types = arg_types;
- float_offset = 16 * sizeof(sljit_sw);
- reg_index = 24;
-
- while (types && reg_index < 24 + 6) {
- switch (types & SLJIT_ARG_MASK) {
- case SLJIT_ARG_TYPE_F64:
- if (reg_index & 0x1) {
- FAIL_IF(push_inst(compiler, STW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- if (reg_index >= 24 + 6 - 1)
- break;
- FAIL_IF(push_inst(compiler, STW | DA(reg_index + 1) | S1(SLJIT_SP) | IMM(float_offset + sizeof(sljit_sw)), MOVABLE_INS));
- } else
- FAIL_IF(push_inst(compiler, STD | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
-
- float_offset += sizeof(sljit_f64);
- reg_index++;
- break;
- case SLJIT_ARG_TYPE_F32:
- FAIL_IF(push_inst(compiler, STW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- float_offset += sizeof(sljit_f64);
- break;
- }
-
- reg_index++;
- types >>= SLJIT_ARG_SHIFT;
- }
-
- args_offset = (16 + 1 + 6) * sizeof(sljit_sw);
- float_offset = 16 * sizeof(sljit_sw);
- reg_index = 24;
- saved_arg_index = 24;
- scratch_arg_index = 8 - 1;
- float_arg_index = 1;
-
- while (arg_types) {
- switch (arg_types & SLJIT_ARG_MASK) {
- case SLJIT_ARG_TYPE_F64:
- if (reg_index < 24 + 6 - 1) {
- FAIL_IF(push_inst(compiler, LDDF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- } else if (reg_index < 24 + 6) {
- FAIL_IF(push_inst(compiler, LDF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- FAIL_IF(push_inst(compiler, LDF | FD(float_arg_index) | (1 << 25) | S1A(30) | IMM(args_offset), MOVABLE_INS));
- } else {
- FAIL_IF(push_inst(compiler, LDF | FD(float_arg_index) | S1A(30) | IMM(args_offset), MOVABLE_INS));
- FAIL_IF(push_inst(compiler, LDF | FD(float_arg_index) | (1 << 25) | S1A(30) | IMM(args_offset + sizeof(sljit_sw)), MOVABLE_INS));
- }
-
- float_arg_index++;
- float_offset += sizeof(sljit_f64);
- reg_index++;
- break;
- case SLJIT_ARG_TYPE_F32:
- if (reg_index < 24 + 6)
- FAIL_IF(push_inst(compiler, LDF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
- else
- FAIL_IF(push_inst(compiler, LDF | FD(float_arg_index) | S1A(30) | IMM(args_offset), MOVABLE_INS));
- float_arg_index++;
- float_offset += sizeof(sljit_f64);
- break;
- default:
- scratch_arg_index++;
-
- if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {
- tmp = saved_arg_index++;
- if (tmp == reg_index)
- break;
- } else
- tmp = scratch_arg_index;
-
- if (reg_index < 24 + 6)
- FAIL_IF(push_inst(compiler, OR | DA(tmp) | S1(0) | S2A(reg_index), tmp));
- else
- FAIL_IF(push_inst(compiler, LDUW | DA(tmp) | S1A(30) | IMM(args_offset), tmp));
- break;
- }
-
- reg_index++;
- arg_types >>= SLJIT_ARG_SHIFT;
- }
-
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
- sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
- sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
-{
- CHECK_ERROR();
- CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
- set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
-
- compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 7) & ~0x7;
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_return_void(compiler));
-
- FAIL_IF(push_inst(compiler, JMPL | D(0) | S1A(31) | IMM(8), UNMOVABLE_INS));
- return push_inst(compiler, RESTORE | D(SLJIT_R0) | S1(SLJIT_R0) | S2(0), UNMOVABLE_INS);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_return(compiler, op, src, srcw));
-
- if (TYPE_CAST_NEEDED(op) || !FAST_IS_REG(src)) {
- FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
- src = SLJIT_R0;
- }
-
- FAIL_IF(push_inst(compiler, JMPL | D(0) | S1A(31) | IMM(8), UNMOVABLE_INS));
- return push_inst(compiler, RESTORE | D(SLJIT_R0) | S1(src) | S2(0), UNMOVABLE_INS);
-}
-
-/* --------------------------------------------------------------------- */
-/* Operators */
-/* --------------------------------------------------------------------- */
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
-#define ARCH_32_64(a, b) a
-#else
-#define ARCH_32_64(a, b) b
-#endif
-
-static const sljit_ins data_transfer_insts[16 + 4] = {
-/* u w s */ ARCH_32_64(OPC1(3) | OPC3(0x04) /* stw */, OPC1(3) | OPC3(0x0e) /* stx */),
-/* u w l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x0b) /* ldx */),
-/* u b s */ OPC1(3) | OPC3(0x05) /* stb */,
-/* u b l */ OPC1(3) | OPC3(0x01) /* ldub */,
-/* u h s */ OPC1(3) | OPC3(0x06) /* sth */,
-/* u h l */ OPC1(3) | OPC3(0x02) /* lduh */,
-/* u i s */ OPC1(3) | OPC3(0x04) /* stw */,
-/* u i l */ OPC1(3) | OPC3(0x00) /* lduw */,
-
-/* s w s */ ARCH_32_64(OPC1(3) | OPC3(0x04) /* stw */, OPC1(3) | OPC3(0x0e) /* stx */),
-/* s w l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x0b) /* ldx */),
-/* s b s */ OPC1(3) | OPC3(0x05) /* stb */,
-/* s b l */ OPC1(3) | OPC3(0x09) /* ldsb */,
-/* s h s */ OPC1(3) | OPC3(0x06) /* sth */,
-/* s h l */ OPC1(3) | OPC3(0x0a) /* ldsh */,
-/* s i s */ OPC1(3) | OPC3(0x04) /* stw */,
-/* s i l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x08) /* ldsw */),
-
-/* d s */ OPC1(3) | OPC3(0x27),
-/* d l */ OPC1(3) | OPC3(0x23),
-/* s s */ OPC1(3) | OPC3(0x24),
-/* s l */ OPC1(3) | OPC3(0x20),
-};
-
-#undef ARCH_32_64
-
-/* Can perform an operation using at most 1 instruction. */
-static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_u32 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)
- || ((arg & OFFS_REG_MASK) && (argw & 0x3) == 0)) {
- /* Works for both absoulte and relative addresses (immediate case). */
- if (SLJIT_UNLIKELY(flags & ARG_TEST))
- return 1;
- FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK]
- | ((flags & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg))
- | S1(arg & REG_MASK) | ((arg & OFFS_REG_MASK) ? S2(OFFS_REG(arg)) : IMM(argw)),
- ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? DR(reg) : MOVABLE_INS));
- return -1;
- }
- return 0;
-}
-
-/* See getput_arg below.
- Note: can_cache is called only for binary operators. Those
- operators always uses word arguments without write back. */
-static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
-{
- SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
-
- /* Simple operation except for updates. */
- if (arg & OFFS_REG_MASK) {
- argw &= 0x3;
- SLJIT_ASSERT(argw);
- next_argw &= 0x3;
- if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == next_argw)
- return 1;
- return 0;
- }
-
- if (((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN))
- return 1;
- return 0;
-}
-
-/* Emit the necessary instructions. See can_cache above. */
-static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_u32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
-{
- sljit_s32 base, arg2, delay_slot;
- sljit_ins dest;
-
- SLJIT_ASSERT(arg & SLJIT_MEM);
- if (!(next_arg & SLJIT_MEM)) {
- next_arg = 0;
- next_argw = 0;
- }
-
- base = arg & REG_MASK;
- if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
- argw &= 0x3;
-
- /* Using the cache. */
- if (((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) && (argw == compiler->cache_argw))
- arg2 = TMP_REG3;
- else {
- if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == (next_argw & 0x3)) {
- compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
- compiler->cache_argw = argw;
- arg2 = TMP_REG3;
- }
- else if ((flags & LOAD_DATA) && ((flags & MEM_MASK) <= GPR_REG) && reg != base && reg != OFFS_REG(arg))
- arg2 = reg;
- else /* It must be a mov operation, so tmp1 must be free to use. */
- arg2 = TMP_REG1;
- FAIL_IF(push_inst(compiler, SLL_W | D(arg2) | S1(OFFS_REG(arg)) | IMM_ARG | (sljit_ins)argw, DR(arg2)));
- }
- }
- else {
- /* Using the cache. */
- if ((compiler->cache_arg == SLJIT_MEM) && (argw - compiler->cache_argw) <= SIMM_MAX && (argw - compiler->cache_argw) >= SIMM_MIN) {
- if (argw != compiler->cache_argw) {
- FAIL_IF(push_inst(compiler, ADD | D(TMP_REG3) | S1(TMP_REG3) | IMM(argw - compiler->cache_argw), DR(TMP_REG3)));
- compiler->cache_argw = argw;
- }
- arg2 = TMP_REG3;
- } else {
- if ((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN) {
- compiler->cache_arg = SLJIT_MEM;
- compiler->cache_argw = argw;
- arg2 = TMP_REG3;
- }
- else if ((flags & LOAD_DATA) && ((flags & MEM_MASK) <= GPR_REG) && reg != base)
- arg2 = reg;
- else /* It must be a mov operation, so tmp1 must be free to use. */
- arg2 = TMP_REG1;
- FAIL_IF(load_immediate(compiler, arg2, argw));
- }
- }
-
- dest = ((flags & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg));
- delay_slot = ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? DR(reg) : MOVABLE_INS;
- if (!base)
- return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | dest | S1(arg2) | IMM(0), delay_slot);
- return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | dest | S1(base) | S2(arg2), delay_slot);
-}
-
-static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_u32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
-{
- if (getput_arg_fast(compiler, flags, reg, arg, argw))
- return compiler->error;
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
-}
-
-static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_u32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
-{
- if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
- return compiler->error;
- return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
-}
-
-static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_u32 flags,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- /* arg1 goes to TMP_REG1 or src reg
- arg2 goes to TMP_REG2, imm or src reg
- TMP_REG3 can be used for caching
- result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
- sljit_s32 dst_r = TMP_REG2;
- sljit_s32 src1_r;
- sljit_sw src2_r = 0;
- sljit_s32 sugg_src2_r = TMP_REG2;
-
- if (!(flags & ALT_KEEP_CACHE)) {
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
- }
-
- if (dst != TMP_REG2) {
- if (FAST_IS_REG(dst)) {
- dst_r = dst;
- flags |= REG_DEST;
- if (flags & MOVE_OP)
- sugg_src2_r = dst_r;
- }
- else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
- flags |= SLOW_DEST;
- }
-
- if (flags & IMM_OP) {
- if ((src2 & SLJIT_IMM) && src2w) {
- if (src2w <= SIMM_MAX && src2w >= SIMM_MIN) {
- flags |= SRC2_IMM;
- src2_r = src2w;
- }
- }
- if (!(flags & SRC2_IMM) && (flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w) {
- if (src1w <= SIMM_MAX && src1w >= SIMM_MIN) {
- flags |= SRC2_IMM;
- src2_r = src1w;
-
- /* And swap arguments. */
- src1 = src2;
- src1w = src2w;
- src2 = SLJIT_IMM;
- /* src2w = src2_r unneeded. */
- }
- }
- }
-
- /* Source 1. */
- if (FAST_IS_REG(src1))
- src1_r = src1;
- else if (src1 & SLJIT_IMM) {
- if (src1w) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
- src1_r = TMP_REG1;
- }
- else
- src1_r = 0;
- }
- else {
- if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w))
- FAIL_IF(compiler->error);
- else
- flags |= SLOW_SRC1;
- src1_r = TMP_REG1;
- }
-
- /* Source 2. */
- if (FAST_IS_REG(src2)) {
- src2_r = src2;
- flags |= REG2_SOURCE;
- if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP)
- dst_r = src2_r;
- }
- else if (src2 & SLJIT_IMM) {
- if (!(flags & SRC2_IMM)) {
- if (src2w) {
- FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
- src2_r = sugg_src2_r;
- }
- else {
- src2_r = 0;
- if (flags & MOVE_OP) {
- if (dst & SLJIT_MEM)
- dst_r = 0;
- else
- op = SLJIT_MOV;
- }
- }
- }
- }
- else {
- if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w))
- FAIL_IF(compiler->error);
- else
- flags |= SLOW_SRC2;
- src2_r = sugg_src2_r;
- }
-
- if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
- SLJIT_ASSERT(src2_r == TMP_REG2);
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w));
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
- }
- else {
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
- }
- }
- else if (flags & SLOW_SRC1)
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
- else if (flags & SLOW_SRC2)
- FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
-
- FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
-
- if (dst & SLJIT_MEM) {
- if (!(flags & SLOW_DEST)) {
- getput_arg_fast(compiler, flags, dst_r, dst, dstw);
- return compiler->error;
- }
- return getput_arg(compiler, flags, dst_r, dst, dstw, 0, 0);
- }
-
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_op0(compiler, op));
-
- op = GET_OPCODE(op);
- switch (op) {
- case SLJIT_BREAKPOINT:
- return push_inst(compiler, TA, UNMOVABLE_INS);
- case SLJIT_NOP:
- return push_inst(compiler, NOP, UNMOVABLE_INS);
- case SLJIT_LMUL_UW:
- case SLJIT_LMUL_SW:
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? UMUL : SMUL) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
- return push_inst(compiler, RDY | D(SLJIT_R1), DR(SLJIT_R1));
-#else
-#error "Implementation required"
-#endif
- case SLJIT_DIVMOD_UW:
- case SLJIT_DIVMOD_SW:
- case SLJIT_DIV_UW:
- case SLJIT_DIV_SW:
- SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- if ((op | 0x2) == SLJIT_DIV_UW)
- FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS));
- else {
- FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_R0) | IMM(31), DR(TMP_REG1)));
- FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS));
- }
- if (op <= SLJIT_DIVMOD_SW)
- FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
- if (op >= SLJIT_DIV_UW)
- return SLJIT_SUCCESS;
- FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_R1) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R1)));
- return push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1));
-#else
-#error "Implementation required"
-#endif
- case SLJIT_ENDBR:
- case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
- return SLJIT_SUCCESS;
- }
-
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
-{
- sljit_u32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
- ADJUST_LOCAL_OFFSET(src, srcw);
-
- op = GET_OPCODE(op);
- switch (op) {
- case SLJIT_MOV:
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- case SLJIT_MOV_U32:
- case SLJIT_MOV_S32:
- case SLJIT_MOV32:
-#endif
- case SLJIT_MOV_P:
- return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, srcw);
-
- case SLJIT_MOV_U8:
- return emit_op(compiler, SLJIT_MOV_U8, flags | BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
-
- case SLJIT_MOV_S8:
- return emit_op(compiler, SLJIT_MOV_S8, flags | BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
-
- case SLJIT_MOV_U16:
- return emit_op(compiler, SLJIT_MOV_U16, flags | HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
-
- case SLJIT_MOV_S16:
- return emit_op(compiler, SLJIT_MOV_S16, flags | HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
-
- case SLJIT_NOT:
- case SLJIT_CLZ:
- return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
- }
-
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- sljit_u32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));
- ADJUST_LOCAL_OFFSET(dst, dstw);
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
-
- op = GET_OPCODE(op);
- switch (op) {
- case SLJIT_ADD:
- case SLJIT_ADDC:
- case SLJIT_MUL:
- case SLJIT_AND:
- case SLJIT_OR:
- case SLJIT_XOR:
- return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
-
- case SLJIT_SUB:
- case SLJIT_SUBC:
- return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
-
- case SLJIT_SHL:
- case SLJIT_LSHR:
- case SLJIT_ASHR:
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- if (src2 & SLJIT_IMM)
- src2w &= 0x1f;
-#else
- SLJIT_UNREACHABLE();
-#endif
- return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
- }
-
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
-
-#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
- || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- compiler->skip_checks = 1;
-#endif
- return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src, sljit_sw srcw)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
- ADJUST_LOCAL_OFFSET(src, srcw);
-
- switch (op) {
- case SLJIT_FAST_RETURN:
- if (FAST_IS_REG(src))
- FAIL_IF(push_inst(compiler, OR | D(TMP_LINK) | S1(0) | S2(src), DR(TMP_LINK)));
- else
- FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_LINK, src, srcw));
-
- FAIL_IF(push_inst(compiler, JMPL | D(0) | S1(TMP_LINK) | IMM(8), UNMOVABLE_INS));
- return push_inst(compiler, NOP, UNMOVABLE_INS);
- case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
- case SLJIT_PREFETCH_L1:
- case SLJIT_PREFETCH_L2:
- case SLJIT_PREFETCH_L3:
- case SLJIT_PREFETCH_ONCE:
- return SLJIT_SUCCESS;
- }
-
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
-{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
-{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
- return freg_map[reg];
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_u32 size)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
-
- return push_inst(compiler, *(sljit_ins*)instruction, UNMOVABLE_INS);
-}
-
-/* --------------------------------------------------------------------- */
-/* Floating point operators */
-/* --------------------------------------------------------------------- */
-
-#define FLOAT_DATA(op) ((sljit_ins)DOUBLE_DATA | (((sljit_ins)(op) & SLJIT_32) >> 7))
-#define SELECT_FOP(op, single, double) ((op & SLJIT_32) ? single : double)
-#define FLOAT_TMP_MEM_OFFSET (22 * sizeof(sljit_sw))
-
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
-{
- if (src & SLJIT_MEM) {
- FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
- src = TMP_FREG1;
- }
-
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSTOI, FDTOI) | FD(TMP_FREG1) | FS2(src), MOVABLE_INS));
-
- if (FAST_IS_REG(dst)) {
- FAIL_IF(emit_op_mem2(compiler, SINGLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
- return emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET);
- }
-
- /* Store the integer value from a VFP register. */
- return emit_op_mem2(compiler, SINGLE_DATA, TMP_FREG1, dst, dstw, 0, 0);
-}
-
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
-{
- sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
-
- if (src & SLJIT_IMM) {
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
- srcw = (sljit_s32)srcw;
-#endif
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
- src = TMP_REG1;
- srcw = 0;
- }
-
- if (FAST_IS_REG(src)) {
- FAIL_IF(emit_op_mem2(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
- src = SLJIT_MEM1(SLJIT_SP);
- srcw = FLOAT_TMP_MEM_OFFSET;
- }
-
- FAIL_IF(emit_op_mem2(compiler, SINGLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FITOS, FITOD) | FD(dst_r) | FS2(TMP_FREG1), MOVABLE_INS));
-
- if (dst & SLJIT_MEM)
- return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
- return SLJIT_SUCCESS;
-}
-
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
- src1 = TMP_FREG1;
- }
-
- if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0));
- src2 = TMP_FREG2;
- }
-
- return push_inst(compiler, SELECT_FOP(op, FCMPS, FCMPD) | FS1(src1) | FS2(src2), FCC_IS_SET | MOVABLE_INS);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
-{
- sljit_s32 dst_r;
-
- CHECK_ERROR();
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
-
- SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
- SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
-
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
- op ^= SLJIT_32;
-
- dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
-
- if (src & SLJIT_MEM) {
- FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, dst, dstw));
- src = dst_r;
- }
-
- switch (GET_OPCODE(op)) {
- case SLJIT_MOV_F64:
- if (src != dst_r) {
- if (dst_r != TMP_FREG1) {
- FAIL_IF(push_inst(compiler, FMOVS | FD(dst_r) | FS2(src), MOVABLE_INS));
- if (!(op & SLJIT_32))
- FAIL_IF(push_inst(compiler, FMOVS | FDN(dst_r) | FS2N(src), MOVABLE_INS));
- }
- else
- dst_r = src;
- }
- break;
- case SLJIT_NEG_F64:
- FAIL_IF(push_inst(compiler, FNEGS | FD(dst_r) | FS2(src), MOVABLE_INS));
- if (dst_r != src && !(op & SLJIT_32))
- FAIL_IF(push_inst(compiler, FMOVS | FDN(dst_r) | FS2N(src), MOVABLE_INS));
- break;
- case SLJIT_ABS_F64:
- FAIL_IF(push_inst(compiler, FABSS | FD(dst_r) | FS2(src), MOVABLE_INS));
- if (dst_r != src && !(op & SLJIT_32))
- FAIL_IF(push_inst(compiler, FMOVS | FDN(dst_r) | FS2N(src), MOVABLE_INS));
- break;
- case SLJIT_CONV_F64_FROM_F32:
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSTOD, FDTOS) | FD(dst_r) | FS2(src), MOVABLE_INS));
- op ^= SLJIT_32;
- break;
- }
-
- if (dst & SLJIT_MEM)
- FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), dst_r, dst, dstw, 0, 0));
- return SLJIT_SUCCESS;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- sljit_s32 dst_r, flags = 0;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
- ADJUST_LOCAL_OFFSET(dst, dstw);
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
-
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
-
- dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
-
- if (src1 & SLJIT_MEM) {
- if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) {
- FAIL_IF(compiler->error);
- src1 = TMP_FREG1;
- } else
- flags |= SLOW_SRC1;
- }
-
- if (src2 & SLJIT_MEM) {
- if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) {
- FAIL_IF(compiler->error);
- src2 = TMP_FREG2;
- } else
- flags |= SLOW_SRC2;
- }
-
- if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
- if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
- FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w));
- FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
- }
- else {
- FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
- FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
- }
- }
- else if (flags & SLOW_SRC1)
- FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
- else if (flags & SLOW_SRC2)
- FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
-
- if (flags & SLOW_SRC1)
- src1 = TMP_FREG1;
- if (flags & SLOW_SRC2)
- src2 = TMP_FREG2;
-
- switch (GET_OPCODE(op)) {
- case SLJIT_ADD_F64:
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADDD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
- break;
-
- case SLJIT_SUB_F64:
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUBD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
- break;
-
- case SLJIT_MUL_F64:
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMULD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
- break;
-
- case SLJIT_DIV_F64:
- FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIVD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
- break;
- }
-
- if (dst_r == TMP_FREG2)
- FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
-
- return SLJIT_SUCCESS;
-}
-
-#undef FLOAT_DATA
-#undef SELECT_FOP
-
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
-
- if (FAST_IS_REG(dst))
- return push_inst(compiler, OR | D(dst) | S1(0) | S2(TMP_LINK), UNMOVABLE_INS);
-
- /* Memory. */
- FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_LINK, dst, dstw));
- compiler->delay_slot = UNMOVABLE_INS;
- return SLJIT_SUCCESS;
-}
-
-/* --------------------------------------------------------------------- */
-/* Conditional instructions */
-/* --------------------------------------------------------------------- */
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
-{
- struct sljit_label *label;
-
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_label(compiler));
-
- if (compiler->last_label && compiler->last_label->size == compiler->size)
- return compiler->last_label;
-
- label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
- PTR_FAIL_IF(!label);
- set_label(label, compiler);
- compiler->delay_slot = UNMOVABLE_INS;
- return label;
-}
-
-static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
-{
- switch (type) {
- case SLJIT_EQUAL:
- case SLJIT_NOT_EQUAL_F64: /* Unordered. */
- return DA(0x1);
-
- case SLJIT_NOT_EQUAL:
- case SLJIT_EQUAL_F64:
- return DA(0x9);
-
- case SLJIT_LESS:
- case SLJIT_GREATER_F64: /* Unordered. */
- case SLJIT_CARRY:
- return DA(0x5);
-
- case SLJIT_GREATER_EQUAL:
- case SLJIT_LESS_EQUAL_F64:
- case SLJIT_NOT_CARRY:
- return DA(0xd);
-
- case SLJIT_GREATER:
- case SLJIT_GREATER_EQUAL_F64: /* Unordered. */
- return DA(0xc);
-
- case SLJIT_LESS_EQUAL:
- case SLJIT_LESS_F64:
- return DA(0x4);
-
- case SLJIT_SIG_LESS:
- return DA(0x3);
-
- case SLJIT_SIG_GREATER_EQUAL:
- return DA(0xb);
-
- case SLJIT_SIG_GREATER:
- return DA(0xa);
-
- case SLJIT_SIG_LESS_EQUAL:
- return DA(0x2);
-
- case SLJIT_OVERFLOW:
- if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
- return DA(0x9);
- /* fallthrough */
-
- case SLJIT_UNORDERED_F64:
- return DA(0x7);
-
- case SLJIT_NOT_OVERFLOW:
- if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
- return DA(0x1);
- /* fallthrough */
-
- case SLJIT_ORDERED_F64:
- return DA(0xf);
-
- default:
- SLJIT_UNREACHABLE();
- return DA(0x8);
- }
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
-{
- struct sljit_jump *jump;
-
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_jump(compiler, type));
-
- jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
- PTR_FAIL_IF(!jump);
- set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
- type &= 0xff;
-
- if (type < SLJIT_EQUAL_F64) {
- jump->flags |= IS_COND;
- if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & ICC_IS_SET))
- jump->flags |= IS_MOVABLE;
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- PTR_FAIL_IF(push_inst(compiler, BICC | get_cc(compiler, type ^ 1) | 5, UNMOVABLE_INS));
-#else
-#error "Implementation required"
-#endif
- }
- else if (type < SLJIT_JUMP) {
- jump->flags |= IS_COND;
- if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & FCC_IS_SET))
- jump->flags |= IS_MOVABLE;
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- PTR_FAIL_IF(push_inst(compiler, FBFCC | get_cc(compiler, type ^ 1) | 5, UNMOVABLE_INS));
-#else
-#error "Implementation required"
-#endif
- }
- else {
- if ((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS)
- jump->flags |= IS_MOVABLE;
- if (type >= SLJIT_FAST_CALL)
- jump->flags |= IS_CALL;
- }
-
- PTR_FAIL_IF(emit_const(compiler, TMP_REG1, 0));
- PTR_FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? TMP_LINK : 0) | S1(TMP_REG1) | IMM(0), UNMOVABLE_INS));
- jump->addr = compiler->size;
- PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-
- return jump;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 arg_types)
-{
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
-
- PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL));
-
-#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
- || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- compiler->skip_checks = 1;
-#endif
-
- return sljit_emit_jump(compiler, type);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
-{
- struct sljit_jump *jump = NULL;
- sljit_s32 src_r;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- ADJUST_LOCAL_OFFSET(src, srcw);
-
- if (FAST_IS_REG(src))
- src_r = src;
- else if (src & SLJIT_IMM) {
- jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
- FAIL_IF(!jump);
- set_jump(jump, compiler, JUMP_ADDR);
- jump->u.target = (sljit_uw)srcw;
-
- if ((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS)
- jump->flags |= IS_MOVABLE;
- if (type >= SLJIT_FAST_CALL)
- jump->flags |= IS_CALL;
-
- FAIL_IF(emit_const(compiler, TMP_REG1, 0));
- src_r = TMP_REG1;
- }
- else {
- FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
- src_r = TMP_REG1;
- }
-
- FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? TMP_LINK : 0) | S1(src_r) | IMM(0), UNMOVABLE_INS));
- if (jump)
- jump->addr = compiler->size;
- return push_inst(compiler, NOP, UNMOVABLE_INS);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 arg_types,
- sljit_s32 src, sljit_sw srcw)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
-
- if (src & SLJIT_MEM) {
- ADJUST_LOCAL_OFFSET(src, srcw);
- FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
- src = TMP_REG1;
- }
-
- FAIL_IF(call_with_args(compiler, arg_types, &src));
-
-#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
- || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- compiler->skip_checks = 1;
-#endif
-
- return sljit_emit_ijump(compiler, type, src, srcw);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 type)
-{
- sljit_s32 reg;
- sljit_u32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
- ADJUST_LOCAL_OFFSET(dst, dstw);
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- op = GET_OPCODE(op);
- reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
-
- compiler->cache_arg = 0;
- compiler->cache_argw = 0;
-
- if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
- FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
-
- type &= 0xff;
- if (type < SLJIT_EQUAL_F64)
- FAIL_IF(push_inst(compiler, BICC | get_cc(compiler, type) | 3, UNMOVABLE_INS));
- else
- FAIL_IF(push_inst(compiler, FBFCC | get_cc(compiler, type) | 3, UNMOVABLE_INS));
-
- FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(1), UNMOVABLE_INS));
- FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS));
-
- if (op >= SLJIT_ADD) {
- flags |= CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE;
- if (dst & SLJIT_MEM)
- return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
- return emit_op(compiler, op, flags, dst, 0, dst, 0, TMP_REG2, 0);
- }
-
- if (!(dst & SLJIT_MEM))
- return SLJIT_SUCCESS;
-
- return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
-#else
-#error "Implementation required"
-#endif
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
-{
- CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
-
-#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
-#else
-#error "Implementation required"
-#endif
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
-{
- struct sljit_const *const_;
- sljit_s32 dst_r;
-
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
- ADJUST_LOCAL_OFFSET(dst, dstw);
-
- const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
- PTR_FAIL_IF(!const_);
- set_const(const_, compiler);
-
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
- PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
-
- if (dst & SLJIT_MEM)
- PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
- return const_;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
-{
- struct sljit_put_label *put_label;
- sljit_s32 dst_r;
-
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
-
- put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
- PTR_FAIL_IF(!put_label);
- set_put_label(put_label, compiler, 0);
-
- dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
- PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
-
- if (dst & SLJIT_MEM)
- PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
- return put_label;
-}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
index ba4a1ebbc2..59ea04a5c8 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
@@ -283,28 +283,25 @@ static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw
/* 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;
@@ -1249,6 +1246,68 @@ static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler,
/* 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)
@@ -1449,10 +1508,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *comp
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;
@@ -1462,7 +1521,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp
sljit_s32 freg, sljit_f64 value)
{
sljit_u8 *inst;
- sljit_s32 tmp_freg = freg;
union {
sljit_s32 imm[2];
sljit_f64 value;
@@ -1478,8 +1536,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp
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));
@@ -1493,23 +1561,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp
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);
@@ -1518,7 +1580,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp
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;
}
@@ -1581,7 +1643,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compi
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));
@@ -1597,7 +1659,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compi
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));
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
index f313f3f038..1ab79293c7 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
@@ -358,26 +358,28 @@ static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw
/* 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);
@@ -386,60 +388,62 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_
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;
}
@@ -1003,6 +1007,46 @@ static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler,
/* 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)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
index c2c0421349..ecb7e9be3b 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
@@ -24,12 +24,6 @@
* 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;
@@ -72,7 +66,6 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
#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
};
@@ -379,6 +372,11 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
#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. */
@@ -392,6 +390,7 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
#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;
@@ -490,22 +489,50 @@ static void execute_cpu_id(sljit_u32 info[4])
}
#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];
@@ -526,6 +553,8 @@ static void get_cpu_features(void)
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)
@@ -537,12 +566,14 @@ static void get_cpu_features(void)
}
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;
}
@@ -617,52 +648,47 @@ static sljit_u8 get_jump_code(sljit_uw type)
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
-static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_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);
@@ -674,7 +700,172 @@ static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code
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;
@@ -683,77 +874,82 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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);
@@ -761,61 +957,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
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);
@@ -921,8 +1070,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
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); \
} \
@@ -2248,10 +2397,9 @@ static sljit_s32 emit_test_binary(struct sljit_compiler *compiler,
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;
}
@@ -2488,8 +2636,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
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)) {
@@ -2583,12 +2729,44 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
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,
@@ -3117,19 +3295,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
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));
}
@@ -3152,7 +3328,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
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;
}
@@ -3215,10 +3391,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
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;
}
@@ -3236,18 +3411,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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;
}
@@ -3268,20 +3438,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
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;
@@ -3414,82 +3578,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
#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,
@@ -3581,7 +3669,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *co
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);
@@ -3593,9 +3681,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
{
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));
@@ -3616,20 +3705,55 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
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 */
@@ -3637,51 +3761,40 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
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);
@@ -3706,8 +3819,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
#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);
}
@@ -3721,16 +3834,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
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:
@@ -3747,44 +3861,66 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
#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 */
}
@@ -3796,9 +3932,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
{
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;
@@ -3814,6 +3951,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
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;
@@ -3865,20 +4003,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
}
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);
}
}
@@ -3886,18 +4027,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
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));
@@ -3910,58 +4054,80 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
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;
@@ -3993,7 +4159,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
srcdstw = 0;
}
- size = 3;
+ op = 3;
switch (elem_size) {
case 0:
@@ -4001,7 +4167,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
break;
case 1:
if (!(type & SLJIT_SIMD_STORE)) {
- size = 2;
+ op = 2;
opcode = PINSRW_x_rm_i8;
} else
opcode = PEXTRW_rm_x_i8;
@@ -4018,15 +4184,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
#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)));
@@ -4056,23 +4227,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile
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
@@ -4096,6 +4267,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
{
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)
@@ -4115,6 +4287,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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;
@@ -4136,8 +4309,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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;
@@ -4163,7 +4339,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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)
@@ -4192,7 +4368,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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) {
@@ -4202,7 +4378,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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));
@@ -4214,14 +4390,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
}
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);
@@ -4229,7 +4408,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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;
@@ -4291,11 +4470,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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;
@@ -4310,7 +4492,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
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)));
}
@@ -4321,6 +4506,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler
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();
@@ -4335,6 +4521,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler
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;
@@ -4345,9 +4532,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler
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) {
@@ -4382,9 +4569,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler
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,
@@ -4393,8 +4580,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c
{
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();
@@ -4414,20 +4602,28 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c
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;
@@ -4459,14 +4655,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c
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) {
@@ -4497,7 +4693,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *co
{
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();
@@ -4540,20 +4735,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *co
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));
@@ -4727,11 +4920,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
@@ -4742,52 +4934,48 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
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)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitProtExecAllocator.c b/src/3rdparty/pcre2/src/sljit/sljitProtExecAllocator.c
deleted file mode 100644
index 915411fbed..0000000000
--- a/src/3rdparty/pcre2/src/sljit/sljitProtExecAllocator.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * 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.
- */
-
-/*
- This file contains a simple executable memory allocator
-
- It is assumed, that executable code blocks are usually medium (or sometimes
- large) memory blocks, and the allocator is not too frequently called (less
- optimized than other allocators). Thus, using it as a generic allocator is
- not suggested.
-
- How does it work:
- Memory is allocated in continuous memory areas called chunks by alloc_chunk()
- Chunk format:
- [ block ][ block ] ... [ block ][ block terminator ]
-
- All blocks and the block terminator is started with block_header. The block
- header contains the size of the previous and the next block. These sizes
- can also contain special values.
- Block size:
- 0 - The block is a free_block, with a different size member.
- 1 - The block is a block terminator.
- n - The block is used at the moment, and the value contains its size.
- Previous block size:
- 0 - This is the first block of the memory chunk.
- n - The size of the previous block.
-
- Using these size values we can go forward or backward on the block chain.
- The unused blocks are stored in a chain list pointed by free_blocks. This
- list is useful if we need to find a suitable memory area when the allocator
- is called.
-
- When a block is freed, the new free block is connected to its adjacent free
- blocks if possible.
-
- [ free block ][ used block ][ free block ]
- and "used block" is freed, the three blocks are connected together:
- [ one big free block ]
-*/
-
-/* --------------------------------------------------------------------- */
-/* System (OS) functions */
-/* --------------------------------------------------------------------- */
-
-/* 64 KByte. */
-#define CHUNK_SIZE (sljit_uw)0x10000
-
-struct chunk_header {
- void *executable;
-};
-
-/*
- alloc_chunk / free_chunk :
- * allocate executable system memory chunks
- * the size is always divisible by CHUNK_SIZE
- SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
- * provided as part of sljitUtils
- * only the allocator requires this lock, sljit is fully thread safe
- as it only uses local variables
-*/
-
-#ifndef __NetBSD__
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifndef O_NOATIME
-#define O_NOATIME 0
-#endif
-
-/* this is a linux extension available since kernel 3.11 */
-#ifndef O_TMPFILE
-#define O_TMPFILE 020200000
-#endif
-
-#ifndef _GNU_SOURCE
-char *secure_getenv(const char *name);
-int mkostemp(char *template, int flags);
-#endif
-
-static SLJIT_INLINE int create_tempfile(void)
-{
- int fd;
- char tmp_name[256];
- size_t tmp_name_len = 0;
- char *dir;
- struct stat st;
-#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
- mode_t mode;
-#endif
-
-#ifdef HAVE_MEMFD_CREATE
- /* this is a GNU extension, make sure to use -D_GNU_SOURCE */
- fd = memfd_create("sljit", MFD_CLOEXEC);
- if (fd != -1) {
- fchmod(fd, 0);
- return fd;
- }
-#endif
-
- dir = secure_getenv("TMPDIR");
-
- if (dir) {
- tmp_name_len = strlen(dir);
- if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)) {
- if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode))
- strcpy(tmp_name, dir);
- }
- }
-
-#ifdef P_tmpdir
- if (!tmp_name_len) {
- tmp_name_len = strlen(P_tmpdir);
- if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name))
- strcpy(tmp_name, P_tmpdir);
- }
-#endif
- if (!tmp_name_len) {
- strcpy(tmp_name, "/tmp");
- tmp_name_len = 4;
- }
-
- SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
-
- if (tmp_name[tmp_name_len - 1] == '/')
- tmp_name[--tmp_name_len] = '\0';
-
-#ifdef __linux__
- /*
- * the previous trimming might had left an empty string if TMPDIR="/"
- * so work around the problem below
- */
- fd = open(tmp_name_len ? tmp_name : "/",
- O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0);
- if (fd != -1)
- return fd;
-#endif
-
- if (tmp_name_len + 7 >= sizeof(tmp_name))
- return -1;
-
- strcpy(tmp_name + tmp_name_len, "/XXXXXX");
-#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
- mode = umask(0777);
-#endif
- fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
-#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
- umask(mode);
-#else
- fchmod(fd, 0);
-#endif
-
- if (fd == -1)
- return -1;
-
- if (unlink(tmp_name)) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size)
-{
- struct chunk_header *retval;
- int fd;
-
- fd = create_tempfile();
- if (fd == -1)
- return NULL;
-
- if (ftruncate(fd, (off_t)size)) {
- close(fd);
- return NULL;
- }
-
- retval = (struct chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-
- if (retval == MAP_FAILED) {
- close(fd);
- return NULL;
- }
-
- retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
-
- if (retval->executable == MAP_FAILED) {
- munmap((void *)retval, size);
- close(fd);
- return NULL;
- }
-
- close(fd);
- return retval;
-}
-#else
-/*
- * MAP_REMAPDUP is a NetBSD extension available sinde 8.0, make sure to
- * adjust your feature macros (ex: -D_NETBSD_SOURCE) as needed
- */
-static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size)
-{
- struct chunk_header *retval;
-
- retval = (struct chunk_header *)mmap(NULL, size,
- PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC),
- MAP_ANON | MAP_SHARED, -1, 0);
-
- if (retval == MAP_FAILED)
- return NULL;
-
- retval->executable = mremap(retval, size, NULL, size, MAP_REMAPDUP);
- if (retval->executable == MAP_FAILED) {
- munmap((void *)retval, size);
- return NULL;
- }
-
- if (mprotect(retval->executable, size, PROT_READ | PROT_EXEC) == -1) {
- munmap(retval->executable, size);
- munmap((void *)retval, size);
- return NULL;
- }
-
- return retval;
-}
-#endif /* NetBSD */
-
-static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
-{
- struct chunk_header *header = ((struct chunk_header *)chunk) - 1;
-
- munmap(header->executable, size);
- munmap((void *)header, size);
-}
-
-/* --------------------------------------------------------------------- */
-/* Common functions */
-/* --------------------------------------------------------------------- */
-
-#define CHUNK_MASK (~(CHUNK_SIZE - 1))
-
-struct block_header {
- sljit_uw size;
- sljit_uw prev_size;
- sljit_sw executable_offset;
-};
-
-struct free_block {
- struct block_header header;
- struct free_block *next;
- struct free_block *prev;
- sljit_uw size;
-};
-
-#define AS_BLOCK_HEADER(base, offset) \
- ((struct block_header*)(((sljit_u8*)base) + offset))
-#define AS_FREE_BLOCK(base, offset) \
- ((struct free_block*)(((sljit_u8*)base) + offset))
-#define MEM_START(base) ((void*)((base) + 1))
-#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7)
-
-static struct free_block* free_blocks;
-static sljit_uw allocated_size;
-static sljit_uw total_size;
-
-static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
-{
- free_block->header.size = 0;
- free_block->size = size;
-
- free_block->next = free_blocks;
- free_block->prev = NULL;
- if (free_blocks)
- free_blocks->prev = free_block;
- free_blocks = free_block;
-}
-
-static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
-{
- if (free_block->next)
- free_block->next->prev = free_block->prev;
-
- if (free_block->prev)
- free_block->prev->next = free_block->next;
- else {
- SLJIT_ASSERT(free_blocks == free_block);
- free_blocks = free_block->next;
- }
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
-{
- struct chunk_header *chunk_header;
- struct block_header *header;
- struct block_header *next_header;
- struct free_block *free_block;
- sljit_uw chunk_size;
- sljit_sw executable_offset;
-
- SLJIT_ALLOCATOR_LOCK();
- if (size < (64 - sizeof(struct block_header)))
- size = (64 - sizeof(struct block_header));
- size = ALIGN_SIZE(size);
-
- free_block = free_blocks;
- while (free_block) {
- if (free_block->size >= size) {
- chunk_size = free_block->size;
- if (chunk_size > size + 64) {
- /* We just cut a block from the end of the free block. */
- chunk_size -= size;
- free_block->size = chunk_size;
- header = AS_BLOCK_HEADER(free_block, chunk_size);
- header->prev_size = chunk_size;
- header->executable_offset = free_block->header.executable_offset;
- AS_BLOCK_HEADER(header, size)->prev_size = size;
- }
- else {
- sljit_remove_free_block(free_block);
- header = (struct block_header*)free_block;
- size = chunk_size;
- }
- allocated_size += size;
- header->size = size;
- SLJIT_ALLOCATOR_UNLOCK();
- return MEM_START(header);
- }
- free_block = free_block->next;
- }
-
- chunk_size = sizeof(struct chunk_header) + sizeof(struct block_header);
- chunk_size = (chunk_size + size + CHUNK_SIZE - 1) & CHUNK_MASK;
-
- chunk_header = alloc_chunk(chunk_size);
- if (!chunk_header) {
- SLJIT_ALLOCATOR_UNLOCK();
- return NULL;
- }
-
- executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header);
-
- chunk_size -= sizeof(struct chunk_header) + sizeof(struct block_header);
- total_size += chunk_size;
-
- header = (struct block_header *)(chunk_header + 1);
-
- header->prev_size = 0;
- header->executable_offset = executable_offset;
- if (chunk_size > size + 64) {
- /* Cut the allocated space into a free and a used block. */
- allocated_size += size;
- header->size = size;
- chunk_size -= size;
-
- free_block = AS_FREE_BLOCK(header, size);
- free_block->header.prev_size = size;
- free_block->header.executable_offset = executable_offset;
- sljit_insert_free_block(free_block, chunk_size);
- next_header = AS_BLOCK_HEADER(free_block, chunk_size);
- }
- else {
- /* All space belongs to this allocation. */
- allocated_size += chunk_size;
- header->size = chunk_size;
- next_header = AS_BLOCK_HEADER(header, chunk_size);
- }
- next_header->size = 1;
- next_header->prev_size = chunk_size;
- next_header->executable_offset = executable_offset;
- SLJIT_ALLOCATOR_UNLOCK();
- return MEM_START(header);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
-{
- struct block_header *header;
- struct free_block* free_block;
-
- SLJIT_ALLOCATOR_LOCK();
- header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
- header = AS_BLOCK_HEADER(header, -header->executable_offset);
- allocated_size -= header->size;
-
- /* Connecting free blocks together if possible. */
-
- /* If header->prev_size == 0, free_block will equal to header.
- In this case, free_block->header.size will be > 0. */
- free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
- if (SLJIT_UNLIKELY(!free_block->header.size)) {
- free_block->size += header->size;
- header = AS_BLOCK_HEADER(free_block, free_block->size);
- header->prev_size = free_block->size;
- }
- else {
- free_block = (struct free_block*)header;
- sljit_insert_free_block(free_block, header->size);
- }
-
- header = AS_BLOCK_HEADER(free_block, free_block->size);
- if (SLJIT_UNLIKELY(!header->size)) {
- free_block->size += ((struct free_block*)header)->size;
- sljit_remove_free_block((struct free_block*)header);
- header = AS_BLOCK_HEADER(free_block, free_block->size);
- header->prev_size = free_block->size;
- }
-
- /* The whole chunk is free. */
- if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
- /* If this block is freed, we still have (allocated_size / 2) free space. */
- if (total_size - free_block->size > (allocated_size * 3 / 2)) {
- total_size -= free_block->size;
- sljit_remove_free_block(free_block);
- free_chunk(free_block, free_block->size +
- sizeof(struct chunk_header) +
- sizeof(struct block_header));
- }
- }
-
- SLJIT_ALLOCATOR_UNLOCK();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
-{
- struct free_block* free_block;
- struct free_block* next_free_block;
-
- SLJIT_ALLOCATOR_LOCK();
-
- free_block = free_blocks;
- while (free_block) {
- next_free_block = free_block->next;
- if (!free_block->header.prev_size &&
- AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
- total_size -= free_block->size;
- sljit_remove_free_block(free_block);
- free_chunk(free_block, free_block->size +
- sizeof(struct chunk_header) +
- sizeof(struct block_header));
- }
- free_block = next_free_block;
- }
-
- SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
- SLJIT_ALLOCATOR_UNLOCK();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr)
-{
- return ((struct block_header *)(ptr))[-1].executable_offset;
-}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitSerialize.c b/src/3rdparty/pcre2/src/sljit/sljitSerialize.c
new file mode 100644
index 0000000000..6ef161fd49
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/sljitSerialize.c
@@ -0,0 +1,516 @@
+/*
+ * 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;
+}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitWXExecAllocator.c b/src/3rdparty/pcre2/src/sljit/sljitWXExecAllocator.c
deleted file mode 100644
index 6893813155..0000000000
--- a/src/3rdparty/pcre2/src/sljit/sljitWXExecAllocator.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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.
- */
-
-/*
- This file contains a simple W^X executable memory allocator for POSIX
- like systems and Windows
-
- In *NIX, MAP_ANON is required (that is considered a feature) so make
- sure to set the right availability macros for your system or the code
- will fail to build.
-
- If your system doesn't support mapping of anonymous pages (ex: IRIX) it
- is also likely that it doesn't need this allocator and should be using
- the standard one instead.
-
- It allocates a separate map for each code block and may waste a lot of
- memory, because whatever was requested, will be rounded up to the page
- size (minimum 4KB, but could be even bigger).
-
- It changes the page permissions (RW <-> RX) as needed and therefore, if you
- will be updating the code after it has been generated, need to make sure to
- block any concurrent execution, or could result in a SIGBUS, that could
- even manifest itself at a different address than the one that was being
- modified.
-
- Only use if you are unable to use the regular allocator because of security
- restrictions and adding exceptions to your application or the system are
- not possible.
-*/
-
-#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
- sljit_update_wx_flags((from), (to), (enable_exec))
-
-#ifndef _WIN32
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#ifdef __NetBSD__
-#define SLJIT_PROT_WX PROT_MPROTECT(PROT_EXEC)
-#define check_se_protected(ptr, size) (0)
-#else /* POSIX */
-#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
-#include <pthread.h>
-#define SLJIT_SE_LOCK() pthread_mutex_lock(&se_lock)
-#define SLJIT_SE_UNLOCK() pthread_mutex_unlock(&se_lock)
-#endif /* !SLJIT_SINGLE_THREADED */
-
-#define check_se_protected(ptr, size) generic_se_protected(ptr, size)
-
-static SLJIT_INLINE int generic_se_protected(void *ptr, sljit_uw size)
-{
- if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC)))
- return mprotect(ptr, size, PROT_READ | PROT_WRITE);
-
- return -1;
-}
-#endif /* NetBSD */
-
-#ifndef SLJIT_SE_LOCK
-#define SLJIT_SE_LOCK()
-#endif
-#ifndef SLJIT_SE_UNLOCK
-#define SLJIT_SE_UNLOCK()
-#endif
-#ifndef SLJIT_PROT_WX
-#define SLJIT_PROT_WX 0
-#endif
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
-{
-#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) \
- && !defined(__NetBSD__)
- static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
- static int se_protected = !SLJIT_PROT_WX;
- int prot = PROT_READ | PROT_WRITE | SLJIT_PROT_WX;
- sljit_uw* ptr;
-
- if (SLJIT_UNLIKELY(se_protected < 0))
- return NULL;
-
-#ifdef PROT_MAX
- prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
-#endif
-
- size += sizeof(sljit_uw);
- ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
-
- if (ptr == MAP_FAILED)
- return NULL;
-
- if (SLJIT_UNLIKELY(se_protected > 0)) {
- SLJIT_SE_LOCK();
- se_protected = check_se_protected(ptr, size);
- SLJIT_SE_UNLOCK();
- if (SLJIT_UNLIKELY(se_protected < 0)) {
- munmap((void *)ptr, size);
- return NULL;
- }
- }
-
- *ptr++ = size;
- return ptr;
-}
-
-#undef SLJIT_PROT_WX
-#undef SLJIT_SE_UNLOCK
-#undef SLJIT_SE_LOCK
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
-{
- sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1;
- munmap((void*)start_ptr, *start_ptr);
-}
-
-static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
-{
- sljit_uw page_mask = (sljit_uw)get_page_alignment();
- sljit_uw start = (sljit_uw)from;
- sljit_uw end = (sljit_uw)to;
- int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
-
- SLJIT_ASSERT(start < end);
-
- start &= ~page_mask;
- end = (end + page_mask) & ~page_mask;
-
- mprotect((void*)start, end - start, prot);
-}
-
-#else /* windows */
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
-{
- sljit_uw *ptr;
-
- size += sizeof(sljit_uw);
- ptr = (sljit_uw*)VirtualAlloc(NULL, size,
- MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-
- if (!ptr)
- return NULL;
-
- *ptr++ = size;
-
- return ptr;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
-{
- sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw);
-#if defined(SLJIT_DEBUG) && SLJIT_DEBUG
- sljit_uw page_mask = (sljit_uw)get_page_alignment();
-
- SLJIT_ASSERT(!(start & page_mask));
-#endif
- VirtualFree((void*)start, 0, MEM_RELEASE);
-}
-
-static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
-{
- DWORD oldprot;
- sljit_uw page_mask = (sljit_uw)get_page_alignment();
- sljit_uw start = (sljit_uw)from;
- sljit_uw end = (sljit_uw)to;
- DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE;
-
- SLJIT_ASSERT(start < end);
-
- start &= ~page_mask;
- end = (end + page_mask) & ~page_mask;
-
- VirtualProtect((void*)start, end - start, prot, &oldprot);
-}
-
-#endif /* !windows */
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
-{
- /* This allocator does not keep unused memory for future allocations. */
-}