Import sljit 0.91 (svn r257).

The changes since the last import are:

r257: Add missing ADJUST_LOCAL_OFFSET for ARM64.
r256: Move incorrectly placed array definitions.
r255: More work on testing environment.
r254: Refactor test default output.
r253: Pass entry adress in r12 on PPC-LE.
r252: Optimize calls on MIPS-64.
r251: Several minor fixes.
r250: Add missing SLJIT_IS_FPU_AVAILABLE checks and reorder U and S flags.
r249: Optimize jumps on ARM-64.
r248: Optimize jumps on PowerPC.
r247: MIPS64 support is mostly finished.
r246: MIPS arithmetic.
r245: Start working on MIPS64.
r244: Uniform names for TILE-Gx.
r243: Uniform the names of ARM compilers.
r242: Change ll to l on x86 and rename some instructions on ARM-64.
r241: Improved memory access in PPC and reordering the parameter type flags.
r240: Prepare for more registers on ARM-Thumb2 and renaming TMP_REGISTER to TMP_REG1 on x86.
r239: Prepare for more registers on ARMv5.
r238: Prepare for more registers on TILE-Gx.
r237: Prepare for more registers on MIPS and SPARC.
r236: Prepare for more registers on PPC.
r235: Prepare for more registers on x86.
r234: Most tests are pass on ARM-64 now.
r233: Around 25 test cases are now pass on ARM-64.
r232: More progress on ARM-64 and Thumb2 refactoring.
r231: Some progress an ARM-64 and ARM-T2 refactoring.
r230: Thumb2 code refactoring.
r229: Start working on ARM-64.
r228: Little endian PowerPC systems are supported now by the JIT compiler.
r227: TileGX architecture is now supported. Patch made by Jiong Wang.
r226: Cache flush for android. Patch by  Giuseppe D'Angelo.
r225: Add support for forcibly freeing unused executable memory. Inspired by Carsten Klein.
r224: Few typo fixes.
r223: Reorder madvise and posix_madvise.
r222: The missing sljit_get_float_register_index function is added.
r221: Remove an invalid shift on ARM.
r220: JIT compiler now supports 32 bit Macs thanks to Lawrence Velazquez.
r219: Better code size statistics.
r218: Improvements for x86 and LIR dump.
r217: ICC and SunPro C fixes
r216: A new file for tracking internal changes are added.
r215: Less GNU dependnet Makefile and Intel style assemby for x86-64 systems.
r214: Switch from stdcall to cdecl in x86-32.
r213: Upstreaming minor fixes. Thanks for Daniel Richard G.
r212: Documentation update and a fix for a locking issue.
r211: Renaming temporaries to scratches to match the new name of the register. Does not affect compatibility.
r210: Improving assertions.
r209: Port sljit to SunPro C compiler. Patch by Daniel Richard G.
r208: SLJIT_TEMPORARY_REGx registers are renamed to SLJIT_SCRATCH_REGx.
r207: Removing unused checks.
r206: Optimizations for arm.
r205: Some optimizations on powerpc, mips and sparc.
r204: Rename sljit_emit_cond_value to sljit_emit_op_flags.
r203: Small x86 optimization.
r202: Finish cond_value with AND and INT_OP.
r201: More x86 fixes and improvements.
r200: Rename buf and code to inst.
r199: Replacing constants with instruction names in x86. Greatly improves maintainability.
r198: Only xmm0-xmm5 is volatile on Win64, so xmm6 must be saved.
r197: PowerPC shift right always modifies the carry flag. We may need to restore it.
r196: Rename SLJIT_F* functions to SLJIT_*D
r195: SLJIT_INT_OP works in the same way as SLJIT_SINGLE_OP: the input register arguments must be generated by the output of another instruction with SLJIT_INT_OP flag
r194: Renaming sljit_w to sljit_sw, sljit_i to sljit_si, sljit_h to sljit_sh, and sljit_b to sljit_sb.
r193: ARM single precision support.
r192: Single precision support added for ppc, mips and sparc.
r191: Add single precision support. Only works on x86 now.
r190: Relace C types with sljit types. No functionality change.
r189: Change 0 to NULL for mmap.
r188: Support environments where MAP_ANON is not available.
r187: Adding type descriptors for pointers and doubles (preparing for x32 ABIs and single precision support).
This commit is contained in:
alnsn 2014-06-17 15:37:40 +00:00
parent 875518eacc
commit e5292e6b87
20 changed files with 21337 additions and 1206 deletions

53
sys/external/bsd/sljit/dist/API_CHANGES vendored Normal file
View File

@ -0,0 +1,53 @@
This file is the short summary of the API changes:
05.03.2014 - Backward compatible
The sljit_set_target now supports those jumps, which
does not created with SLJIT_REWRITABLE_JUMP flag.
Reason: sljit_emit_ijump does not support conditional
jumps.
03.03.2014 - Non-backward compatible
SLJIT_MOV_UI cannot be combined with SLJIT_INT_OP.
Reason: SLJIT_INT_OP flag is not recommended to use
directly, and SLJIT_IMOV has no sign bit.
29.01.2014 - Backward compatible
Bits assigned to SLJIT_MEM and SLJIT_IMM flags are changed.
Reason: the most common cases are fits into one byte now,
and more registers can be supported in the future.
08.11.2012 - Non-backward compatible
SLJIT_TEMPORARY_REGx registers are renamed to SLJIT_SCRATCH_REGx.
07.11.2012 - Non-backward compatible
sljit_emit_cond_value is renamed to sljit_emit_op_flags. An
extra source argument is added which will be used in the future.
05.11.2012 - Backward compatible
sljit_emit_cond_value now supports SLJIT_AND and SLJIT_INT_OP
flags, which makes this function complete.
01.11.2012 - Non-backward compatible
SLJIT_F* opcodes are renamed to SLJIT_*D to show that
they are double precision operators. Furthermore
SLJIT_*S single precision opcodes are added.
01.11.2012 - Non-backward compatible
Register arguments of operations with SLJIT_INT_OP flag
must be computed by another operation with SLJIT_INT_OP flag.
The same way as SLJIT_SINGLE_OP flag works with floating point
numbers. See the description of SLJIT_INT_OP.
01.11.2012 - Backward compatible
All operations whose support the SLJIT_INT_OP flag, have an
alternate name now, which includes the SLJIT_INT_OP. These
names starting with I.
31.10.2012 - Non-backward compatible
Renaming sljit_w to sljit_sw, sljit_i to sljit_si, sljit_h
to sljit_sh, and sljit_b to sljit_sb. Reason: their sign
bit is part of the type now.
20.10.2012 - Non-backward compatible
Renaming SLJIT_C_FLOAT_NAN to SLJIT_C_FLOAT_UNORDERED.
Reason: all architectures call these unordered comparions.

View File

@ -0,0 +1,8 @@
This file is the short summary of the internal changes:
18.11.2012
Switching from stdcall to cdecl on x86-32. Fastcall is still the default
on GCC and MSVC. Now Intel C compilers are supported.
20.10.2012
Supporting Sparc-32 CPUs.

View File

