PCRE: upgrade to 10.44
New upstream release. [ChangeLog][Third-Party Code] PCRE2 was updated to version 10.44. Change-Id: I49ecc9f25c104813f87203b8a75338e81a1bd813 Pick-to: 6.7 6.5 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 33387ed25f3fa5d914040ebe889b63b7c3daf853) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>bb10
parent
c9b985eae3
commit
3b1d343215
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -603,6 +603,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
|
|||
pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \
|
||||
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
|
||||
pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \
|
||||
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
|
||||
pcre2_set_max_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 \
|
||||
|
|
@ -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_)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -352,6 +353,13 @@ ccontext->max_pattern_length = length;
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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). */
|
||||
|
||||
if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
|
||||
lgb != ucp_gbExtended_Pictographic)
|
||||
lgb = rgb;
|
||||
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 || lgb != ucp_gbExtended_Pictographic) lgb = rgb;
|
||||
|
||||
eptr += len;
|
||||
if (xcount != NULL) *xcount += 1;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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). */
|
||||
|
||||
if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
|
||||
lgb != ucp_gbExtended_Pictographic)
|
||||
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 || 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). */
|
||||
|
||||
if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
|
||||
lgb != ucp_gbExtended_Pictographic)
|
||||
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 || 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). */
|
||||
|
||||
if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
|
||||
lgb != ucp_gbExtended_Pictographic)
|
||||
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 || 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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 (label)
|
||||
result = label->size;
|
||||
if (SLJIT_LIKELY(!(options & SLJIT_GENERATE_CODE_BUFFER))) {
|
||||
code = SLJIT_MALLOC_EXEC(size, exec_allocator_data);
|
||||
*executable_offset = SLJIT_EXEC_OFFSET(code);
|
||||
return code;
|
||||
}
|
||||
|
||||
if (jump && jump->addr < result)
|
||||
result = jump->addr;
|
||||
buffer = (struct sljit_generate_code_buffer*)exec_allocator_data;
|
||||
|
||||
if (const_ && const_->addr < result)
|
||||
result = const_->addr;
|
||||
if (size <= buffer->size) {
|
||||
*executable_offset = buffer->executable_offset;
|
||||
return buffer->buffer;
|
||||
}
|
||||
|
||||
if (put_label && put_label->addr < result)
|
||||
result = put_label->addr;
|
||||
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_);
|
||||
|
||||
#define SLJIT_GET_NEXT_MIN() \
|
||||
next_min_addr = sljit_get_next_min(next_label_size, next_jump_addr, next_const_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 (next_const_addr < result)
|
||||
result = next_const_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,12 +1295,18 @@ 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,12 +1358,18 @@ 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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* 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. */
|
||||
/* Option bits for sljit_generate_code. */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler);
|
||||
/* 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, 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_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);
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(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);
|
||||
|
||||
/* 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; }
|
||||
|
||||
|
|
@ -2221,6 +2266,98 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
|
|||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler,
|
||||
sljit_s32 current_flags);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Serialization functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Label/jump/const enumeration functions. The items in each group
|
||||
are enumerated in creation order. Serialization / deserialization
|
||||
preserves this order for each group. For example the fifth label
|
||||
after deserialization refers to the same machine code location as
|
||||
the fifth label before the serialization. */
|
||||
static SLJIT_INLINE struct sljit_label *sljit_get_first_label(struct sljit_compiler *compiler) { return compiler->labels; }
|
||||
static SLJIT_INLINE struct sljit_jump *sljit_get_first_jump(struct sljit_compiler *compiler) { return compiler->jumps; }
|
||||
static SLJIT_INLINE struct sljit_const *sljit_get_first_const(struct sljit_compiler *compiler) { return compiler->consts; }
|
||||
|
||||
static SLJIT_INLINE struct sljit_label *sljit_get_next_label(struct sljit_label *label) { return label->next; }
|
||||
static SLJIT_INLINE struct sljit_jump *sljit_get_next_jump(struct sljit_jump *jump) { return jump->next; }
|
||||
static SLJIT_INLINE struct sljit_const *sljit_get_next_const(struct sljit_const *const_) { return const_->next; }
|
||||
|
||||
/* A number starting from 0 is assigned to each label, which
|
||||
represents its creation index. The first label created by the
|
||||
compiler has index 0, the second has index 1, the third has
|
||||
index 2, and so on. The returned value is unspecified after
|
||||
sljit_generate_code() is called. */
|
||||
static SLJIT_INLINE sljit_uw sljit_get_label_index(struct sljit_label *label) { return label->u.index; }
|
||||
|
||||
/* The sljit_jump_has_label() and sljit_jump_has_target() functions
|
||||
returns non-zero value if a label or target is set for the jump
|
||||
respectively. Both may return with a zero value. The other two
|
||||
functions return the value assigned to the jump. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_label(struct sljit_jump *jump);
|
||||
static SLJIT_INLINE struct sljit_label *sljit_jump_get_label(struct sljit_jump *jump) { return jump->u.label; }
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_target(struct sljit_jump *jump);
|
||||
static SLJIT_INLINE sljit_uw sljit_jump_get_target(struct sljit_jump *jump) { return jump->u.target; }
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_is_mov_addr(struct sljit_jump *jump);
|
||||
|
||||
/* Option bits for sljit_serialize_compiler. */
|
||||
|
||||
/* When debugging is enabled, the serialized buffer contains
|
||||
debugging information unless this option is specified. */
|
||||
#define SLJIT_SERIALIZE_IGNORE_DEBUG 0x1
|
||||
|
||||
/* Serialize the internal structure of the compiler into a buffer.
|
||||
If the serialization is successful, the returned value is a newly
|
||||
allocated buffer which is allocated by the memory allocator assigned
|
||||
to the compiler. Otherwise the returned value is NULL. Unlike
|
||||
sljit_generate_code(), serialization does not modify the internal
|
||||
state of the compiler, so the code generation can be continued.
|
||||
|
||||
options must be the combination of SLJIT_SERIALIZE_* option bits
|
||||
size is an output argument, which is set to the byte size of
|
||||
the result buffer if the operation is successful
|
||||
|
||||
Notes:
|
||||
- This function is useful for ahead-of-time compilation (AOT).
|
||||
- The returned buffer must be freed later by the caller.
|
||||
The SLJIT_FREE() macro is suitable for this purpose:
|
||||
SLJIT_FREE(returned_buffer, sljit_get_allocator_data(compiler))
|
||||
- Memory allocated by sljit_alloc_memory() is not serialized.
|
||||
- The type of the returned buffer is sljit_uw* to emphasize that
|
||||
the buffer is word aligned. However, the 'size' output argument
|
||||
contains the byte size, so this value is always divisible by
|
||||
sizeof(sljit_uw).
|
||||
*/
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_uw *size);
|
||||
|
||||
/* Construct a new compiler instance from a buffer produced by
|
||||
sljit_serialize_compiler(). If the operation is successful, the new
|
||||
compiler instance is returned. Otherwise the returned value is NULL.
|
||||
|
||||
buffer points to a word aligned memory data which was
|
||||
created by sljit_serialize_compiler()
|
||||
size is the byte size of the buffer
|
||||
options must be 0
|
||||
allocator_data specify an allocator specific data, see
|
||||
sljit_create_compiler() for further details
|
||||
|
||||
Notes:
|
||||
- Labels assigned to jumps are restored with their
|
||||
corresponding label in the label set created by
|
||||
the deserializer. Target addresses assigned to
|
||||
jumps are also restored. Uninitialized jumps
|
||||
remain uninitialized.
|
||||
- After the deserialization, sljit_generate_code() does
|
||||
not need to be the next operation on the returned
|
||||
compiler, the code generation can be continued.
|
||||
Even sljit_serialize_compiler() can be called again.
|
||||
- When debugging is enabled, a buffers without debug
|
||||
information cannot be deserialized.
|
||||
*/
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit_uw* buffer, sljit_uw size,
|
||||
sljit_s32 options, void *allocator_data);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Miscellaneous utility functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -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,6 +2168,36 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
|||
}
|
||||
} while(0);
|
||||
|
||||
/* Destination. */
|
||||
dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op <= SLJIT_MOV_P) {
|
||||
if (dst & SLJIT_MEM) {
|
||||
if (inp_flags & BYTE_SIZE)
|
||||
inp_flags &= ~SIGNED;
|
||||
|
||||
if (FAST_IS_REG(src2))
|
||||
return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG1);
|
||||
}
|
||||
|
||||
if (FAST_IS_REG(src2) && dst_reg != TMP_REG2)
|
||||
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;
|
||||
|
|
@ -2079,30 +2209,12 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
|
|||
src1_reg = TMP_REG1;
|
||||
}
|
||||
|
||||
/* Destination. */
|
||||
dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op <= SLJIT_MOV_P) {
|
||||
if (dst & SLJIT_MEM) {
|
||||
if (inp_flags & BYTE_SIZE)
|
||||
inp_flags &= ~SIGNED;
|
||||
|
||||
if (FAST_IS_REG(src2))
|
||||
return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG2);
|
||||
}
|
||||
|
||||
if (FAST_IS_REG(src2) && dst_reg != TMP_REG2)
|
||||
flags |= MOVE_REG_CONV;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
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)
|
||||
FAIL_IF(emit_blx(compiler));
|
||||
#else /* !SLJIT_CONFIG_ARM_V6 */
|
||||
FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
|
||||
FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));
|
||||
#endif /* SLJIT_CONFIG_ARM_V6 */
|
||||
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) {
|
||||
jump->addr = compiler->size;
|
||||
FAIL_IF(emit_blx(compiler));
|
||||
}
|
||||
#else /* !SLJIT_CONFIG_ARM_V6 */
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
code_ptr[3] = code_ptr[0];
|
||||
return code_ptr + 3;
|
||||
}
|
||||
|
||||
exit:
|
||||
jump->flags |= PATCH_ABS64;
|
||||
code_ptr[4] = code_ptr[0];
|
||||
return code_ptr + 4;
|
||||
}
|
||||
|
||||
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)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 (diff <= 0xfffff000l && diff >= -0x100000000l) {
|
||||
SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
|
||||
jump->flags |= PATCH_B32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
jump->flags |= PATCH_ABS64;
|
||||
return 0;
|
||||
}
|
||||
if (addr < 0x100000000l) {
|
||||
SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
|
||||
{
|
||||
if (max_label < 0x100000000l) {
|
||||
put_label->flags = 0;
|
||||
if (addr < 0x1000000000000l) {
|
||||
SLJIT_ASSERT(jump->flags >= ((sljit_uw)2 << JUMP_SIZE_SHIFT));
|
||||
jump->flags |= PATCH_ABS48;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (max_label < 0x1000000000000l) {
|
||||
put_label->flags = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
put_label->flags = 2;
|
||||
return 0;
|
||||
SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));
|
||||
jump->flags |= PATCH_ABS64;
|
||||
return 3;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
|
||||
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_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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
else if (jump->flags & IS_BL) {
|
||||
if (diff <= 8388607 && diff >= -8388608) {
|
||||
jump->flags |= PATCH_BL;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (diff <= 1023 && diff >= -1024) {
|
||||
jump->flags |= PATCH_TYPE4;
|
||||
return 4;
|
||||
}
|
||||
if (diff <= 8388607 && diff >= -8388608) {
|
||||
diff -= SSIZE_OF(u16);
|
||||
} else if (jump->flags & IS_BL) {
|
||||
/* Branch and link. */
|
||||
if (diff <= 0xffffff && diff >= -0x1000000) {
|
||||
jump->flags |= PATCH_TYPE5;
|
||||
return 3;
|
||||
return code_ptr + 1;
|
||||
}
|
||||
goto exit;
|
||||
} else if (diff <= 0x7ff && diff >= -0x800) {
|
||||
jump->flags |= PATCH_TYPE3;
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (diff <= 0xffffff && diff >= -0x1000000) {
|
||||
jump->flags |= PATCH_TYPE4;
|
||||
return code_ptr + 1;
|
||||
}
|
||||
|
||||
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 void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset)
|
||||
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 3;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(jump->u.label->addr & 0x1);
|
||||
diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
|
||||
}
|
||||
jump_inst = (sljit_u16*)jump->addr;
|
||||
|
||||
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. */
|
||||
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));
|
||||
/* Really complex instruction form for branches. Negate with sign bit. */
|
||||
diff ^= ((diff >> 2) & 0x600000) ^ 0x600000;
|
||||
|
||||
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)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 48);
|
||||
inst[1] = ORI | S(reg) | A(reg) | IMM((addr >> 32) & 0xffff);
|
||||
inst++;
|
||||
}
|
||||
|
||||
inst[1] = SLDI(32) | S(reg) | A(reg);
|
||||
inst[2] = ORIS | S(reg) | A(reg) | IMM((addr >> 16) & 0xffff);
|
||||
inst += 2;
|
||||
}
|
||||
|
||||
inst[1] = ORI | S(reg) | A(reg) | IMM(addr & 0xffff);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
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;
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
|
||||
#else
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
compiler->size++;
|
||||
#else
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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 (max_label <= S44_MAX) {
|
||||
put_label->flags = PATCH_ABS44;
|
||||
if (addr <= S32_MAX) {
|
||||
SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));
|
||||
jump->flags |= PATCH_ABS32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
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_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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
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 >> 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);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
ins |= (sljit_ins)offset & 0xffffffff;
|
||||
|
||||
/* update address */
|
||||
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);
|
||||
|
||||
/* move to next constant */
|
||||
const_ = const_->next;
|
||||
next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
|
||||
}
|
||||
|
||||
SLJIT_GET_NEXT_MIN();
|
||||
}
|
||||
|
||||
if (ins & 0xffff00000000L) {
|
||||
*code_ptr++ = (sljit_u16)(ins >> 32);
|
||||
half_count++;
|
||||
}
|
||||
|
||||
if (ins & 0xffffffff0000L) {
|
||||
*code_ptr++ = (sljit_u16)(ins >> 16);
|
||||
half_count++;
|
||||
}
|
||||
|
||||
*code_ptr++ = (sljit_u16)ins;
|
||||
half_count++;
|
||||
} while (buf_ptr < buf_end);
|
||||
|
||||
buf = buf->next;
|
||||
} while (buf);
|
||||
|
||||
if (next_label_size == half_count) {
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label = label->next;
|
||||
}
|
||||
|
||||
/* reset jumps */
|
||||
jump = compiler->jumps;
|
||||
put_label = compiler->put_labels;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* update instruction with relative address of constant */
|
||||
source = (sljit_sw)code_ptr;
|
||||
offset = (sljit_sw)pool_ptr - source;
|
||||
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1; /* halfword (not byte) offset */
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
|
||||
ins |= (sljit_ins)offset & 0xffffffff;
|
||||
|
||||
/* update address */
|
||||
const_->const_.addr = (sljit_uw)pool_ptr;
|
||||
|
||||
/* store initial value into pool and update pool address */
|
||||
*(pool_ptr++) = (sljit_uw)const_->init_value;
|
||||
|
||||
/* move to next constant */
|
||||
const_ = (struct sljit_s390x_const *)const_->const_.next;
|
||||
}
|
||||
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;
|
||||
|
||||
/* 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));
|
||||
|
||||
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;
|
||||
|
||||
/* offset must be halfword aligned */
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */
|
||||
|
||||
/* 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(put_label->label);
|
||||
put_label->addr = (sljit_uw)code_ptr;
|
||||
|
||||
/* store target into pool */
|
||||
*pool_ptr = put_label->label->addr;
|
||||
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;
|
||||
|
||||
put_label = put_label->next;
|
||||
}
|
||||
encode_inst(&code_ptr, ins);
|
||||
}
|
||||
}
|
||||
SLJIT_ASSERT((sljit_u8 *)code + ins_size == code_ptr);
|
||||
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);
|
||||
|
||||
jump = compiler->jumps;
|
||||
while (jump != NULL) {
|
||||
offset = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr);
|
||||
|
||||
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);
|
||||
|
||||
/* offset must be halfword aligned */
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */
|
||||
|
||||
code_ptr[1] = (sljit_u16)(offset >> 16);
|
||||
code_ptr[2] = (sljit_u16)offset;
|
||||
}
|
||||
jump = jump->next;
|
||||
}
|
||||
|
||||
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;
|
||||
if (dst & SLJIT_MEM)
|
||||
return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw);
|
||||
|
||||
SLJIT_ASSERT(dst_r == TMP_FREG1);
|
||||
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
sljit_uw addr;
|
||||
sljit_sw diff;
|
||||
SLJIT_UNUSED_ARG(executable_offset);
|
||||
|
||||
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;
|
||||
|
||||
if (addr > 0xffffffffl) {
|
||||
diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
jump->flags |= PATCH_MD;
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
if (put_label->flags == 0) {
|
||||
/* Destination is register. */
|
||||
code_ptr = (sljit_u8*)put_label->addr - 2 - sizeof(sljit_uw);
|
||||
|
||||
SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
|
||||
SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
put_label->addr = (sljit_uw)code_ptr;
|
||||
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)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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. */
|
||||
}
|
||||
Loading…
Reference in New Issue