@ -1,17 +1,22 @@
ifndef CROSS_COMPILER
# default compier
CC = gcc
else
CC = $(CROSS_COMPILER)
endif
# Cross compiler for ARM
#CC = arm-linux-gcc
ifndef EXTRA_CPPFLAGS
EXTRA_CPPFLAGS=
endif
# Cross compiler for PPC
#CC = powerpc-linux-gnu-gcc
ifndef EXTRA_LDFLAGS
EXTRA_LDFLAGS=
endif
# Cross compiler for PPC-64
#CC = powerpc64-unknown-linux-gnu-gcc
CFLAGS = -O2 -Wall -DSLJIT_CONFIG_AUTO=1
LDFLAGS=
CPPFLAGS = $(EXTRA_CPPFLAGS) -DSLJIT_CONFIG_AUTO=1 -Isljit_src
CFLAGS = -O2 -Wall
REGEX_CFLAGS = -fshort-wchar
LDFLAGS = $(EXTRA_LDFLAGS)
TARGET = sljit_test regex_test
@ -20,17 +25,15 @@ SRCDIR = sljit_src
TESTDIR = test_src
REGEXDIR = regex_src
CFLAGS += -Isljit_src
REGEX_CFLAGS = -fshort-wchar
SLJIT_HEADERS = $(SRCDIR)/sljitLir.h $(SRCDIR)/sljitConfig.h $(SRCDIR)/sljitConfigInternal.h
SLJIT_LIR_FILES = $(SRCDIR)/sljitLir.c $(SRCDIR)/sljitExecAllocator.c $(SRCDIR)/sljitUtils.c \
$(SRCDIR)/sljitNativeX86_common.c $(SRCDIR)/sljitNativeX86_32.c $(SRCDIR)/sljitNativeX86_64.c \
$(SRCDIR)/sljitNativeARM_v5.c $(SRCDIR)/sljitNativeARM_Thumb2.c \
$(SRCDIR)/sljitNativeARM_32.c $(SRCDIR)/sljitNativeARM_T2_32.c $(SRCDIR)/sljitNativeARM_64.c \
$(SRCDIR)/sljitNativeMIPS_common.c $(SRCDIR)/sljitNativeMIPS_32.c $(SRCDIR)/sljitNativeMIPS_64.c \
$(SRCDIR)/sljitNativePPC_common.c $(SRCDIR)/sljitNativePPC_32.c $(SRCDIR)/sljitNativePPC_64.c \
$(SRCDIR)/sljitNativeMIPS_common.c $(SRCDIR)/sljitNativeMIPS_32.c \
$(SRCDIR)/sljitNativeSPARC_common.c $(SRCDIR)/sljitNativeSPARC_32.c
$(SRCDIR)/sljitNativeSPARC_common.c $(SRCDIR)/sljitNativeSPARC_32.c \
$(SRCDIR)/sljitNativeTILEGX_64.c \
$(SRCDIR)/sljitNativeX86_common.c $(SRCDIR)/sljitNativeX86_32.c $(SRCDIR)/sljitNativeX86_64.c
all: $(BINDIR) $(TARGET)
@ -38,25 +41,25 @@ $(BINDIR) :
mkdir $(BINDIR)
$(BINDIR)/sljitLir.o : $(BINDIR) $(SLJIT_LIR_FILES) $(SLJIT_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/sljitLir.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SRCDIR)/sljitLir.c
$(BINDIR)/sljitMain.o : $(TESTDIR)/sljitMain.c $(BINDIR) $(SLJIT_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $(TESTDIR)/sljitMain.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(TESTDIR)/sljitMain.c
$(BINDIR)/sljitTest.o : $(TESTDIR)/sljitTest.c $(BINDIR) $(SLJIT_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $(TESTDIR)/sljitTest.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(TESTDIR)/sljitTest.c
$(BINDIR)/regexMain.o : $(REGEXDIR)/regexMain.c $(BINDIR) $(SLJIT_HEADERS)
$(CC) $(CFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexMain.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexMain.c
$(BINDIR)/regexJIT.o : $(REGEXDIR)/regexJIT.c $(BINDIR) $(SLJIT_HEADERS) $(REGEXDIR)/regexJIT.h
$(CC) $(CFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexJIT.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexJIT.c
clean:
rm -f $(BINDIR)/*.o $(BINDIR)/sljit_test $(BINDIR)/regex_test
sljit_test: $(BINDIR)/sljitMain.o $(BINDIR)/sljitTest.o $(BINDIR)/sljitLir.o
$(CC) $(LDFLAGS) $(BINDIR)/sljitMain.o $(BINDIR)/sljitTest.o $(BINDIR)/sljitLir.o -o $(BINDIR)/$@ -lm -lpthread
$(CC) $(CFLAGS) $(LDFLAGS) $(BINDIR)/sljitMain.o $(BINDIR)/sljitTest.o $(BINDIR)/sljitLir.o -o $(BINDIR)/$@ -lm -lpthread
regex_test: $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o
$(CC) $(LDFLAGS) $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o -o $(BINDIR)/$@ -lm -lpthread
$(CC) $(CFLAGS) $(LDFLAGS) $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o -o $(BINDIR)/$@ -lm -lpthread

View File

@ -2,18 +2,19 @@
SLJIT - Stack Less JIT Compiler
Purpose:
A simple machine independent JIT, which suitable for interpreters and
other dynamic tools. See sljitLir.h for more information.
A simple, machine independent JIT compiler, which suitable for
translating interpreted byte code to machine code. The sljitLir.h
describes the LIR (low-level intermediate representation) of SLJIT.
Compatible:
Any C (C++) compiler. At least I hope so.
Using sljit:
Copy sljitLir.c sljitLir.h sljitConfig.h sljitExecAllocator.c and sljitNative*.c
files into your project. Add sljitLir.c into your project. The other files are
included by sljitLir.c (when required). Define the machine by SLJIT_CONFIG_*
selector. See sljitConfig.h for all possible values. For C++ compilers, rename
sljitLir.c to sljitLir.cpp.
Copy the content of sljit_src directory into your project source directory.
Add sljitLir.c source file to your build environment. All other files are
included by sljitLir.c (if required). Define the machine by SLJIT_CONFIG_*
selector. See sljitConfig.h for all possible values. For C++ compilers,
rename sljitLir.c to sljitLir.cpp.
More info:
http://sljit.sourceforge.net/
@ -24,3 +25,5 @@ Contact:
Special thanks:
Alexander Nasonov
Daniel Richard G.
Giuseppe D'Angelo
Jiong Wang (TileGX support)

View File

@ -53,13 +53,13 @@ struct regex_machine
/* flags. */
int flags;
/* Number of state descriptors for one term. */
sljit_w no_states;
sljit_sw no_states;
/* Total size. */
sljit_w size;
sljit_sw size;
union {
void *init_match;
sljit_w (SLJIT_CALL *call_init)(void *next, void* match);
sljit_sw (SLJIT_CALL *call_init)(void *next, void* match);
} u;
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
struct sljit_function_context context;
@ -74,19 +74,19 @@ struct regex_machine
struct regex_match
{
/* Current and next state array. */
sljit_w *current;
sljit_w *next;
sljit_sw *current;
sljit_sw *next;
/* Starting. */
sljit_w head;
sljit_sw head;
/* String character index (ever increasing). */
sljit_w index;
sljit_sw index;
/* Best match found so far (members in priority order). */
sljit_w best_begin;
sljit_w best_end;
sljit_w best_id;
sljit_sw best_begin;
sljit_sw best_end;
sljit_sw best_id;
/* Bool flags (encoded as word). */
sljit_w fast_quit;
sljit_w fast_forward;
sljit_sw fast_quit;
sljit_sw fast_forward;
/* Machine. */
struct regex_machine *machine;
@ -96,7 +96,7 @@ struct regex_match
} u;
/* Variable sized array to contain the state arrays. */
sljit_w states[1];
sljit_sw states[1];
};
/* State vector
@ -117,11 +117,11 @@ struct regex_match
/* String fragment length. */
#define R_LENGTH SLJIT_SAVED_EREG2
/* 'struct regex_match*' */
#define R_REGEX_MATCH SLJIT_TEMPORARY_REG1
#define R_REGEX_MATCH SLJIT_SCRATCH_REG1
/* Current character. */
#define R_CURR_CHAR SLJIT_TEMPORARY_REG2
#define R_CURR_CHAR SLJIT_SCRATCH_REG2
/* Temporary register. */
#define R_TEMP SLJIT_TEMPORARY_REG3
#define R_TEMP SLJIT_SCRATCH_REG3
/* Caches the regex_match->best_begin. */
#define R_BEST_BEGIN SLJIT_TEMPORARY_EREG1
/* Current character index. */
@ -379,13 +379,13 @@ struct compiler_common {
/* REGEX_ flags. */
int flags;
/* Encoded size of the dfa representation. */
sljit_w dfa_size;
sljit_sw dfa_size;
/* Number of terms. */
sljit_w terms_size;
sljit_sw terms_size;
/* Number of state descriptors for one term (same as machine->no_states). */
sljit_w no_states;
sljit_sw no_states;
/* Number of type_rng_(char|left)-s in the longest character range. */
sljit_w longest_range_size;
sljit_sw longest_range_size;
/* DFA linear representation (size: dfa_size). */
struct stack_item *dfa_transitions;
@ -555,7 +555,7 @@ static int iterate(struct stack *stack, int min, int max)
return len;
}
static int parse_iterator(const regex_char_t *regex_string, int length, struct stack *stack, sljit_w *dfa_size, int begin)
static int parse_iterator(const regex_char_t *regex_string, int length, struct stack *stack, sljit_sw *dfa_size, int begin)
{
/* We only know that *regex_string == { . */
int val1, val2;
@ -1281,8 +1281,8 @@ static int trace_transitions(int from, struct compiler_common *compiler_common)
/* Code generator */
/* --------------------------------------------------------------------- */
#define TERM_OFFSET_OF(index, offs) (((index) * no_states + (offs)) * sizeof(sljit_w))
#define TERM_REL_OFFSET_OF(base, offs) ((base) + ((offs) * sizeof(sljit_w)))
#define TERM_OFFSET_OF(index, offs) (((index) * no_states + (offs)) * sizeof(sljit_sw))
#define TERM_REL_OFFSET_OF(base, offs) ((base) + ((offs) * sizeof(sljit_sw)))
#define EMIT_OP1(type, arg1, arg2, arg3, arg4) \
CHECK(sljit_emit_op1(compiler, type, arg1, arg2, arg3, arg4))
@ -1314,9 +1314,9 @@ static int compile_uncond_tran(struct compiler_common *compiler_common, int reg)
struct stack *stack = &compiler_common->stack;
struct stack_item *search_states = compiler_common->search_states;
int flags = compiler_common->flags;
sljit_w no_states = compiler_common->no_states;
sljit_sw no_states = compiler_common->no_states;
sljit_uw head = 0;
sljit_w offset, value;
sljit_sw offset, value;
if (reg != R_CURR_STATE || !(compiler_common->flags & REGEX_FAKE_MATCH_BEGIN)) {
CHECK(trace_transitions(0, compiler_common));
@ -1366,15 +1366,15 @@ static int compile_uncond_tran(struct compiler_common *compiler_common, int reg)
return REGEX_NO_ERROR;
}
static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w curr_index)
static int compile_cond_tran(struct compiler_common *compiler_common, sljit_sw curr_index)
{
struct sljit_compiler *compiler = compiler_common->compiler;
struct stack *stack = &compiler_common->stack;
struct stack_item *search_states = compiler_common->search_states;
sljit_w offset;
sljit_sw offset;
int flags;
sljit_w no_states;
sljit_w value;
sljit_sw no_states;
sljit_sw value;
struct sljit_jump *jump1;
struct sljit_jump *jump2;
struct sljit_jump *jump3;
@ -1402,8 +1402,8 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
if (!(flags & REGEX_ID_CHECK)) {
if (!(flags & REGEX_MATCH_BEGIN)) {
/* Check whether item is inserted. */
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), R_NEXT_HEAD, 0);
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), R_NEXT_HEAD, 0);
if (offset > 0) {
EMIT_OP1(SLJIT_MOV, R_NEXT_HEAD, 0, SLJIT_IMM, offset);
}
@ -1413,19 +1413,19 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
EMIT_LABEL(label1);
sljit_set_label(jump1, label1);
EMIT_CMP(jump1, SLJIT_C_LESS_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_w), R_TEMP, 0);
EMIT_CMP(jump1, SLJIT_C_LESS_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_LABEL(label1);
sljit_set_label(jump2, label1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_w), R_TEMP, 0);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_LABEL(label1);
sljit_set_label(jump1, label1);
}
else {
/* Check whether item is inserted. */
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), R_NEXT_HEAD, 0);
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), R_NEXT_HEAD, 0);
if (offset > 0) {
EMIT_OP1(SLJIT_MOV, R_NEXT_HEAD, 0, SLJIT_IMM, offset);
}
@ -1438,8 +1438,8 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
EMIT_OP1(SLJIT_MOV, R_TEMP, 0, SLJIT_MEM1(R_CURR_STATE), TERM_OFFSET_OF(curr_index, 2));
/* Check whether item is inserted. */
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), R_NEXT_HEAD, 0);
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), R_NEXT_HEAD, 0);
if (offset > 0) {
EMIT_OP1(SLJIT_MOV, R_NEXT_HEAD, 0, SLJIT_IMM, offset);
}
@ -1449,7 +1449,7 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
EMIT_LABEL(label1);
sljit_set_label(jump1, label1);
EMIT_OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_w), R_TEMP, 0);
EMIT_OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_JUMP(jump1, SLJIT_C_LESS);
EMIT_JUMP(jump3, SLJIT_C_GREATER);
@ -1463,7 +1463,7 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
sljit_set_label(jump4, label1);
}
EMIT_OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, SLJIT_MEM1(R_NEXT_STATE), offset + 3 * sizeof(sljit_w), R_TEMP, 0);
EMIT_OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, SLJIT_MEM1(R_NEXT_STATE), offset + 3 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_JUMP(jump4, SLJIT_C_GREATER_EQUAL);
EMIT_JUMP(jump5, SLJIT_JUMP);
@ -1471,7 +1471,7 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
EMIT_LABEL(label1);
sljit_set_label(jump3, label1);
sljit_set_label(jump2, label1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_w), R_TEMP, 0);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_OP1(SLJIT_MOV, R_TEMP, 0, SLJIT_MEM1(R_CURR_STATE), TERM_OFFSET_OF(curr_index, 3));
if (search_states[value].value > 0) {
@ -1484,7 +1484,7 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
EMIT_LABEL(label1);
sljit_set_label(jump5, label1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 3 * sizeof(sljit_w), R_TEMP, 0);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 3 * sizeof(sljit_sw), R_TEMP, 0);
/* Exit. */
EMIT_LABEL(label1);
@ -1503,8 +1503,8 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
}
/* Check whether item is inserted. */
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_w), R_NEXT_HEAD, 0);
EMIT_CMP(jump1, SLJIT_C_NOT_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + sizeof(sljit_sw), R_NEXT_HEAD, 0);
if (offset > 0) {
EMIT_OP1(SLJIT_MOV, R_NEXT_HEAD, 0, SLJIT_IMM, offset);
}
@ -1514,11 +1514,11 @@ static int compile_cond_tran(struct compiler_common *compiler_common, sljit_w cu
EMIT_LABEL(label1);
sljit_set_label(jump1, label1);
EMIT_CMP(jump1, SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_w), R_TEMP, 0);
EMIT_CMP(jump1, SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_LABEL(label1);
sljit_set_label(jump2, label1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_w), R_TEMP, 0);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_NEXT_STATE), offset + 2 * sizeof(sljit_sw), R_TEMP, 0);
EMIT_LABEL(label1);
sljit_set_label(jump1, label1);
@ -1593,11 +1593,11 @@ static int compile_end_check(struct compiler_common *compiler_common, struct slj
sljit_set_label(jump, leave_label);
EMIT_OP2(SLJIT_ADD, R_TEMP, 0, R_TEMP, 0, R_CURR_STATE, 0);
EMIT_OP1(SLJIT_MOV, R_BEST_BEGIN, 0, SLJIT_MEM1(R_TEMP), sizeof(sljit_w));
EMIT_CMP(clear_states_jump, !(compiler_common->flags & REGEX_MATCH_NON_GREEDY) ? SLJIT_C_GREATER : SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(R_TEMP), 2 * sizeof(sljit_w), R_CURR_CHAR, 0);
EMIT_OP1(SLJIT_MOV, R_BEST_BEGIN, 0, SLJIT_MEM1(R_TEMP), sizeof(sljit_sw));
EMIT_CMP(clear_states_jump, !(compiler_common->flags & REGEX_MATCH_NON_GREEDY) ? SLJIT_C_GREATER : SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(R_TEMP), 2 * sizeof(sljit_sw), R_CURR_CHAR, 0);
/* Case 1: keep this case. */
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_TEMP), sizeof(sljit_w), R_NEXT_HEAD, 0);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_TEMP), sizeof(sljit_sw), R_NEXT_HEAD, 0);
EMIT_OP2(SLJIT_SUB, R_NEXT_HEAD, 0, R_TEMP, 0, R_CURR_STATE, 0);
EMIT_OP1(SLJIT_MOV, R_TEMP, 0, R_BEST_BEGIN, 0);
@ -1608,7 +1608,7 @@ static int compile_end_check(struct compiler_common *compiler_common, struct slj
EMIT_LABEL(label);
sljit_set_label(clear_states_jump, label);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_TEMP), sizeof(sljit_w), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, SLJIT_MEM1(R_TEMP), sizeof(sljit_sw), SLJIT_IMM, -1);
EMIT_OP1(SLJIT_MOV, R_TEMP, 0, R_BEST_BEGIN, 0);
EMIT_JUMP(jump, SLJIT_JUMP);
@ -1689,14 +1689,14 @@ static int compile_leave_fast_forward(struct compiler_common *compiler_common, s
return REGEX_NO_ERROR;
}
static int compile_newline_check(struct compiler_common *compiler_common, sljit_w ind)
static int compile_newline_check(struct compiler_common *compiler_common, sljit_sw ind)
{
struct sljit_compiler *compiler = compiler_common->compiler;
struct sljit_jump *jump1;
struct sljit_jump *jump2;
struct sljit_label *label;
sljit_w no_states;
sljit_w offset;
sljit_sw no_states;
sljit_sw offset;
/* Check whether a new-line character is found. */
EMIT_CMP(jump1, SLJIT_C_EQUAL, R_CURR_CHAR, 0, SLJIT_IMM, '\n');
@ -1728,15 +1728,15 @@ static SLJIT_INLINE void range_set_label(struct sljit_jump **range_jump_list, st
}
}
static sljit_w compile_range_check(struct compiler_common *compiler_common, sljit_w ind)
static sljit_sw compile_range_check(struct compiler_common *compiler_common, sljit_sw ind)
{
struct sljit_compiler *compiler = compiler_common->compiler;
struct stack_item *dfa_transitions = compiler_common->dfa_transitions;
struct sljit_jump **range_jump_list = compiler_common->range_jump_list;
int invert = dfa_transitions[ind].value;
struct sljit_label *label;
sljit_w no_states;
sljit_w offset;
sljit_sw no_states;
sljit_sw offset;
int init_range = 1, prev_value = 0;
ind++;
@ -1799,7 +1799,7 @@ static sljit_w compile_range_check(struct compiler_common *compiler_common, slji
/* Main compiler */
/* --------------------------------------------------------------------- */
#define TERM_OFFSET_OF(ind, offs) (((ind) * compiler_common.no_states + (offs)) * sizeof(sljit_w))
#define TERM_OFFSET_OF(ind, offs) (((ind) * compiler_common.no_states + (offs)) * sizeof(sljit_sw))
#define EMIT_OP1(type, arg1, arg2, arg3, arg4) \
CHECK(sljit_emit_op1(compiler_common.compiler, type, arg1, arg2, arg3, arg4))
@ -1833,7 +1833,7 @@ static sljit_w compile_range_check(struct compiler_common *compiler_common, slji
struct regex_machine* regex_compile(const regex_char_t *regex_string, int length, int re_flags, int *error)
{
struct compiler_common compiler_common;
sljit_w ind;
sljit_sw ind;
int error_code, done, suggest_fast_forward;
/* ID of an empty match (-1 if not reachable). */
int empty_match_id;
@ -2263,7 +2263,7 @@ struct regex_machine* regex_compile(const regex_char_t *regex_string, int length
compiler_common.machine->continue_match = sljit_generate_code(compiler_common.compiler);
#ifndef SLJIT_INDIRECT_CALL
compiler_common.machine->u.init_match = (void*)(sljit_w)sljit_get_label_addr(label);
compiler_common.machine->u.init_match = (void*)(sljit_sw)sljit_get_label_addr(label);
#else
sljit_set_function_context(&compiler_common.machine->u.init_match, &compiler_common.machine->context, sljit_get_label_addr(label), regex_compile);
#endif
@ -2325,19 +2325,19 @@ const char* regex_get_platform_name(void)
struct regex_match* regex_begin_match(struct regex_machine *machine)
{
sljit_w *ptr1;
sljit_w *ptr2;
sljit_w *end;
sljit_w *entry_addrs;
sljit_sw *ptr1;
sljit_sw *ptr2;
sljit_sw *end;
sljit_sw *entry_addrs;
struct regex_match *match = (struct regex_match*)SLJIT_MALLOC(sizeof(struct regex_match) + (machine->size * 2 - 1) * sizeof(sljit_w));
struct regex_match *match = (struct regex_match*)SLJIT_MALLOC(sizeof(struct regex_match) + (machine->size * 2 - 1) * sizeof(sljit_sw));
if (!match)
return NULL;
ptr1 = match->states;
ptr2 = match->states + machine->size;
end = ptr2;
entry_addrs = (sljit_w*)machine->entry_addrs;
entry_addrs = (sljit_sw*)machine->entry_addrs;
match->current = ptr1;
match->next = ptr2;
@ -2395,8 +2395,8 @@ struct regex_match* regex_begin_match(struct regex_machine *machine)
void regex_reset_match(struct regex_match *match)
{
struct regex_machine *machine = match->machine;
sljit_w current, ind;
sljit_w *current_ptr;
sljit_sw current, ind;
sljit_sw *current_ptr;
match->best_end = 0;
match->fast_quit = 0;
@ -2407,7 +2407,7 @@ void regex_reset_match(struct regex_match *match)
current = match->head;
current_ptr = match->current;
do {
ind = (current / sizeof(sljit_w)) + 1;
ind = (current / sizeof(sljit_sw)) + 1;
current = current_ptr[ind];
current_ptr[ind] = -1;
} while (current != 0);
@ -2428,7 +2428,7 @@ void regex_continue_match(struct regex_match *match, const regex_char_t *input_s
int regex_get_result(struct regex_match *match, int *end, int *id)
{
int flags = match->machine->flags;
sljit_w no_states;
sljit_sw no_states;
*end = match->best_end;
*id = match->best_id;
@ -2493,14 +2493,14 @@ int regex_is_match_finished(struct regex_match *match)
#ifdef REGEX_MATCH_VERBOSE
void regex_continue_match_debug(struct regex_match *match, const regex_char_t *input_string, int length)
{
sljit_w *ptr;
sljit_w *end;
sljit_w count;
sljit_sw *ptr;
sljit_sw *end;
sljit_sw count;
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
sljit_w current;
sljit_sw current;
#endif
sljit_w no_states = match->machine->no_states;
sljit_w len = match->machine->size;
sljit_sw no_states = match->machine->no_states;
sljit_sw len = match->machine->size;
while (length > 0) {
match->u.call_continue(match, input_string, 1);
@ -2568,10 +2568,10 @@ void regex_continue_match_debug(struct regex_match *match, const regex_char_t *i
current = match->head;
ptr = match->current;
while (current != 0) {
SLJIT_ASSERT(current >= 0 && current < len * sizeof(sljit_w));
SLJIT_ASSERT((current % (no_states * sizeof(sljit_w))) == 0);
SLJIT_ASSERT(current >= 0 && current < len * sizeof(sljit_sw));
SLJIT_ASSERT((current % (no_states * sizeof(sljit_sw))) == 0);
SLJIT_ASSERT(count > 0);
current = ptr[(current / sizeof(sljit_w)) + 1];
current = ptr[(current / sizeof(sljit_sw)) + 1];
count--;
}
SLJIT_ASSERT(count == 0);

View File

@ -24,10 +24,23 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Must be the first one. Must not depend on any other include. */
#include "regexJIT.h"
#include <stdio.h>
#if defined _WIN32 || defined _WIN64
#define COLOR_RED
#define COLOR_GREEN
#define COLOR_ARCH
#define COLOR_DEFAULT
#else
#define COLOR_RED "\33[31m"
#define COLOR_GREEN "\33[32m"
#define COLOR_ARCH "\33[33m"
#define COLOR_DEFAULT "\33[0m"
#endif
#ifdef REGEX_USE_8BIT_CHARS
#define S(str) str
#else
@ -90,7 +103,7 @@ struct test_case {
const regex_char_t *string; /* NULL : end of tests. */
};
void run_tests(struct test_case* test)
void run_tests(struct test_case* test, int verbose, int silent)
{
int error;
const regex_char_t *ptr;
@ -99,8 +112,12 @@ void run_tests(struct test_case* test)
int begin, end, id, finished;
int success = 0, fail = 0;
if (!verbose && !silent)
printf("Pass -v to enable verbose, -s to disable this hint.\n\n");
for ( ; test->string ; test++) {
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
if (verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
fail++;
if (test->pattern) {
@ -114,15 +131,21 @@ void run_tests(struct test_case* test)
machine = regex_compile(test->pattern, ptr - test->pattern, test->flags, &error);
if (error) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("ABORT: Error %d\n", error);
return;
}
if (!machine) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("ABORT: machine must be exists. Report this bug, please\n");
return;
}
}
else if (test->flags != 0) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("ABORT: flag must be 0 if no pattern\n");
return;
}
@ -134,6 +157,8 @@ void run_tests(struct test_case* test)
match = regex_begin_match(machine);
#ifdef REGEX_MATCH_VERBOSE
if (!match) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("ABORT: Not enough memory for matching\n");
regex_free_machine(machine);
return;
@ -143,10 +168,14 @@ void run_tests(struct test_case* test)
finished = regex_is_match_finished(match);
if (begin != test->begin || end != test->end || id != test->id) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("FAIL A: begin: %d != %d || end: %d != %d || id: %d != %d\n", test->begin, begin, test->end, end, test->id, id);
continue;
}
if (test->finished != -1 && test->finished != !!finished) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("FAIL A: finish check\n");
continue;
}
@ -159,26 +188,31 @@ void run_tests(struct test_case* test)
regex_free_match(match);
if (begin != test->begin || end != test->end || id != test->id) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("FAIL B: begin: %d != %d || end: %d != %d || id: %d != %d\n", test->begin, begin, test->end, end, test->id, id);
continue;
}
if (test->finished != -1 && test->finished != !!finished) {
if (!verbose)
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
printf("FAIL B: finish check\n");
continue;
}
printf("SUCCESS\n");
if (verbose)
printf("SUCCESS\n");
fail--;
success++;
}
if (machine)
regex_free_machine(machine);
printf("On %s: ", regex_get_platform_name());
printf("REGEX tests: On " COLOR_ARCH "%s" COLOR_DEFAULT ": ", regex_get_platform_name());
if (fail == 0)
printf("All tests are passed!\n");
printf("All tests are " COLOR_GREEN "PASSED" COLOR_DEFAULT "!\n");
else
printf("Successful test ratio: %d%%.\n", success * 100 / (success + fail));
printf("Successful test ratio: " COLOR_RED "%d%%" COLOR_DEFAULT ".\n", success * 100 / (success + fail));
}
/* Testing. */
@ -280,6 +314,8 @@ static struct test_case tests[] = {
int main(int argc, char* argv[])
{
int has_arg = (argc >= 2 && argv[1][0] == '-' && argv[1][2] == '\0');
/* verbose_test("a((b)((c|d))|)c|"); */
/* verbose_test("Xa{009,0010}Xb{,7}Xc{5,}Xd{,}Xe{1,}Xf{,1}X"); */
/* verbose_test("{3!}({3})({0!}){,"); */
@ -287,7 +323,6 @@ int main(int argc, char* argv[])
/* verbose_test("^a({2!})*b+(a|{1!}b)+d$"); */
/* verbose_test("((a|b|c)*(xy)+)+", "asbcxyxy"); */
run_tests(tests);
run_tests(tests, has_arg && argv[1][1] == 'v', has_arg && argv[1][1] == 's');
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
/* mips 32-bit arch dependent functions. */
static int load_immediate(struct sljit_compiler *compiler, int dst_ar, sljit_w imm)
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
{
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
@ -52,7 +52,7 @@ static int load_immediate(struct sljit_compiler *compiler, int dst_ar, sljit_w i
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
}
#define EMIT_SHIFT(op_imm, op_norm) \
#define EMIT_SHIFT(op_imm, op_v) \
if (flags & SRC2_IMM) { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
@ -61,20 +61,19 @@ static int load_immediate(struct sljit_compiler *compiler, int dst_ar, sljit_w i
} \
else { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_norm | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_norm | S(src2) | T(src1) | D(dst), DR(dst))); \
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
}
static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags,
int dst, int src1, sljit_w src2)
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_sw src2)
{
int overflow_ra = 0;
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
@ -137,30 +136,31 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
}
/* Nearly all instructions are unmovable in the following sequence. */
FAIL_IF(push_inst(compiler, ADDU_W | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
/* Check zero. */
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, ADDIU_W | SA(0) | T(dst) | IMM(-1), DR(dst)));
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
/* Loop for searching the highest bit. */
FAIL_IF(push_inst(compiler, ADDIU_W | S(dst) | T(dst) | IMM(1), DR(dst)));
FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
if (op & SLJIT_SET_E)
return push_inst(compiler, ADDU_W | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
return push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
#endif
return SLJIT_SUCCESS;
case SLJIT_ADD:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
FAIL_IF(push_inst(compiler, SRL | T(src1) | DA(TMP_EREG1) | SH_IMM(31), TMP_EREG1));
if (src2 < 0)
FAIL_IF(push_inst(compiler, XORI | SA(TMP_EREG1) | TA(TMP_EREG1) | IMM(1), TMP_EREG1));
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
if (op & SLJIT_SET_C) {
if (op & (SLJIT_SET_C | SLJIT_SET_O)) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
else {
@ -171,45 +171,28 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
if (op & SLJIT_SET_O) {
FAIL_IF(push_inst(compiler, SRL | T(dst) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
if (src2 < 0)
FAIL_IF(push_inst(compiler, XORI | SA(OVERFLOW_FLAG) | TA(OVERFLOW_FLAG) | IMM(1), OVERFLOW_FLAG));
}
}
else {
if (op & SLJIT_SET_O) {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(TMP_EREG1), TMP_EREG1));
FAIL_IF(push_inst(compiler, SRL | TA(TMP_EREG1) | DA(TMP_EREG1) | SH_IMM(31), TMP_EREG1));
if (src1 != dst)
overflow_ra = DR(src1);
else if (src2 != dst)
overflow_ra = DR(src2);
else {
/* Rare ocasion. */
FAIL_IF(push_inst(compiler, ADDU | S(src1) | TA(0) | DA(TMP_EREG2), TMP_EREG2));
overflow_ra = TMP_EREG2;
}
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & SLJIT_SET_C)
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
if (op & SLJIT_SET_O) {
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(overflow_ra) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, SRL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
}
}
/* a + b >= a | b (otherwise, the carry should be set to 1). */
if (op & SLJIT_SET_C)
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
if (op & SLJIT_SET_O)
return push_inst(compiler, MOVN | SA(0) | TA(TMP_EREG1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
return SLJIT_SUCCESS;
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SLL | TA(ULESS_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | SA(TMP_EREG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SLL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_ADDC:
if (flags & SRC2_IMM) {
@ -235,14 +218,13 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
if (!(op & SLJIT_SET_C))
return SLJIT_SUCCESS;
/* Set TMP_EREG2 (dst == 0) && (ULESS_FLAG == 1). */
FAIL_IF(push_inst(compiler, SLTIU | S(dst) | TA(TMP_EREG2) | IMM(1), TMP_EREG2));
FAIL_IF(push_inst(compiler, AND | SA(TMP_EREG2) | TA(ULESS_FLAG) | DA(TMP_EREG2), TMP_EREG2));
/* Set ULESS_FLAG (dst == 0) && (ULESS_FLAG == 1). */
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
/* Set carry flag. */
return push_inst(compiler, OR | SA(TMP_EREG2) | TA(TMP_EREG1) | DA(ULESS_FLAG), ULESS_FLAG);
return push_inst(compiler, OR | SA(ULESS_FLAG) | TA(TMP_EREG1) | DA(ULESS_FLAG), ULESS_FLAG);
case SLJIT_SUB:
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_S | SLJIT_SET_U)) || src2 == SIMM_MIN)) {
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_MIN)) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
@ -250,40 +232,25 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
FAIL_IF(push_inst(compiler, SRL | T(src1) | DA(TMP_EREG1) | SH_IMM(31), TMP_EREG1));
if (src2 < 0)
FAIL_IF(push_inst(compiler, XORI | SA(TMP_EREG1) | TA(TMP_EREG1) | IMM(1), TMP_EREG1));
if (src1 != dst)
overflow_ra = DR(src1);
else {
/* Rare ocasion. */
FAIL_IF(push_inst(compiler, ADDU | S(src1) | TA(0) | DA(TMP_EREG2), TMP_EREG2));
overflow_ra = TMP_EREG2;
}
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
if (op & SLJIT_SET_C)
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O) {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(TMP_EREG1), TMP_EREG1));
FAIL_IF(push_inst(compiler, SRL | TA(TMP_EREG1) | DA(TMP_EREG1) | SH_IMM(31), TMP_EREG1));
if (src1 != dst)
overflow_ra = DR(src1);
else {
/* Rare ocasion. */
FAIL_IF(push_inst(compiler, ADDU | S(src1) | TA(0) | DA(TMP_EREG2), TMP_EREG2));
overflow_ra = TMP_EREG2;
}
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_U | SLJIT_SET_C))
if (op & (SLJIT_SET_U | SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
if (op & SLJIT_SET_U)
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(UGREATER_FLAG), UGREATER_FLAG));
@ -292,16 +259,16 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(GREATER_FLAG), GREATER_FLAG));
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_C))
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_O) {
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(overflow_ra) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, SRL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
return push_inst(compiler, MOVZ | SA(0) | TA(TMP_EREG1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
}
return SLJIT_SUCCESS;
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SLL | TA(ULESS_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | SA(TMP_EREG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SRL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_SUBC:
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
@ -312,7 +279,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(TMP_EREG1) | IMM(-src2), TMP_EREG1));
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(TMP_EREG1) | IMM(src2), TMP_EREG1));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
@ -324,14 +291,10 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, MOVZ | SA(ULESS_FLAG) | T(dst) | DA(TMP_EREG1), TMP_EREG1));
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(TMP_EREG2), TMP_EREG2));
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, ADDU | SA(TMP_EREG1) | TA(0) | DA(ULESS_FLAG), ULESS_FLAG));
return SLJIT_SUCCESS;
return (op & SLJIT_SET_C) ? push_inst(compiler, OR | SA(TMP_EREG1) | TA(TMP_EREG2) | DA(ULESS_FLAG), ULESS_FLAG) : SLJIT_SUCCESS;
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM));
@ -378,7 +341,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
return SLJIT_SUCCESS;
}
static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int dst, sljit_w init_value)
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
@ -393,7 +356,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;

View File

@ -0,0 +1,469 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 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.
*/
/* mips 64-bit arch dependent functions. */
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
{
sljit_si shift = 32;
sljit_si shift2;
sljit_si inv = 0;
sljit_ins ins;
sljit_uw uimm;
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
if (imm < 0 && imm >= SIMM_MIN)
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
}
/* Zero extended number. */
uimm = imm;
if (imm < 0) {
uimm = ~imm;
inv = 1;
}
while (!(uimm & 0xff00000000000000l)) {
shift -= 8;
uimm <<= 8;
}
if (!(uimm & 0xf000000000000000l)) {
shift -= 4;
uimm <<= 4;
}
if (!(uimm & 0xc000000000000000l)) {
shift -= 2;
uimm <<= 2;
}
if ((sljit_sw)uimm < 0) {
uimm >>= 1;
shift += 1;
}
SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32));
if (inv)
uimm = ~uimm;
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
if (uimm & 0x0000ffff00000000l)
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar));
imm &= (1l << shift) - 1;
if (!(imm & ~0xffff)) {
ins = (shift == 32) ? DSLL32 : DSLL;
if (shift < 32)
ins |= SH_IMM(shift);
FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar));
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
}
/* Double shifts needs to be performed. */
uimm <<= 32;
shift2 = shift - 16;
while (!(uimm & 0xf000000000000000l)) {
shift2 -= 4;
uimm <<= 4;
}
if (!(uimm & 0xc000000000000000l)) {
shift2 -= 2;
uimm <<= 2;
}
if (!(uimm & 0x8000000000000000l)) {
shift2--;
uimm <<= 1;
}
SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16));
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar));
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar));
imm &= (1l << shift2) - 1;
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
}
#define SELECT_OP(a, b) \
(!(op & SLJIT_INT_OP) ? a : b)
#define EMIT_LOGICAL(op_imm, op_norm) \
if (flags & SRC2_IMM) { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
} \
else { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
}
#define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
if (flags & SRC2_IMM) { \
if (src2 >= 32) { \
SLJIT_ASSERT(!(op & SLJIT_INT_OP)); \
ins = op_dimm32; \
src2 -= 32; \
} \
else \
ins = (op & SLJIT_INT_OP) ? op_imm : op_dimm; \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
} \
else { \
ins = (op & SLJIT_INT_OP) ? op_v : op_dv; \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
}
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_sw src2)
{
sljit_ins ins;
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
return SLJIT_SUCCESS;
case SLJIT_MOV_UB:
case SLJIT_MOV_SB:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SB) {
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
}
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_MOV_UH:
case SLJIT_MOV_SH:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SH) {
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
}
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_MOV_UI:
SLJIT_ASSERT(!(op & SLJIT_INT_OP));
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
case SLJIT_MOV_SI:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
case SLJIT_NOT:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
return SLJIT_SUCCESS;
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64)
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
#else
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
}
/* Nearly all instructions are unmovable in the following sequence. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
/* Check zero. */
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_INT_OP) ? 32 : 64), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
/* Loop for searching the highest bit. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
if (op & SLJIT_SET_E)
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
#endif
return SLJIT_SUCCESS;
case SLJIT_ADD:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O)) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
else {
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
}
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(TMP_EREG1), TMP_EREG1));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
/* a + b >= a | b (otherwise, the carry should be set to 1). */
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(ULESS_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | SA(TMP_EREG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SELECT_OP(DSRL32, SLL) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_ADDC:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(TMP_EREG1) | IMM(src2), TMP_EREG1));
else {
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(TMP_EREG1) | IMM(src2), TMP_EREG1));
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(TMP_EREG1) | DA(TMP_EREG1), TMP_EREG1));
}
}
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
} else {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(TMP_EREG1), TMP_EREG1));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(TMP_EREG1) | DA(TMP_EREG1), TMP_EREG1));
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
if (!(op & SLJIT_SET_C))
return SLJIT_SUCCESS;
/* Set ULESS_FLAG (dst == 0) && (ULESS_FLAG == 1). */
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
/* Set carry flag. */
return push_inst(compiler, OR | SA(ULESS_FLAG) | TA(TMP_EREG1) | DA(ULESS_FLAG), ULESS_FLAG);
case SLJIT_SUB:
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_MIN)) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
}
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(TMP_EREG1), TMP_EREG1));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(TMP_EREG1), TMP_EREG1));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_U | SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
if (op & SLJIT_SET_U)
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(UGREATER_FLAG), UGREATER_FLAG));
if (op & SLJIT_SET_S) {
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(LESS_FLAG), LESS_FLAG));
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(GREATER_FLAG), GREATER_FLAG));
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(ULESS_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | SA(TMP_EREG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_SUBC:
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
}
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(TMP_EREG1) | IMM(src2), TMP_EREG1));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(TMP_EREG1), TMP_EREG1));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(TMP_EREG2), TMP_EREG2));
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
return (op & SLJIT_SET_C) ? push_inst(compiler, OR | SA(TMP_EREG1) | TA(TMP_EREG2) | DA(ULESS_FLAG), ULESS_FLAG) : SLJIT_SUCCESS;
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM));
if (!(op & SLJIT_SET_O)) {
#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64)
if (op & SLJIT_INT_OP)
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
return push_inst(compiler, MFLO | D(dst), DR(dst));
#else
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
return push_inst(compiler, MFLO | D(dst), DR(dst));
#endif
}
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
FAIL_IF(push_inst(compiler, MFHI | DA(TMP_EREG1), TMP_EREG1));
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(TMP_EREG2) | SH_IMM(31), TMP_EREG2));
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(TMP_EREG1) | TA(TMP_EREG2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
case SLJIT_AND:
EMIT_LOGICAL(ANDI, AND);
return SLJIT_SUCCESS;
case SLJIT_OR:
EMIT_LOGICAL(ORI, OR);
return SLJIT_SUCCESS;
case SLJIT_XOR:
EMIT_LOGICAL(XORI, XOR);
return SLJIT_SUCCESS;
case SLJIT_SHL:
EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV);
return SLJIT_SUCCESS;
case SLJIT_LSHR:
EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV);
return SLJIT_SUCCESS;
case SLJIT_ASHR:
EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV);
return SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst)));
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((new_addr >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
inst[5] = (inst[5] & 0xffff0000) | (new_addr & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 6);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
inst[5] = (inst[5] & 0xffff0000) | (new_constant & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 6);
}

File diff suppressed because it is too large Load Diff

View File

@ -26,13 +26,13 @@
/* ppc 32-bit arch dependent functions. */
static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm)
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
{
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | S(ZERO_REG) | A(reg) | IMM(imm));
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
@ -41,13 +41,14 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm)
#define INS_CLEAR_LEFT(dst, src, from) \
(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags,
int dst, int src1, int src2)
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_si src2)
{
switch (op) {
case SLJIT_MOV:
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1);
if (dst != src2)
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
@ -119,7 +120,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
case SLJIT_ADDC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | S(0)));
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
return push_inst(compiler, MTXER | S(0));
}
@ -154,7 +155,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
case SLJIT_SUBC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | S(0)));
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
return push_inst(compiler, MTXER | S(0));
}
@ -227,19 +228,23 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_ASHR:
if (flags & ALT_FORM3)
FAIL_IF(push_inst(compiler, MFXER | D(0)));
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
compiler->imm &= 0x1f;
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)));
}
return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
else
FAIL_IF(push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2)));
return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int reg, sljit_w init_value)
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
@ -254,7 +259,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;

View File

@ -41,7 +41,7 @@
#define PUSH_RLDICR(reg, shift) \
push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm)
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
{
sljit_uw tmp;
sljit_uw shift;
@ -52,9 +52,9 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm)
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | S(ZERO_REG) | A(reg) | IMM(imm));
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
if (imm <= SLJIT_W(0x7fffffff) && imm >= SLJIT_W(-0x80000000)) {
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
}
@ -145,11 +145,12 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm)
src1 = TMP_REG1; \
}
static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags,
int dst, int src1, int src2)
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_si src2)
{
switch (op) {
case SLJIT_MOV:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1);
if (dst != src2)
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
@ -240,7 +241,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
case SLJIT_ADDC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | S(0)));
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
return push_inst(compiler, MTXER | S(0));
}
@ -277,7 +278,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
case SLJIT_SUBC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | S(0)));
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
return push_inst(compiler, MTXER | S(0));
}
@ -349,9 +350,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
}
}
if (flags & ALT_FORM2)
return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
return push_inst(compiler, SLD | RC(flags) | S(src1) | A(dst) | B(src2));
return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_LSHR:
if (flags & ALT_FORM1) {
@ -365,32 +364,32 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
}
}
if (flags & ALT_FORM2)
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
return push_inst(compiler, SRD | RC(flags) | S(src1) | A(dst) | B(src2));
return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_ASHR:
if (flags & ALT_FORM3)
FAIL_IF(push_inst(compiler, MFXER | D(0)));
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
if (flags & ALT_FORM2) {
compiler->imm &= 0x1f;
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)));
}
else {
compiler->imm &= 0x3f;
return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4));
FAIL_IF(push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4)));
}
}
if (flags & ALT_FORM2)
return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
return push_inst(compiler, SRAD | RC(flags) | S(src1) | A(dst) | B(src2));
else
FAIL_IF(push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2)));
return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int reg, sljit_w init_value)
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
@ -410,7 +409,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad
SLJIT_CACHE_FLUSH(inst, inst + 5);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;

View File

@ -24,7 +24,7 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static int load_immediate(struct sljit_compiler *compiler, int dst, sljit_w imm)
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst, sljit_sw imm)
{
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
@ -35,8 +35,8 @@ static int load_immediate(struct sljit_compiler *compiler, int dst, sljit_w imm)
#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags,
int dst, int src1, sljit_w src2)
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_sw src2)
{
SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
@ -44,6 +44,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
case SLJIT_MOV:
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
@ -138,7 +139,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op,
return SLJIT_SUCCESS;
}
static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int dst, sljit_w init_value)
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si 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));
@ -153,7 +154,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;

View File

@ -35,6 +35,30 @@ typedef sljit_ui sljit_ins;
static void sparc_cache_flush(sljit_ins *from, sljit_ins *to)
{
#if defined(__SUNPRO_C) && __SUNPRO_C < 0x590
__asm (
/* if (from == to) return */
"cmp %i0, %i1\n"
"be .leave\n"
"nop\n"
/* loop until from >= to */
".mainloop:\n"
"flush %i0\n"
"add %i0, 8, %i0\n"
"cmp %i0, %i1\n"
"bcs .mainloop\n"
"nop\n"
/* The comparison was done above. */
"bne .leave\n"
/* nop is not necessary here, since the
sub operation has no side effect. */
"sub %i0, 4, %i0\n"
"flush %i0\n"
".leave:"
);
#else
if (SLJIT_UNLIKELY(from == to))
return;
@ -49,12 +73,13 @@ static void sparc_cache_flush(sljit_ins *from, sljit_ins *to)
if (from == to) {
/* Flush the last word. */
to --;
from --;
__asm__ volatile (
"flush %0\n"
: : "r"(to)
: : "r"(from)
);
}
#endif
}
/* TMP_REG2 is not used by getput_arg */
@ -62,10 +87,10 @@ static void sparc_cache_flush(sljit_ins *from, sljit_ins *to)
#define TMP_REG2 (SLJIT_NO_REGISTERS + 2)
#define TMP_REG3 (SLJIT_NO_REGISTERS + 3)
#define TMP_REG4 (SLJIT_NO_REGISTERS + 4)
#define LINK_REG (SLJIT_NO_REGISTERS + 5)
#define TMP_LINK (SLJIT_NO_REGISTERS + 5)
#define TMP_FREG1 ((SLJIT_FLOAT_REG4 + 1) << 1)
#define TMP_FREG2 ((SLJIT_FLOAT_REG4 + 2) << 1)
#define TMP_FREG1 (0)
#define TMP_FREG2 ((SLJIT_FLOAT_REG6 + 1) << 1)
static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 7] = {
0, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20, 14, 1, 24, 25, 26, 15
@ -98,12 +123,17 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 7] = {
#define CALL (OPC1(0x1))
#define FABSS (OPC1(0x2) | OPC3(0x34) | DOP(0x09))
#define FADDD (OPC1(0x2) | OPC3(0x34) | DOP(0x42))
#define FADDS (OPC1(0x2) | OPC3(0x34) | DOP(0x41))
#define FCMPD (OPC1(0x2) | OPC3(0x35) | DOP(0x52))
#define FCMPS (OPC1(0x2) | OPC3(0x35) | DOP(0x51))
#define FDIVD (OPC1(0x2) | OPC3(0x34) | DOP(0x4e))
#define FDIVS (OPC1(0x2) | OPC3(0x34) | DOP(0x4d))
#define FMOVS (OPC1(0x2) | OPC3(0x34) | DOP(0x01))
#define FMULD (OPC1(0x2) | OPC3(0x34) | DOP(0x4a))
#define FMULS (OPC1(0x2) | OPC3(0x34) | DOP(0x49))
#define FNEGS (OPC1(0x2) | OPC3(0x34) | DOP(0x05))
#define FSUBD (OPC1(0x2) | OPC3(0x34) | DOP(0x46))
#define FSUBS (OPC1(0x2) | OPC3(0x34) | DOP(0x45))
#define JMPL (OPC1(0x2) | OPC3(0x38))
#define NOP (OPC1(0x0) | OPC2(0x04))
#define OR (OPC1(0x2) | OPC3(0x02))
@ -146,12 +176,13 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 7] = {
/* dest_reg is the absolute name of the register
Useful for reordering instructions in the delay slot. */
static int push_inst(struct sljit_compiler *compiler, sljit_ins ins, int delay_slot)
static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_si delay_slot)
{
sljit_ins *ptr;
SLJIT_ASSERT((delay_slot & DST_INS_MASK) == UNMOVABLE_INS
|| (delay_slot & DST_INS_MASK) == MOVABLE_INS
|| (delay_slot & DST_INS_MASK) == ((ins >> 25) & 0x1f));
sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
*ptr = ins;
compiler->size++;
@ -159,9 +190,9 @@ static int push_inst(struct sljit_compiler *compiler, sljit_ins ins, int delay_s
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_ins* optimize_jump(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
{
sljit_w diff;
sljit_sw diff;
sljit_uw target_addr;
sljit_ins *inst;
sljit_ins saved_inst;
@ -200,7 +231,7 @@ static SLJIT_INLINE sljit_ins* optimize_jump(struct sljit_jump *jump, sljit_ins
inst--;
if (jump->flags & IS_MOVABLE) {
diff = ((sljit_w)target_addr - (sljit_w)(inst - 1)) >> 2;
diff = ((sljit_sw)target_addr - (sljit_sw)(inst - 1)) >> 2;
if (diff <= MAX_DISP && diff >= MIN_DISP) {
jump->flags |= PATCH_B;
inst--;
@ -217,7 +248,7 @@ static SLJIT_INLINE sljit_ins* optimize_jump(struct sljit_jump *jump, sljit_ins
}
}
diff = ((sljit_w)target_addr - (sljit_w)(inst)) >> 2;
diff = ((sljit_sw)target_addr - (sljit_sw)(inst)) >> 2;
if (diff <= MAX_DISP && diff >= MIN_DISP) {
jump->flags |= PATCH_B;
if (jump->flags & IS_COND)
@ -280,7 +311,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
#else
jump->addr = (sljit_uw)(code_ptr - 6);
#endif
code_ptr = optimize_jump(jump, code_ptr, code);
code_ptr = detect_jump_type(jump, code_ptr, code);
jump = jump->next;
}
if (const_ && const_->addr == word_count) {
@ -304,7 +335,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
SLJIT_ASSERT(!label);
SLJIT_ASSERT(!jump);
SLJIT_ASSERT(!const_);
SLJIT_ASSERT(code_ptr - code <= (int)compiler->size);
SLJIT_ASSERT(code_ptr - code <= (sljit_si)compiler->size);
jump = compiler->jumps;
while (jump) {
@ -313,14 +344,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
buf_ptr = (sljit_ins*)jump->addr;
if (jump->flags & PATCH_CALL) {
addr = (sljit_w)(addr - jump->addr) >> 2;
SLJIT_ASSERT((sljit_w)addr <= 0x1fffffff && (sljit_w)addr >= -0x20000000);
addr = (sljit_sw)(addr - jump->addr) >> 2;
SLJIT_ASSERT((sljit_sw)addr <= 0x1fffffff && (sljit_sw)addr >= -0x20000000);
buf_ptr[0] = CALL | (addr & 0x3fffffff);
break;
}
if (jump->flags & PATCH_B) {
addr = (sljit_w)(addr - jump->addr) >> 2;
SLJIT_ASSERT((sljit_w)addr <= MAX_DISP && (sljit_w)addr >= MIN_DISP);
addr = (sljit_sw)(addr - jump->addr) >> 2;
SLJIT_ASSERT((sljit_sw)addr <= MAX_DISP && (sljit_sw)addr >= MIN_DISP);
buf_ptr[0] = (buf_ptr[0] & ~DISP_MASK) | (addr & DISP_MASK);
break;
}
@ -338,7 +369,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_size = compiler->size * sizeof(sljit_ins);
compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
SLJIT_CACHE_FLUSH(code, code_ptr);
return code;
}
@ -362,15 +393,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
#define WRITE_BACK 0x00020
#define ARG_TEST 0x00040
#define CUMULATIVE_OP 0x00080
#define IMM_OP 0x00100
#define SRC2_IMM 0x00200
#define ALT_KEEP_CACHE 0x00080
#define CUMULATIVE_OP 0x00100
#define IMM_OP 0x00200
#define SRC2_IMM 0x00400
#define REG_DEST 0x00800
#define REG2_SOURCE 0x01000
#define SLOW_SRC1 0x02000
#define SLOW_SRC2 0x04000
#define SLOW_DEST 0x08000
#define REG_DEST 0x00400
#define REG2_SOURCE 0x00800
#define SLOW_SRC1 0x01000
#define SLOW_SRC2 0x02000
#define SLOW_DEST 0x04000
/* SET_FLAGS (0x10 << 19) also belong here! */
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
@ -379,18 +412,18 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
#include "sljitNativeSPARC_64.c"
#endif
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size)
{
CHECK_ERROR();
check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size);
check_sljit_emit_enter(compiler, args, scratches, saveds, local_size);
compiler->temporaries = temporaries;
compiler->scratches = scratches;
compiler->saveds = saveds;
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
compiler->logical_local_size = local_size;
#endif
local_size += 23 * sizeof(sljit_w);
local_size += 23 * sizeof(sljit_sw);
local_size = (local_size + 7) & ~0x7;
compiler->local_size = local_size;
@ -412,33 +445,33 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size)
{
CHECK_ERROR_VOID();
check_sljit_set_context(compiler, args, temporaries, saveds, local_size);
check_sljit_set_context(compiler, args, scratches, saveds, local_size);
compiler->temporaries = temporaries;
compiler->scratches = scratches;
compiler->saveds = saveds;
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
compiler->logical_local_size = local_size;
#endif
local_size += 23 * sizeof(sljit_w);
local_size += 23 * sizeof(sljit_sw);
compiler->local_size = (local_size + 7) & ~0x7;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
{
CHECK_ERROR();
check_sljit_emit_return(compiler, op, src, srcw);
if (op != SLJIT_MOV || !(src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS)) {
if (op != SLJIT_MOV || !FAST_IS_REG(src)) {
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
src = SLJIT_TEMPORARY_REG1;
src = SLJIT_SCRATCH_REG1;
}
FAIL_IF(push_inst(compiler, JMPL | D(0) | S1A(31) | IMM(8), UNMOVABLE_INS));
return push_inst(compiler, RESTORE | D(SLJIT_TEMPORARY_REG1) | S1(src) | S2(0), UNMOVABLE_INS);
return push_inst(compiler, RESTORE | D(SLJIT_SCRATCH_REG1) | S1(src) | S2(0), UNMOVABLE_INS);
}
/* --------------------------------------------------------------------- */
@ -451,7 +484,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler,
#define ARCH_32_64(a, b) b
#endif
static SLJIT_CONST sljit_ins data_transfer_insts[16 + 2] = {
static SLJIT_CONST sljit_ins data_transfer_insts[16 + 4] = {
/* u w s */ ARCH_32_64(OPC1(3) | OPC3(0x04) /* stw */, OPC1(3) | OPC3(0x0e) /* stx */),
/* u w l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x0b) /* ldx */),
/* u b s */ OPC1(3) | OPC3(0x05) /* stb */,
@ -472,24 +505,26 @@ static SLJIT_CONST sljit_ins data_transfer_insts[16 + 2] = {
/* d s */ OPC1(3) | OPC3(0x27),
/* d l */ OPC1(3) | OPC3(0x23),
/* s s */ OPC1(3) | OPC3(0x24),
/* s l */ OPC1(3) | OPC3(0x20),
};
#undef ARCH_32_64
/* Can perform an operation using at most 1 instruction. */
static int getput_arg_fast(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw)
static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
{
SLJIT_ASSERT(arg & SLJIT_MEM);
if (!(flags & WRITE_BACK)) {
if ((!(arg & 0xf0) && argw <= SIMM_MAX && argw >= SIMM_MIN)
|| ((arg & 0xf0) && (argw & 0x3) == 0)) {
if (!(flags & WRITE_BACK) || !(arg & REG_MASK)) {
if ((!(arg & OFFS_REG_MASK) && argw <= SIMM_MAX && argw >= SIMM_MIN)
|| ((arg & OFFS_REG_MASK) && (argw & 0x3) == 0)) {
/* Works for both absoulte and relative addresses (immediate case). */
if (SLJIT_UNLIKELY(flags & ARG_TEST))
return 1;
FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK]
| ((flags & MEM_MASK) <= GPR_REG ? D(reg) : DA(reg))
| S1(arg & 0xf) | ((arg & 0xf0) ? S2((arg >> 4) & 0xf) : IMM(argw)),
| S1(arg & REG_MASK) | ((arg & OFFS_REG_MASK) ? S2(OFFS_REG(arg)) : IMM(argw)),
((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? DR(reg) : MOVABLE_INS));
return -1;
}
@ -500,16 +535,16 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int flags, int reg,
/* See getput_arg below.
Note: can_cache is called only for binary operators. Those
operators always uses word arguments without write back. */
static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw)
static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
{
SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
/* Simple operation except for updates. */
if (arg & 0xf0) {
if (arg & OFFS_REG_MASK) {
argw &= 0x3;
SLJIT_ASSERT(argw);
next_argw &= 0x3;
if ((arg & 0xf0) == (next_arg & 0xf0) && argw == next_argw)
if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == next_argw)
return 1;
return 0;
}
@ -520,9 +555,9 @@ static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw)
}
/* Emit the necessary instructions. See can_cache above. */
static int getput_arg(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw, int next_arg, sljit_w next_argw)
static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw)
{
int base, arg2, delay_slot;
sljit_si base, arg2, delay_slot;
sljit_ins dest;
SLJIT_ASSERT(arg & SLJIT_MEM);
@ -531,25 +566,25 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg, int a
next_argw = 0;
}
base = arg & 0xf;
if (SLJIT_UNLIKELY(arg & 0xf0)) {
base = arg & REG_MASK;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
argw &= 0x3;
SLJIT_ASSERT(argw != 0);
/* Using the cache. */
if (((SLJIT_MEM | (arg & 0xf0)) == compiler->cache_arg) && (argw == compiler->cache_argw))
if (((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) && (argw == compiler->cache_argw))
arg2 = TMP_REG3;
else {
if ((arg & 0xf0) == (next_arg & 0xf0) && argw == (next_argw & 0x3)) {
compiler->cache_arg = SLJIT_MEM | (arg & 0xf0);
if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == (next_argw & 0x3)) {
compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
compiler->cache_argw = argw;
arg2 = TMP_REG3;
}
else if ((flags & LOAD_DATA) && ((flags & MEM_MASK) <= GPR_REG) && reg != base && (reg << 4) != (arg & 0xf0))
else if ((flags & LOAD_DATA) && ((flags & MEM_MASK) <= GPR_REG) && reg != base && reg != OFFS_REG(arg))
arg2 = reg;
else /* It must be a mov operation, so tmp1 must be free to use. */
arg2 = TMP_REG1;
FAIL_IF(push_inst(compiler, SLL_W | D(arg2) | S1((arg >> 4) & 0xf) | IMM_ARG | argw, DR(arg2)));
FAIL_IF(push_inst(compiler, SLL_W | D(arg2) | S1(OFFS_REG(arg)) | IMM_ARG | argw, DR(arg2)));
}
}
else {
@ -584,7 +619,7 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg, int a
return push_inst(compiler, ADD | D(base) | S1(base) | S2(arg2), DR(base));
}
static SLJIT_INLINE int emit_op_mem(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw)
static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw)
{
if (getput_arg_fast(compiler, flags, reg, arg, argw))
return compiler->error;
@ -593,40 +628,42 @@ static SLJIT_INLINE int emit_op_mem(struct sljit_compiler *compiler, int flags,
return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
}
static SLJIT_INLINE int emit_op_mem2(struct sljit_compiler *compiler, int flags, int reg, int arg1, sljit_w arg1w, int arg2, sljit_w arg2w)
static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w)
{
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
return compiler->error;
return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
}
static int emit_op(struct sljit_compiler *compiler, int op, int flags,
int dst, sljit_w dstw,
int src1, sljit_w src1w,
int src2, sljit_w src2w)
static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_sw dstw,
sljit_si src1, sljit_sw src1w,
sljit_si src2, sljit_sw src2w)
{
/* arg1 goes to TMP_REG1 or src reg
arg2 goes to TMP_REG2, imm or src reg
TMP_REG3 can be used for caching
result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
int dst_r = TMP_REG2;
int src1_r;
sljit_w src2_r = 0;
int sugg_src2_r = TMP_REG2;
sljit_si dst_r = TMP_REG2;
sljit_si src1_r;
sljit_sw src2_r = 0;
sljit_si sugg_src2_r = TMP_REG2;
compiler->cache_arg = 0;
compiler->cache_argw = 0;
if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REG3) {
dst_r = dst;
flags |= REG_DEST;
if (GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI)
sugg_src2_r = dst_r;
if (!(flags & ALT_KEEP_CACHE)) {
compiler->cache_arg = 0;
compiler->cache_argw = 0;
}
else if (dst == SLJIT_UNUSED) {
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
return SLJIT_SUCCESS;
}
else if (FAST_IS_REG(dst)) {
dst_r = dst;
flags |= REG_DEST;
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
sugg_src2_r = dst_r;
}
else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
flags |= SLOW_DEST;
@ -652,7 +689,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags,
}
/* Source 1. */
if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= TMP_REG3)
if (FAST_IS_REG(src1))
src1_r = src1;
else if (src1 & SLJIT_IMM) {
if (src1w) {
@ -671,20 +708,23 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags,
}
/* Source 2. */
if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REG3) {
if (FAST_IS_REG(src2)) {
src2_r = src2;
flags |= REG2_SOURCE;
if (!(flags & REG_DEST) && GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI)
if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
dst_r = src2_r;
}
else if (src2 & SLJIT_IMM) {
if (!(flags & SRC2_IMM)) {
if (src2w || (GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI)) {
if (src2w) {
FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
src2_r = sugg_src2_r;
}
else
else {
src2_r = 0;
if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) && (dst & SLJIT_MEM))
dst_r = 0;
}
}
}
else {
@ -724,7 +764,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags,
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op)
{
CHECK_ERROR();
check_sljit_emit_op0(compiler, op);
@ -738,8 +778,8 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int
case SLJIT_UMUL:
case SLJIT_SMUL:
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
FAIL_IF(push_inst(compiler, (op == SLJIT_UMUL ? UMUL : SMUL) | D(SLJIT_TEMPORARY_REG1) | S1(SLJIT_TEMPORARY_REG1) | S2(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG1)));
return push_inst(compiler, RDY | D(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG2));
FAIL_IF(push_inst(compiler, (op == SLJIT_UMUL ? UMUL : SMUL) | D(SLJIT_SCRATCH_REG1) | S1(SLJIT_SCRATCH_REG1) | S2(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG1)));
return push_inst(compiler, RDY | D(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG2));
#else
#error "Implementation required"
#endif
@ -749,13 +789,13 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int
if (op == SLJIT_UDIV)
FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS));
else {
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_TEMPORARY_REG1) | IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_SCRATCH_REG1) | IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS));
}
FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_TEMPORARY_REG1), DR(TMP_REG2)));
FAIL_IF(push_inst(compiler, (op == SLJIT_UDIV ? UDIV : SDIV) | D(SLJIT_TEMPORARY_REG1) | S1(SLJIT_TEMPORARY_REG1) | S2(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG1)));
FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_TEMPORARY_REG2) | S1(SLJIT_TEMPORARY_REG1) | S2(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG2)));
FAIL_IF(push_inst(compiler, SUB | D(SLJIT_TEMPORARY_REG2) | S1(TMP_REG2) | S2(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG2)));
FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_SCRATCH_REG1), DR(TMP_REG2)));
FAIL_IF(push_inst(compiler, (op == SLJIT_UDIV ? UDIV : SDIV) | D(SLJIT_SCRATCH_REG1) | S1(SLJIT_SCRATCH_REG1) | S2(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG1)));
FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_SCRATCH_REG2) | S1(SLJIT_SCRATCH_REG1) | S2(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG2)));
FAIL_IF(push_inst(compiler, SUB | D(SLJIT_SCRATCH_REG2) | S1(TMP_REG2) | S2(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG2)));
return SLJIT_SUCCESS;
#else
#error "Implementation required"
@ -765,22 +805,21 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op,
int dst, sljit_w dstw,
int src, sljit_w srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op,
sljit_si dst, sljit_sw dstw,
sljit_si src, sljit_sw srcw)
{
int flags = GET_FLAGS(op) ? SET_FLAGS : 0;
sljit_si flags = GET_FLAGS(op) ? SET_FLAGS : 0;
CHECK_ERROR();
check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw);
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src, srcw);
SLJIT_COMPILE_ASSERT(SLJIT_MOV + 7 == SLJIT_MOVU, movu_offset);
op = GET_OPCODE(op);
switch (op) {
case SLJIT_MOV:
case SLJIT_MOV_P:
return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_MOV_UI:
@ -790,18 +829,19 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int
return emit_op(compiler, SLJIT_MOV_SI, flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_MOV_UB:
return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
case SLJIT_MOV_SB:
return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
case SLJIT_MOV_UH:
return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
case SLJIT_MOV_SH:
return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
case SLJIT_MOVU:
case SLJIT_MOVU_P:
return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_MOVU_UI:
@ -811,16 +851,16 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int
return emit_op(compiler, SLJIT_MOV_SI, flags | INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_MOVU_UB:
return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw);
case SLJIT_MOVU_SB:
return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw);
case SLJIT_MOVU_UH:
return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw);
case SLJIT_MOVU_SH:
return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw);
return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw);
case SLJIT_NOT:
case SLJIT_CLZ:
@ -833,12 +873,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op,
int dst, sljit_w dstw,
int src1, sljit_w src1w,
int src2, sljit_w src2w)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op,
sljit_si dst, sljit_sw dstw,
sljit_si src1, sljit_sw src1w,
sljit_si src2, sljit_sw src2w)
{
int flags = GET_FLAGS(op) ? SET_FLAGS : 0;
sljit_si flags = GET_FLAGS(op) ? SET_FLAGS : 0;
CHECK_ERROR();
check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w);
@ -875,14 +915,20 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg)
{
check_sljit_get_register_index(reg);
return reg_map[reg];
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, int size)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg)
{
check_sljit_get_float_register_index(reg);
return reg << 1;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_si size)
{
CHECK_ERROR();
check_sljit_emit_op_custom(compiler, instruction, size);
@ -895,84 +941,94 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile
/* Floating point operators */
/* --------------------------------------------------------------------- */
SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void)
{
#ifdef SLJIT_IS_FPU_AVAILABLE
return SLJIT_IS_FPU_AVAILABLE;
#else
/* Available by default. */
return 1;
#endif
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op,
int dst, sljit_w dstw,
int src, sljit_w srcw)
#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_SINGLE_OP) >> 7))
#define SELECT_FOP(op, single, double) ((op & SLJIT_SINGLE_OP) ? single : double)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op,
sljit_si dst, sljit_sw dstw,
sljit_si src, sljit_sw srcw)
{
int dst_fr;
sljit_si dst_fr;
CHECK_ERROR();
check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw);
SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
compiler->cache_arg = 0;
compiler->cache_argw = 0;
if (GET_OPCODE(op) == SLJIT_FCMP) {
if (dst > SLJIT_FLOAT_REG4) {
FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, dst, dstw, src, srcw));
if (GET_OPCODE(op) == SLJIT_CMPD) {
if (dst & SLJIT_MEM) {
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, dst, dstw, src, srcw));
dst = TMP_FREG1;
}
else
dst <<= 1;
if (src > SLJIT_FLOAT_REG4) {
FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, src, srcw, 0, 0));
if (src & SLJIT_MEM) {
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src, srcw, 0, 0));
src = TMP_FREG2;
}
else
src <<= 1;
return push_inst(compiler, FCMPD | S1A(dst) | S2A(src), FCC_IS_SET | MOVABLE_INS);
return push_inst(compiler, SELECT_FOP(op, FCMPS, FCMPD) | S1A(dst) | S2A(src), FCC_IS_SET | MOVABLE_INS);
}
dst_fr = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : (dst << 1);
dst_fr = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG1;
if (src > SLJIT_FLOAT_REG4) {
FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, dst_fr, src, srcw, dst, dstw));
if (src & SLJIT_MEM) {
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_fr, src, srcw, dst, dstw));
src = dst_fr;
}
else
src <<= 1;
switch (op) {
case SLJIT_FMOV:
switch (GET_OPCODE(op)) {
case SLJIT_MOVD:
if (src != dst_fr && dst_fr != TMP_FREG1) {
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_fr) | S2A(src), MOVABLE_INS));
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_fr | 1) | S2A(src | 1), MOVABLE_INS));
if (!(op & SLJIT_SINGLE_OP))
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_fr | 1) | S2A(src | 1), MOVABLE_INS));
}
break;
case SLJIT_FNEG:
case SLJIT_NEGD:
FAIL_IF(push_inst(compiler, FNEGS | DA(dst_fr) | S2A(src), MOVABLE_INS));
if (dst_fr != src)
if (dst_fr != src && !(op & SLJIT_SINGLE_OP))
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_fr | 1) | S2A(src | 1), MOVABLE_INS));
break;
case SLJIT_FABS:
case SLJIT_ABSD:
FAIL_IF(push_inst(compiler, FABSS | DA(dst_fr) | S2A(src), MOVABLE_INS));
if (dst_fr != src)
if (dst_fr != src && !(op & SLJIT_SINGLE_OP))
FAIL_IF(push_inst(compiler, FMOVS | DA(dst_fr | 1) | S2A(src | 1), MOVABLE_INS));
break;
}
if (dst_fr == TMP_FREG1) {
if (op == SLJIT_FMOV)
if (GET_OPCODE(op) == SLJIT_MOVD)
dst_fr = src;
FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA, dst_fr, dst, dstw, 0, 0));
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), dst_fr, dst, dstw, 0, 0));
}
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op,
int dst, sljit_w dstw,
int src1, sljit_w src1w,
int src2, sljit_w src2w)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(struct sljit_compiler *compiler, sljit_si op,
sljit_si dst, sljit_sw dstw,
sljit_si src1, sljit_sw src1w,
sljit_si src2, sljit_sw src2w)
{
int dst_fr, flags = 0;
sljit_si dst_fr, flags = 0;
CHECK_ERROR();
check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w);
@ -980,10 +1036,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in
compiler->cache_arg = 0;
compiler->cache_argw = 0;
dst_fr = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG2 : (dst << 1);
dst_fr = FAST_IS_REG(dst) ? (dst << 1) : TMP_FREG2;
if (src1 > SLJIT_FLOAT_REG4) {
if (getput_arg_fast(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src1, src1w)) {
if (src1 & SLJIT_MEM) {
if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) {
FAIL_IF(compiler->error);
src1 = TMP_FREG1;
} else
@ -992,8 +1048,8 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in
else
src1 <<= 1;
if (src2 > SLJIT_FLOAT_REG4) {
if (getput_arg_fast(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, src2, src2w)) {
if (src2 & SLJIT_MEM) {
if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) {
FAIL_IF(compiler->error);
src2 = TMP_FREG2;
} else
@ -1004,81 +1060,86 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in
if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
FAIL_IF(getput_arg(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w));
FAIL_IF(getput_arg(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
}
else {
FAIL_IF(getput_arg(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
FAIL_IF(getput_arg(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
}
}
else if (flags & SLOW_SRC1)
FAIL_IF(getput_arg(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
else if (flags & SLOW_SRC2)
FAIL_IF(getput_arg(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
if (flags & SLOW_SRC1)
src1 = TMP_FREG1;
if (flags & SLOW_SRC2)
src2 = TMP_FREG2;
switch (op) {
case SLJIT_FADD:
FAIL_IF(push_inst(compiler, FADDD | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
switch (GET_OPCODE(op)) {
case SLJIT_ADDD:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADDD) | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
case SLJIT_FSUB:
FAIL_IF(push_inst(compiler, FSUBD | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
case SLJIT_SUBD:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUBD) | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
case SLJIT_FMUL:
FAIL_IF(push_inst(compiler, FMULD | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
case SLJIT_MULD:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMULD) | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
case SLJIT_FDIV:
FAIL_IF(push_inst(compiler, FDIVD | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
case SLJIT_DIVD:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIVD) | DA(dst_fr) | S1A(src1) | S2A(src2), MOVABLE_INS));
break;
}
if (dst_fr == TMP_FREG2)
FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA, TMP_FREG2, dst, dstw, 0, 0));
FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
return SLJIT_SUCCESS;
}
#undef FLOAT_DATA
#undef SELECT_FOP
/* --------------------------------------------------------------------- */
/* Other instructions */
/* --------------------------------------------------------------------- */
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
{
CHECK_ERROR();
check_sljit_emit_fast_enter(compiler, dst, dstw);
ADJUST_LOCAL_OFFSET(dst, dstw);
if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS)
return push_inst(compiler, OR | D(dst) | S1(0) | S2(LINK_REG), DR(dst));
else if (dst & SLJIT_MEM)
return emit_op_mem(compiler, WORD_DATA, LINK_REG, dst, dstw);
/* For UNUSED dst. Uncommon, but possible. */
if (dst == SLJIT_UNUSED)
return SLJIT_SUCCESS;
/* SLJIT_UNUSED is also possible, although highly unlikely. */
return SLJIT_SUCCESS;
if (FAST_IS_REG(dst))
return push_inst(compiler, OR | D(dst) | S1(0) | S2(TMP_LINK), DR(dst));
/* Memory. */
return emit_op_mem(compiler, WORD_DATA, TMP_LINK, dst, dstw);
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
{
CHECK_ERROR();
check_sljit_emit_fast_return(compiler, src, srcw);
ADJUST_LOCAL_OFFSET(src, srcw);
if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS)
FAIL_IF(push_inst(compiler, OR | D(LINK_REG) | S1(0) | S2(src), DR(LINK_REG)));
if (FAST_IS_REG(src))
FAIL_IF(push_inst(compiler, OR | D(TMP_LINK) | S1(0) | S2(src), DR(TMP_LINK)));
else if (src & SLJIT_MEM)
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, LINK_REG, src, srcw));
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_LINK, src, srcw));
else if (src & SLJIT_IMM)
FAIL_IF(load_immediate(compiler, LINK_REG, srcw));
FAIL_IF(load_immediate(compiler, TMP_LINK, srcw));
FAIL_IF(push_inst(compiler, JMPL | D(0) | S1(LINK_REG) | IMM(8), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, JMPL | D(0) | S1(TMP_LINK) | IMM(8), UNMOVABLE_INS));
return push_inst(compiler, NOP, UNMOVABLE_INS);
}
@ -1103,7 +1164,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
return label;
}
static sljit_ins get_cc(int type)
static sljit_ins get_cc(sljit_si type)
{
switch (type) {
case SLJIT_C_EQUAL:
@ -1174,7 +1235,7 @@ static sljit_ins get_cc(int type)
}
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type)
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type)
{
struct sljit_jump *jump;
@ -1213,23 +1274,23 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
}
PTR_FAIL_IF(emit_const(compiler, TMP_REG2, 0));
PTR_FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? LINK_REG : 0) | S1(TMP_REG2) | IMM(0), UNMOVABLE_INS));
PTR_FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? TMP_LINK : 0) | S1(TMP_REG2) | IMM(0), UNMOVABLE_INS));
jump->addr = compiler->size;
PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
return jump;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw)
{
struct sljit_jump *jump = NULL;
int src_r;
sljit_si src_r;
CHECK_ERROR();
check_sljit_emit_ijump(compiler, type, src, srcw);
ADJUST_LOCAL_OFFSET(src, srcw);
if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS)
if (FAST_IS_REG(src))
src_r = src;
else if (src & SLJIT_IMM) {
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
@ -1249,25 +1310,38 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i
src_r = TMP_REG2;
}
FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? LINK_REG : 0) | S1(src_r) | IMM(0), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? TMP_LINK : 0) | S1(src_r) | IMM(0), UNMOVABLE_INS));
if (jump)
jump->addr = compiler->size;
return push_inst(compiler, NOP, UNMOVABLE_INS);
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op,
sljit_si dst, sljit_sw dstw,
sljit_si src, sljit_sw srcw,
sljit_si type)
{
int reg;
sljit_si reg, flags = (GET_FLAGS(op) ? SET_FLAGS : 0);
CHECK_ERROR();
check_sljit_emit_cond_value(compiler, op, dst, dstw, type);
check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type);
ADJUST_LOCAL_OFFSET(dst, dstw);
if (dst == SLJIT_UNUSED)
return SLJIT_SUCCESS;
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
reg = (op == SLJIT_MOV && dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2;
op = GET_OPCODE(op);
reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
compiler->cache_arg = 0;
compiler->cache_argw = 0;
if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
ADJUST_LOCAL_OFFSET(src, srcw);
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
src = TMP_REG1;
srcw = 0;
}
if (type < SLJIT_C_FLOAT_EQUAL)
FAIL_IF(push_inst(compiler, BICC | get_cc(type) | 3, UNMOVABLE_INS));
@ -1277,8 +1351,8 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(1), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS));
if (GET_OPCODE(op) == SLJIT_OR)
return emit_op(compiler, SLJIT_OR, (GET_FLAGS(op) ? SET_FLAGS : 0) | CUMULATIVE_OP | IMM_OP, dst, dstw, dst, dstw, TMP_REG2, 0);
if (op >= SLJIT_ADD)
return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0);
return (reg == TMP_REG2) ? emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw) : SLJIT_SUCCESS;
#else
@ -1286,9 +1360,9 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil
#endif
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value)
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value)
{
int reg;
sljit_si reg;
struct sljit_const *const_;
CHECK_ERROR_PTR();
@ -1299,12 +1373,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
PTR_FAIL_IF(!const_);
set_const(const_, compiler);
reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2;
reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
PTR_FAIL_IF(emit_const(compiler, reg, init_value));
if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
return const_;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,75 +26,76 @@
/* x86 64-bit arch dependent functions. */
static int emit_load_imm64(struct sljit_compiler *compiler, int reg, sljit_w imm)
static sljit_si emit_load_imm64(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
{
sljit_ub *buf;
sljit_ub *inst;
buf = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_w));
FAIL_IF(!buf);
INC_SIZE(2 + sizeof(sljit_w));
*buf++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
*buf++ = 0xb8 + (reg_map[reg] & 0x7);
*(sljit_w*)buf = imm;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
FAIL_IF(!inst);
INC_SIZE(2 + sizeof(sljit_sw));
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
*(sljit_sw*)inst = imm;
return SLJIT_SUCCESS;
}
static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, int type)
static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type)
{
if (type < SLJIT_JUMP) {
/* Invert type. */
*code_ptr++ = get_jump_code(type ^ 0x1) - 0x10;
*code_ptr++ = 10 + 3;
}
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_first);
*code_ptr++ = REX_W | REX_B;
*code_ptr++ = 0xb8 + 1;
*code_ptr++ = MOV_r_i32 + 1;
jump->addr = (sljit_uw)code_ptr;
if (jump->flags & JUMP_LABEL)
jump->flags |= PATCH_MD;
else
*(sljit_w*)code_ptr = jump->u.target;
*(sljit_sw*)code_ptr = jump->u.target;
code_ptr += sizeof(sljit_w);
code_ptr += sizeof(sljit_sw);
*code_ptr++ = REX_B;
*code_ptr++ = 0xff;
*code_ptr++ = (type >= SLJIT_FAST_CALL) ? 0xd1 /* call */ : 0xe1 /* jmp */;
*code_ptr++ = GROUP_FF;
*code_ptr++ = (type >= SLJIT_FAST_CALL) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
return code_ptr;
}
static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_w addr, int type)
static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_sw addr, sljit_si type)
{
sljit_w delta = addr - ((sljit_w)code_ptr + 1 + sizeof(sljit_hw));
sljit_sw delta = addr - ((sljit_sw)code_ptr + 1 + sizeof(sljit_si));
if (delta <= SLJIT_W(0x7fffffff) && delta >= SLJIT_W(-0x80000000)) {
*code_ptr++ = (type == 2) ? 0xe8 /* call */ : 0xe9 /* jmp */;
*(sljit_w*)code_ptr = delta;
if (delta <= HALFWORD_MAX && delta >= HALFWORD_MIN) {
*code_ptr++ = (type == 2) ? CALL_i32 : JMP_i32;
*(sljit_sw*)code_ptr = delta;
}
else {
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_second);
*code_ptr++ = REX_W | REX_B;
*code_ptr++ = 0xb8 + 1;
*(sljit_w*)code_ptr = addr;
code_ptr += sizeof(sljit_w);
*code_ptr++ = MOV_r_i32 + 1;
*(sljit_sw*)code_ptr = addr;
code_ptr += sizeof(sljit_sw);
*code_ptr++ = REX_B;
*code_ptr++ = 0xff;
*code_ptr++ = (type == 2) ? 0xd1 /* call */ : 0xe1 /* jmp */;
*code_ptr++ = GROUP_FF;
*code_ptr++ = (type == 2) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
}
return code_ptr;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size)
{
int size, pushed_size;
sljit_ub *buf;
sljit_si size, pushed_size;
sljit_ub *inst;
CHECK_ERROR();
check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size);
check_sljit_emit_enter(compiler, args, scratches, saveds, local_size);
compiler->temporaries = temporaries;
compiler->scratches = scratches;
compiler->saveds = saveds;
compiler->flags_saved = 0;
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
@ -103,38 +104,38 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i
size = saveds;
/* Including the return address saved by the call instruction. */
pushed_size = (saveds + 1) * sizeof(sljit_w);
pushed_size = (saveds + 1) * sizeof(sljit_sw);
#ifndef _WIN64
if (saveds >= 2)
size += saveds - 1;
#else
if (saveds >= 4)
size += saveds - 3;
if (temporaries >= 5) {
if (scratches >= 5) {
size += (5 - 4) * 2;
pushed_size += sizeof(sljit_w);
pushed_size += sizeof(sljit_sw);
}
#endif
size += args * 3;
if (size > 0) {
buf = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (saveds >= 5) {
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_EREG2] >= 8, saved_ereg2_is_hireg);
*buf++ = REX_B;
*inst++ = REX_B;
PUSH_REG(reg_lmap[SLJIT_SAVED_EREG2]);
}
if (saveds >= 4) {
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_EREG1] >= 8, saved_ereg1_is_hireg);
*buf++ = REX_B;
*inst++ = REX_B;
PUSH_REG(reg_lmap[SLJIT_SAVED_EREG1]);
}
if (saveds >= 3) {
#ifndef _WIN64
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG3] >= 8, saved_reg3_is_hireg);
*buf++ = REX_B;
*inst++ = REX_B;
#else
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG3] < 8, saved_reg3_is_loreg);
#endif
@ -143,7 +144,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i
if (saveds >= 2) {
#ifndef _WIN64
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG2] >= 8, saved_reg2_is_hireg);
*buf++ = REX_B;
*inst++ = REX_B;
#else
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG2] < 8, saved_reg2_is_loreg);
#endif
@ -154,44 +155,44 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i
PUSH_REG(reg_lmap[SLJIT_SAVED_REG1]);
}
#ifdef _WIN64
if (temporaries >= 5) {
if (scratches >= 5) {
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_TEMPORARY_EREG2] >= 8, temporary_ereg2_is_hireg);
*buf++ = REX_B;
*inst++ = REX_B;
PUSH_REG(reg_lmap[SLJIT_TEMPORARY_EREG2]);
}
#endif
#ifndef _WIN64
if (args > 0) {
*buf++ = REX_W;
*buf++ = 0x8b;
*buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x7;
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x7 /* rdi */;
}
if (args > 1) {
*buf++ = REX_W | REX_R;
*buf++ = 0x8b;
*buf++ = 0xc0 | (reg_lmap[SLJIT_SAVED_REG2] << 3) | 0x6;
*inst++ = REX_W | REX_R;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_lmap[SLJIT_SAVED_REG2] << 3) | 0x6 /* rsi */;
}
if (args > 2) {
*buf++ = REX_W | REX_R;
*buf++ = 0x8b;
*buf++ = 0xc0 | (reg_lmap[SLJIT_SAVED_REG3] << 3) | 0x2;
*inst++ = REX_W | REX_R;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_lmap[SLJIT_SAVED_REG3] << 3) | 0x2 /* rdx */;
}
#else
if (args > 0) {
*buf++ = REX_W;
*buf++ = 0x8b;
*buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x1;
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x1 /* rcx */;
}
if (args > 1) {
*buf++ = REX_W;
*buf++ = 0x8b;
*buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG2] << 3) | 0x2;
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG2] << 3) | 0x2 /* rdx */;
}
if (args > 2) {
*buf++ = REX_W | REX_B;
*buf++ = 0x8b;
*buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG3] << 3) | 0x0;
*inst++ = REX_W | REX_B;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG3] << 3) | 0x0 /* r8 */;
}
#endif
}
@ -201,75 +202,91 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i
#ifdef _WIN64
if (local_size > 1024) {
/* Allocate stack for the callback, which grows the stack. */
buf = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!buf);
INC_SIZE(4);
*buf++ = REX_W;
*buf++ = 0x83;
*buf++ = 0xc0 | (5 << 3) | 4;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_si)));
FAIL_IF(!inst);
INC_SIZE(4 + (3 + sizeof(sljit_si)));
*inst++ = REX_W;
*inst++ = GROUP_BINARY_83;
*inst++ = MOD_REG | SUB | 4;
/* Pushed size must be divisible by 8. */
SLJIT_ASSERT(!(pushed_size & 0x7));
if (pushed_size & 0x8) {
*buf++ = 5 * sizeof(sljit_w);
local_size -= 5 * sizeof(sljit_w);
*inst++ = 5 * sizeof(sljit_sw);
local_size -= 5 * sizeof(sljit_sw);
} else {
*buf++ = 4 * sizeof(sljit_w);
local_size -= 4 * sizeof(sljit_w);
*inst++ = 4 * sizeof(sljit_sw);
local_size -= 4 * sizeof(sljit_sw);
}
FAIL_IF(emit_load_imm64(compiler, SLJIT_TEMPORARY_REG1, local_size));
/* Second instruction */
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG1] < 8, temporary_reg1_is_loreg);
*inst++ = REX_W;
*inst++ = MOV_rm_i32;
*inst++ = MOD_REG | reg_lmap[SLJIT_SCRATCH_REG1];
*(sljit_si*)inst = local_size;
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG)
compiler->skip_checks = 1;
#endif
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
}
#endif
SLJIT_ASSERT(local_size > 0);
if (local_size <= 127) {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
*buf++ = REX_W;
*buf++ = 0x83;
*buf++ = 0xc0 | (5 << 3) | 4;
*buf++ = local_size;
*inst++ = REX_W;
*inst++ = GROUP_BINARY_83;
*inst++ = MOD_REG | SUB | 4;
*inst++ = local_size;
}
else {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 7);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 7);
FAIL_IF(!inst);
INC_SIZE(7);
*buf++ = REX_W;
*buf++ = 0x81;
*buf++ = 0xc0 | (5 << 3) | 4;
*(sljit_hw*)buf = local_size;
buf += sizeof(sljit_hw);
*inst++ = REX_W;
*inst++ = GROUP_BINARY_81;
*inst++ = MOD_REG | SUB | 4;
*(sljit_si*)inst = local_size;
inst += sizeof(sljit_si);
}
#ifdef _WIN64
/* Save xmm6 with MOVAPS instruction. */
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
*(sljit_si*)inst = 0x20247429;
#endif
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size)
{
int pushed_size;
sljit_si pushed_size;
CHECK_ERROR_VOID();
check_sljit_set_context(compiler, args, temporaries, saveds, local_size);
check_sljit_set_context(compiler, args, scratches, saveds, local_size);
compiler->temporaries = temporaries;
compiler->scratches = scratches;
compiler->saveds = saveds;
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
compiler->logical_local_size = local_size;
#endif
/* Including the return address saved by the call instruction. */
pushed_size = (saveds + 1) * sizeof(sljit_w);
pushed_size = (saveds + 1) * sizeof(sljit_sw);
#ifdef _WIN64
if (temporaries >= 5)
pushed_size += sizeof(sljit_w);
if (scratches >= 5)
pushed_size += sizeof(sljit_sw);
#endif
compiler->local_size = ((local_size + FIXED_LOCALS_OFFSET + pushed_size + 16 - 1) & ~(16 - 1)) - pushed_size;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
{
int size;
sljit_ub *buf;
sljit_si size;
sljit_ub *inst;
CHECK_ERROR();
check_sljit_emit_return(compiler, op, src, srcw);
@ -277,24 +294,32 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler,
compiler->flags_saved = 0;
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
#ifdef _WIN64
/* Restore xmm6 with MOVAPS instruction. */
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
*(sljit_si*)inst = 0x20247428;
#endif
SLJIT_ASSERT(compiler->local_size > 0);
if (compiler->local_size <= 127) {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
*buf++ = REX_W;
*buf++ = 0x83;
*buf++ = 0xc0 | (0 << 3) | 4;
*buf = compiler->local_size;
*inst++ = REX_W;
*inst++ = GROUP_BINARY_83;
*inst++ = MOD_REG | ADD | 4;
*inst = compiler->local_size;
}
else {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 7);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 7);
FAIL_IF(!inst);
INC_SIZE(7);
*buf++ = REX_W;
*buf++ = 0x81;
*buf++ = 0xc0 | (0 << 3) | 4;
*(sljit_hw*)buf = compiler->local_size;
*inst++ = REX_W;
*inst++ = GROUP_BINARY_81;
*inst++ = MOD_REG | ADD | 4;
*(sljit_si*)inst = compiler->local_size;
}
size = 1 + compiler->saveds;
@ -304,17 +329,17 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler,
#else
if (compiler->saveds >= 4)
size += compiler->saveds - 3;
if (compiler->temporaries >= 5)
if (compiler->scratches >= 5)
size += (5 - 4) * 2;
#endif
buf = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
#ifdef _WIN64
if (compiler->temporaries >= 5) {
*buf++ = REX_B;
if (compiler->scratches >= 5) {
*inst++ = REX_B;
POP_REG(reg_lmap[SLJIT_TEMPORARY_EREG2]);
}
#endif
@ -322,22 +347,22 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler,
POP_REG(reg_map[SLJIT_SAVED_REG1]);
if (compiler->saveds >= 2) {
#ifndef _WIN64
*buf++ = REX_B;
*inst++ = REX_B;
#endif
POP_REG(reg_lmap[SLJIT_SAVED_REG2]);
}
if (compiler->saveds >= 3) {
#ifndef _WIN64
*buf++ = REX_B;
*inst++ = REX_B;
#endif
POP_REG(reg_lmap[SLJIT_SAVED_REG3]);
}
if (compiler->saveds >= 4) {
*buf++ = REX_B;
*inst++ = REX_B;
POP_REG(reg_lmap[SLJIT_SAVED_EREG1]);
}
if (compiler->saveds >= 5) {
*buf++ = REX_B;
*inst++ = REX_B;
POP_REG(reg_lmap[SLJIT_SAVED_EREG2]);
}
@ -349,39 +374,32 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler,
/* Operators */
/* --------------------------------------------------------------------- */
static int emit_do_imm32(struct sljit_compiler *compiler, sljit_ub rex, sljit_ub opcode, sljit_w imm)
static sljit_si emit_do_imm32(struct sljit_compiler *compiler, sljit_ub rex, sljit_ub opcode, sljit_sw imm)
{
sljit_ub *buf;
sljit_ub *inst;
sljit_si length = 1 + (rex ? 1 : 0) + sizeof(sljit_si);
if (rex != 0) {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_hw));
FAIL_IF(!buf);
INC_SIZE(2 + sizeof(sljit_hw));
*buf++ = rex;
*buf++ = opcode;
*(sljit_hw*)buf = imm;
}
else {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_hw));
FAIL_IF(!buf);
INC_SIZE(1 + sizeof(sljit_hw));
*buf++ = opcode;
*(sljit_hw*)buf = imm;
}
inst = (sljit_ub*)ensure_buf(compiler, 1 + length);
FAIL_IF(!inst);
INC_SIZE(length);
if (rex)
*inst++ = rex;
*inst++ = opcode;
*(sljit_si*)inst = imm;
return SLJIT_SUCCESS;
}
static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size,
/* The register or immediate operand. */
int a, sljit_w imma,
sljit_si a, sljit_sw imma,
/* The general operand (not immediate). */
int b, sljit_w immb)
sljit_si b, sljit_sw immb)
{
sljit_ub *buf;
sljit_ub *inst;
sljit_ub *buf_ptr;
sljit_ub rex = 0;
int flags = size & ~0xf;
int inst_size;
sljit_si flags = size & ~0xf;
sljit_si inst_size;
/* The immediate operand must be 32 bit. */
SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
@ -394,17 +412,20 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
#if (defined SLJIT_SSE2 && SLJIT_SSE2)
/* SSE2 and immediate is not possible. */
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
#endif
size &= 0xf;
inst_size = size;
if ((b & SLJIT_MEM) && !(b & 0xf0) && NOT_HALFWORD(immb)) {
if ((b & SLJIT_MEM) && !(b & OFFS_REG_MASK) && NOT_HALFWORD(immb)) {
if (emit_load_imm64(compiler, TMP_REG3, immb))
return NULL;
immb = 0;
if (b & 0xf)
b |= TMP_REG3 << 4;
if (b & REG_MASK)
b |= TO_OFFS_REG(TMP_REG3);
else
b |= TMP_REG3;
}
@ -415,7 +436,7 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
rex |= REX;
#if (defined SLJIT_SSE2 && SLJIT_SSE2)
if (flags & EX86_PREF_F2)
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
inst_size++;
#endif
if (flags & EX86_PREF_66)
@ -424,26 +445,26 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
/* Calculate size of b. */
inst_size += 1; /* mod r/m byte. */
if (b & SLJIT_MEM) {
if ((b & 0x0f) == SLJIT_UNUSED)
inst_size += 1 + sizeof(sljit_hw); /* SIB byte required to avoid RIP based addressing. */
if ((b & REG_MASK) == SLJIT_UNUSED)
inst_size += 1 + sizeof(sljit_si); /* SIB byte required to avoid RIP based addressing. */
else {
if (reg_map[b & 0x0f] >= 8)
if (reg_map[b & REG_MASK] >= 8)
rex |= REX_B;
if (immb != 0 && !(b & 0xf0)) {
if (immb != 0 && !(b & OFFS_REG_MASK)) {
/* Immediate operand. */
if (immb <= 127 && immb >= -128)
inst_size += sizeof(sljit_b);
inst_size += sizeof(sljit_sb);
else
inst_size += sizeof(sljit_hw);
inst_size += sizeof(sljit_si);
}
}
if ((b & 0xf) == SLJIT_LOCALS_REG && !(b & 0xf0))
b |= SLJIT_LOCALS_REG << 4;
if ((b & REG_MASK) == SLJIT_LOCALS_REG && !(b & OFFS_REG_MASK))
b |= TO_OFFS_REG(SLJIT_LOCALS_REG);
if ((b & 0xf0) != SLJIT_UNUSED) {
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
inst_size += 1; /* SIB byte. */
if (reg_map[(b >> 4) & 0x0f] >= 8)
if (reg_map[OFFS_REG(b)] >= 8)
rex |= REX_X;
}
}
@ -474,7 +495,7 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
else if (flags & EX86_HALF_ARG)
inst_size += sizeof(short);
else
inst_size += sizeof(sljit_hw);
inst_size += sizeof(sljit_si);
}
else {
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
@ -491,25 +512,27 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
if (rex)
inst_size++;
buf = (sljit_ub*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!inst);
/* Encoding the byte. */
INC_SIZE(inst_size);
#if (defined SLJIT_SSE2 && SLJIT_SSE2)
if (flags & EX86_PREF_F2)
*buf++ = 0xf2;
*inst++ = 0xf2;
if (flags & EX86_PREF_F3)
*inst++ = 0xf3;
#endif
if (flags & EX86_PREF_66)
*buf++ = 0x66;
*inst++ = 0x66;
if (rex)
*buf++ = rex;
buf_ptr = buf + size;
*inst++ = rex;
buf_ptr = inst + size;
/* Encode mod/rm byte. */
if (!(flags & EX86_SHIFT_INS)) {
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
*buf = (flags & EX86_BYTE_ARG) ? 0x83 : 0x81;
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
if ((a & SLJIT_IMM) || (a == 0))
*buf_ptr = 0;
@ -526,22 +549,22 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
else {
if (a & SLJIT_IMM) {
if (imma == 1)
*buf = 0xd1;
*inst = GROUP_SHIFT_1;
else
*buf = 0xc1;
*inst = GROUP_SHIFT_N;
} else
*buf = 0xd3;
*inst = GROUP_SHIFT_CL;
*buf_ptr = 0;
}
if (!(b & SLJIT_MEM))
#if (defined SLJIT_SSE2 && SLJIT_SSE2)
*buf_ptr++ |= 0xc0 + ((!(flags & EX86_SSE2)) ? reg_lmap[b] : b);
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2)) ? reg_lmap[b] : b);
#else
*buf_ptr++ |= 0xc0 + reg_lmap[b];
*buf_ptr++ |= MOD_REG + reg_lmap[b];
#endif
else if ((b & 0x0f) != SLJIT_UNUSED) {
if ((b & 0xf0) == SLJIT_UNUSED || (b & 0xf0) == (SLJIT_LOCALS_REG << 4)) {
else if ((b & REG_MASK) != SLJIT_UNUSED) {
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_LOCALS_REG)) {
if (immb != 0) {
if (immb <= 127 && immb >= -128)
*buf_ptr |= 0x40;
@ -549,32 +572,32 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
*buf_ptr |= 0x80;
}
if ((b & 0xf0) == SLJIT_UNUSED)
*buf_ptr++ |= reg_lmap[b & 0x0f];
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
*buf_ptr++ |= reg_lmap[b & REG_MASK];
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = reg_lmap[b & 0x0f] | (reg_lmap[(b >> 4) & 0x0f] << 3);
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3);
}
if (immb != 0) {
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
*(sljit_hw*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_hw);
*(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_si);
}
}
}
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = reg_lmap[b & 0x0f] | (reg_lmap[(b >> 4) & 0x0f] << 3) | (immb << 6);
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6);
}
}
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = 0x25;
*(sljit_hw*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_hw);
*(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_si);
}
if (a & SLJIT_IMM) {
@ -583,55 +606,55 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size,
else if (flags & EX86_HALF_ARG)
*(short*)buf_ptr = imma;
else if (!(flags & EX86_SHIFT_INS))
*(sljit_hw*)buf_ptr = imma;
*(sljit_si*)buf_ptr = imma;
}
return !(flags & EX86_SHIFT_INS) ? buf : (buf + 1);
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
}
/* --------------------------------------------------------------------- */
/* Call / return instructions */
/* --------------------------------------------------------------------- */
static SLJIT_INLINE int call_with_args(struct sljit_compiler *compiler, int type)
static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type)
{
sljit_ub *buf;
sljit_ub *inst;
#ifndef _WIN64
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_TEMPORARY_REG2] == 6 && reg_map[SLJIT_TEMPORARY_REG1] < 8 && reg_map[SLJIT_TEMPORARY_REG3] < 8, args_registers);
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG2] == 6 && reg_map[SLJIT_SCRATCH_REG1] < 8 && reg_map[SLJIT_SCRATCH_REG3] < 8, args_registers);
buf = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
FAIL_IF(!inst);
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
if (type >= SLJIT_CALL3) {
*buf++ = REX_W;
*buf++ = 0x8b;
*buf++ = 0xc0 | (0x2 << 3) | reg_lmap[SLJIT_TEMPORARY_REG3];
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x2 /* rdx */ << 3) | reg_lmap[SLJIT_SCRATCH_REG3];
}
*buf++ = REX_W;
*buf++ = 0x8b;
*buf++ = 0xc0 | (0x7 << 3) | reg_lmap[SLJIT_TEMPORARY_REG1];
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x7 /* rdi */ << 3) | reg_lmap[SLJIT_SCRATCH_REG1];
#else
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_TEMPORARY_REG2] == 2 && reg_map[SLJIT_TEMPORARY_REG1] < 8 && reg_map[SLJIT_TEMPORARY_REG3] < 8, args_registers);
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG2] == 2 && reg_map[SLJIT_SCRATCH_REG1] < 8 && reg_map[SLJIT_SCRATCH_REG3] < 8, args_registers);
buf = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
FAIL_IF(!inst);
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
if (type >= SLJIT_CALL3) {
*buf++ = REX_W | REX_R;
*buf++ = 0x8b;
*buf++ = 0xc0 | (0x0 << 3) | reg_lmap[SLJIT_TEMPORARY_REG3];
*inst++ = REX_W | REX_R;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x0 /* r8 */ << 3) | reg_lmap[SLJIT_SCRATCH_REG3];
}
*buf++ = REX_W;
*buf++ = 0x8b;
*buf++ = 0xc0 | (0x1 << 3) | reg_lmap[SLJIT_TEMPORARY_REG1];
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x1 /* rcx */ << 3) | reg_lmap[SLJIT_SCRATCH_REG1];
#endif
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
{
sljit_ub *buf;
sljit_ub *inst;
CHECK_ERROR();
check_sljit_emit_fast_enter(compiler, dst, dstw);
@ -639,87 +662,85 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compil
/* For UNUSED dst. Uncommon, but possible. */
if (dst == SLJIT_UNUSED)
dst = TMP_REGISTER;
dst = TMP_REG1;
if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) {
if (FAST_IS_REG(dst)) {
if (reg_map[dst] < 8) {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
POP_REG(reg_lmap[dst]);
return SLJIT_SUCCESS;
}
else {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!buf);
INC_SIZE(2);
*buf++ = REX_B;
POP_REG(reg_lmap[dst]);
}
}
else if (dst & SLJIT_MEM) {
/* REX_W is not necessary (src is not immediate). */
compiler->mode32 = 1;
buf = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!buf);
*buf++ = 0x8f;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
*inst++ = REX_B;
POP_REG(reg_lmap[dst]);
return SLJIT_SUCCESS;
}
/* REX_W is not necessary (src is not immediate). */
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!inst);
*inst++ = POP_rm;
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
{
sljit_ub *buf;
sljit_ub *inst;
CHECK_ERROR();
check_sljit_emit_fast_return(compiler, src, srcw);
ADJUST_LOCAL_OFFSET(src, srcw);
if ((src & SLJIT_IMM) && NOT_HALFWORD(srcw)) {
FAIL_IF(emit_load_imm64(compiler, TMP_REGISTER, srcw));
src = TMP_REGISTER;
FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
src = TMP_REG1;
}
if (src >= SLJIT_TEMPORARY_REG1 && src <= TMP_REGISTER) {
if (FAST_IS_REG(src)) {
if (reg_map[src] < 8) {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 1);
PUSH_REG(reg_lmap[src]);
}
else {
buf = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 1);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 1);
FAIL_IF(!inst);
INC_SIZE(2 + 1);
*buf++ = REX_B;
*inst++ = REX_B;
PUSH_REG(reg_lmap[src]);
}
}
else if (src & SLJIT_MEM) {
/* REX_W is not necessary (src is not immediate). */
compiler->mode32 = 1;
buf = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!buf);
*buf++ = 0xff;
*buf |= 6 << 3;
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = GROUP_FF;
*inst |= PUSH_rm;
buf = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
}
else {
SLJIT_ASSERT(IS_HALFWORD(srcw));
/* SLJIT_IMM. */
buf = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1);
FAIL_IF(!buf);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1);
FAIL_IF(!inst);
INC_SIZE(5 + 1);
*buf++ = 0x68;
*(sljit_hw*)buf = srcw;
buf += sizeof(sljit_hw);
*inst++ = PUSH_i32;
*(sljit_si*)inst = srcw;
inst += sizeof(sljit_si);
}
RET();
@ -731,12 +752,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi
/* Extend input */
/* --------------------------------------------------------------------- */
static int emit_mov_int(struct sljit_compiler *compiler, int sign,
int dst, sljit_w dstw,
int src, sljit_w srcw)
static sljit_si emit_mov_int(struct sljit_compiler *compiler, sljit_si sign,
sljit_si dst, sljit_sw dstw,
sljit_si src, sljit_sw srcw)
{
sljit_ub* code;
int dst_r;
sljit_ub* inst;
sljit_si dst_r;
compiler->mode32 = 0;
@ -744,32 +765,32 @@ static int emit_mov_int(struct sljit_compiler *compiler, int sign,
return SLJIT_SUCCESS; /* Empty instruction. */
if (src & SLJIT_IMM) {
if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) {
if (FAST_IS_REG(dst)) {
if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
code = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_w)(sljit_i)srcw, dst, dstw);
FAIL_IF(!code);
*code = 0xc7;
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_i32;
return SLJIT_SUCCESS;
}
return emit_load_imm64(compiler, dst, srcw);
}
compiler->mode32 = 1;
code = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_w)(sljit_i)srcw, dst, dstw);
FAIL_IF(!code);
*code = 0xc7;
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_i32;
compiler->mode32 = 0;
return SLJIT_SUCCESS;
}
dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_SAVED_REG3) ? dst : TMP_REGISTER;
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if ((dst & SLJIT_MEM) && (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_SAVED_REG3))
if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
dst_r = src;
else {
if (sign) {
code = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
FAIL_IF(!code);
*code++ = 0x63;
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = MOVSXD_r_rm;
} else {
compiler->mode32 = 1;
FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
@ -779,9 +800,9 @@ static int emit_mov_int(struct sljit_compiler *compiler, int sign,
if (dst & SLJIT_MEM) {
compiler->mode32 = 1;
code = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
FAIL_IF(!code);
*code = 0x89;
inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_r;
compiler->mode32 = 0;
}