remove some unneeded files
thought i removed these in previous commits, apparently not
This commit is contained in:
parent
0f603840e3
commit
2b986c17d4
|
@ -1,2 +0,0 @@
|
|||
bin
|
||||
taring
|
|
@ -1,99 +0,0 @@
|
|||
ifdef CROSS_COMPILER
|
||||
CC = $(CROSS_COMPILER)
|
||||
else
|
||||
ifndef CC
|
||||
# default compiler
|
||||
CC = gcc
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef EXTRA_CPPFLAGS
|
||||
EXTRA_CPPFLAGS=
|
||||
endif
|
||||
|
||||
ifndef EXTRA_LDFLAGS
|
||||
EXTRA_LDFLAGS=
|
||||
endif
|
||||
|
||||
CPPFLAGS = $(EXTRA_CPPFLAGS) -Isljit_src
|
||||
CFLAGS += -O2 -Wall -Wextra -Wconversion -Wsign-compare -Werror
|
||||
REGEX_CFLAGS += $(CFLAGS) -fshort-wchar
|
||||
LDFLAGS = $(EXTRA_LDFLAGS)
|
||||
|
||||
BINDIR = bin
|
||||
SRCDIR = sljit_src
|
||||
TESTDIR = test_src
|
||||
REGEXDIR = regex_src
|
||||
EXAMPLEDIR = doc/tutorial
|
||||
|
||||
TARGET = $(BINDIR)/sljit_test $(BINDIR)/regex_test
|
||||
EXAMPLE_TARGET = $(BINDIR)/func_call $(BINDIR)/first_program $(BINDIR)/branch $(BINDIR)/loop $(BINDIR)/array_access $(BINDIR)/func_call $(BINDIR)/struct_access $(BINDIR)/temp_var $(BINDIR)/brainfuck
|
||||
|
||||
SLJIT_HEADERS = $(SRCDIR)/sljitLir.h $(SRCDIR)/sljitConfig.h $(SRCDIR)/sljitConfigInternal.h
|
||||
|
||||
SLJIT_LIR_FILES = $(SRCDIR)/sljitLir.c $(SRCDIR)/sljitUtils.c \
|
||||
$(SRCDIR)/allocator_src/sljitExecAllocatorCore.c $(SRCDIR)/allocator_src/sljitExecAllocatorApple.c \
|
||||
$(SRCDIR)/allocator_src/sljitExecAllocatorPosix.c $(SRCDIR)/allocator_src/sljitExecAllocatorWindows.c \
|
||||
$(SRCDIR)/allocator_src/sljitProtExecAllocatorNetBSD.c $(SRCDIR)/allocator_src/sljitProtExecAllocatorPosix.c \
|
||||
$(SRCDIR)/allocator_src/sljitWXExecAllocatorPosix.c $(SRCDIR)/allocator_src/sljitWXExecAllocatorWindows.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)/sljitNativeRISCV_common.c $(SRCDIR)/sljitNativeRISCV_32.c $(SRCDIR)/sljitNativeRISCV_64.c \
|
||||
$(SRCDIR)/sljitNativeS390X.c \
|
||||
$(SRCDIR)/sljitNativeX86_common.c $(SRCDIR)/sljitNativeX86_32.c $(SRCDIR)/sljitNativeX86_64.c
|
||||
|
||||
.PHONY: all clean examples
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
clean:
|
||||
-$(RM) $(BINDIR)/*.o $(BINDIR)/sljit_test $(BINDIR)/regex_test $(EXAMPLE_TARGET)
|
||||
|
||||
$(BINDIR)/.keep :
|
||||
mkdir -p $(BINDIR)
|
||||
@touch $@
|
||||
|
||||
$(BINDIR)/sljitLir.o : $(BINDIR)/.keep $(SLJIT_LIR_FILES) $(SLJIT_HEADERS)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SRCDIR)/sljitLir.c
|
||||
|
||||
$(BINDIR)/sljitMain.o : $(TESTDIR)/sljitMain.c $(BINDIR)/.keep $(SLJIT_HEADERS)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(TESTDIR)/sljitMain.c
|
||||
|
||||
$(BINDIR)/regexMain.o : $(REGEXDIR)/regexMain.c $(BINDIR)/.keep $(SLJIT_HEADERS)
|
||||
$(CC) $(CPPFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexMain.c
|
||||
|
||||
$(BINDIR)/regexJIT.o : $(REGEXDIR)/regexJIT.c $(BINDIR)/.keep $(SLJIT_HEADERS) $(REGEXDIR)/regexJIT.h
|
||||
$(CC) $(CPPFLAGS) $(REGEX_CFLAGS) -c -o $@ $(REGEXDIR)/regexJIT.c
|
||||
|
||||
$(BINDIR)/sljit_test: $(BINDIR)/.keep $(BINDIR)/sljitMain.o $(TESTDIR)/sljitTest.c $(SRCDIR)/sljitLir.c $(SLJIT_LIR_FILES) $(SLJIT_HEADERS) $(TESTDIR)/sljitConfigPre.h $(TESTDIR)/sljitConfigPost.h
|
||||
$(CC) $(CPPFLAGS) -DSLJIT_HAVE_CONFIG_PRE=1 -I$(TESTDIR) $(CFLAGS) $(LDFLAGS) $(BINDIR)/sljitMain.o $(TESTDIR)/sljitTest.c $(SRCDIR)/sljitLir.c -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/regex_test: $(BINDIR)/.keep $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(BINDIR)/regexMain.o $(BINDIR)/regexJIT.o $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
examples: $(EXAMPLE_TARGET)
|
||||
|
||||
$(BINDIR)/first_program: $(EXAMPLEDIR)/first_program.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/first_program.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/branch: $(EXAMPLEDIR)/branch.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/branch.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/loop: $(EXAMPLEDIR)/loop.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/loop.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/array_access: $(EXAMPLEDIR)/array_access.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/array_access.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/func_call: $(EXAMPLEDIR)/func_call.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/func_call.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/struct_access: $(EXAMPLEDIR)/struct_access.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/struct_access.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/temp_var: $(EXAMPLEDIR)/temp_var.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/temp_var.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
||||
|
||||
$(BINDIR)/brainfuck: $(EXAMPLEDIR)/brainfuck.c $(BINDIR)/.keep $(BINDIR)/sljitLir.o
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) $(EXAMPLEDIR)/brainfuck.c $(BINDIR)/sljitLir.o -o $@ -lm -lpthread
|
|
@ -1,226 +0,0 @@
|
|||
The following text is a brief overview of those key
|
||||
principles which are useful to know when generating code
|
||||
with SLJIT. Further details can be found in sljitLir.h.
|
||||
|
||||
----------------------------------------------------------------
|
||||
What is SLJIT?
|
||||
----------------------------------------------------------------
|
||||
|
||||
SLJIT is a platform independent assembler which
|
||||
- provides access to common CPU features
|
||||
- can be easily ported to wide-spread CPU
|
||||
architectures (e.g. x86, ARM, POWER, MIPS, s390x, LoongArch)
|
||||
|
||||
The key challenge of this project is finding a common
|
||||
subset of CPU features which
|
||||
- covers traditional assembly level programming
|
||||
- can be translated to machine code efficiently
|
||||
|
||||
This aim is achieved by selecting those instructions / CPU
|
||||
features which are either available on all platforms or
|
||||
simulating them has a low performance overhead.
|
||||
|
||||
For example, some SLJIT instructions support base register
|
||||
pre-update when [base+offs] memory accessing mode is used.
|
||||
Although this feature is only available on ARM and POWER
|
||||
CPUs, the simulation overhead is low on other CPUs.
|
||||
|
||||
----------------------------------------------------------------
|
||||
The generic CPU model of SLJIT
|
||||
----------------------------------------------------------------
|
||||
|
||||
The CPU has
|
||||
- integer registers, which can store either an
|
||||
int32_t (4 byte) or intptr_t (4 or 8 byte) value
|
||||
- floating point registers, which can store either a
|
||||
single (4 byte) or double (8 byte) precision value
|
||||
- boolean status flags
|
||||
|
||||
*** Integer registers:
|
||||
|
||||
The most important rule is: when a source operand of
|
||||
an instruction is a register, the data type of the
|
||||
register must match the data type expected by an
|
||||
instruction.
|
||||
|
||||
For example, the following code snippet
|
||||
is a valid instruction sequence:
|
||||
|
||||
sljit_emit_op1(compiler, SLJIT_MOV32,
|
||||
SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0);
|
||||
// An int32_t value is loaded into SLJIT_R0
|
||||
sljit_emit_op1(compiler, SLJIT_REV32,
|
||||
SLJIT_R0, 0, SLJIT_R0, 0);
|
||||
// the int32_t value in SLJIT_R0 is byte swapped
|
||||
// and the type of the result is still int32_t
|
||||
|
||||
The next code snippet is not allowed:
|
||||
|
||||
sljit_emit_op1(compiler, SLJIT_MOV,
|
||||
SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0);
|
||||
// An intptr_t value is loaded into SLJIT_R0
|
||||
sljit_emit_op1(compiler, SLJIT_REV32,
|
||||
SLJIT_R0, 0, SLJIT_R0, 0);
|
||||
// The result of the instruction is undefined.
|
||||
// Even crash is possible for some instructions
|
||||
// (e.g. on MIPS-64).
|
||||
|
||||
However, it is always allowed to overwrite a
|
||||
register regardless of its previous value:
|
||||
|
||||
sljit_emit_op1(compiler, SLJIT_MOV,
|
||||
SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R1), 0);
|
||||
// An intptr_t value is loaded into SLJIT_R0
|
||||
sljit_emit_op1(compiler, SLJIT_MOV32,
|
||||
SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R2), 0);
|
||||
// From now on SLJIT_R0 contains an int32_t
|
||||
// value. The previous value is discarded.
|
||||
|
||||
Type conversion instructions are provided to convert an
|
||||
int32_t value to an intptr_t value and vice versa. In
|
||||
certain architectures these conversions are nops (no
|
||||
instructions are emitted).
|
||||
|
||||
Memory accessing:
|
||||
|
||||
Registers arguments of SLJIT_MEM1 / SLJIT_MEM2 addressing
|
||||
modes must contain intptr_t data.
|
||||
|
||||
Signed / unsigned values:
|
||||
|
||||
Most operations are executed in the same way regardless
|
||||
the value is signed or unsigned. These operations have
|
||||
only one instruction form (e.g. SLJIT_ADD / SLJIT_MUL).
|
||||
Instructions where the result depends on the sign have
|
||||
two forms (e.g. integer division, long multiply).
|
||||
|
||||
*** Floating point registers
|
||||
|
||||
Floating point registers can either contain a single
|
||||
or double precision value. Similar to integer registers,
|
||||
the data type of the value stored in a source register
|
||||
must match the data type expected by the instruction.
|
||||
Otherwise the result is undefined (even crash is possible).
|
||||
|
||||
Rounding:
|
||||
|
||||
Similar to standard C, floating point computation
|
||||
results are rounded toward zero.
|
||||
|
||||
*** Boolean status flags:
|
||||
|
||||
Conditional branches usually depend on the value
|
||||
of CPU status flags. These status flags are boolean
|
||||
values and can be set by certain instructions.
|
||||
|
||||
To achive maximum efficiency and portability, the
|
||||
following rules were introduced:
|
||||
- Most instructions can freely modify these status
|
||||
flags except if SLJIT_KEEP_FLAGS is passed.
|
||||
- The SLJIT_KEEP_FLAGS option may have a performance
|
||||
overhead, so it should only be used when necessary.
|
||||
- The SLJIT_SET_E, SLJIT_SET_U, etc. options can
|
||||
force an instruction to correctly set the
|
||||
specified status flags. However, all other
|
||||
status flags are undefined. This rule must
|
||||
always be kept in mind!
|
||||
- Status flags cannot be controlled directly
|
||||
(there are no set/clear/invert operations)
|
||||
|
||||
The last two rules allows efficient mapping of status flags.
|
||||
For example the arithmetic and multiply overflow flag is
|
||||
mapped to the same overflow flag bit on x86. This is allowed,
|
||||
since no instruction can set both of these flags. When
|
||||
either of them is set by an instruction, the other can
|
||||
have any value (this satisfies the "all other flags are
|
||||
undefined" rule). Therefore mapping two SLJIT flags to the
|
||||
same CPU flag is possible. Even though SLJIT supports
|
||||
a dozen status flags, they can be efficiently mapped
|
||||
to CPUs with only 4 status flags (e.g. ARM or SPARC).
|
||||
|
||||
----------------------------------------------------------------
|
||||
Complex instructions
|
||||
----------------------------------------------------------------
|
||||
|
||||
We noticed, that introducing complex instructions for common
|
||||
tasks can improve performance. For example, compare and
|
||||
branch instruction sequences can be optimized if certain
|
||||
conditions apply, but these conditions depend on the target
|
||||
CPU. SLJIT can do these optimizations, but it needs to
|
||||
understand the "purpose" of the generated code. Static
|
||||
instruction analysis has a large performance overhead
|
||||
however, so we choose another approach: we introduced
|
||||
complex instruction forms for certain non-atomic tasks.
|
||||
SLJIT can optimize these "instructions" more efficiently
|
||||
since the "purpose" is known to the compiler. These complex
|
||||
instruction forms can often be assembled from other SLJIT
|
||||
instructions, but we recommended to use them since the
|
||||
compiler can optimize them on certain CPUs.
|
||||
|
||||
----------------------------------------------------------------
|
||||
Generating functions
|
||||
----------------------------------------------------------------
|
||||
|
||||
SLJIT is often used for generating function bodies which are
|
||||
called from C. SLJIT provides two complex instructions for
|
||||
generating function entry and return: sljit_emit_enter and
|
||||
sljit_emit_return. The sljit_emit_enter also initializes the
|
||||
"compiling context" which specify the current register mapping,
|
||||
local space size, etc. configurations. The sljit_set_context
|
||||
can also set this context without emitting any machine
|
||||
instructions.
|
||||
|
||||
This context is important since it affects the compiler, so
|
||||
the first instruction after a compiler is created must be
|
||||
either sljit_emit_enter or sljit_set_context. The context can
|
||||
be changed by calling sljit_emit_enter or sljit_set_context
|
||||
again.
|
||||
|
||||
----------------------------------------------------------------
|
||||
All-in-one building
|
||||
----------------------------------------------------------------
|
||||
|
||||
Instead of using a separate library, the whole SLJIT
|
||||
compiler infrastructure can be directly included:
|
||||
|
||||
#define SLJIT_CONFIG_STATIC 1
|
||||
#include "sljitLir.c"
|
||||
|
||||
This approach is useful for single file compilers.
|
||||
|
||||
Advantages:
|
||||
- Everything provided by SLJIT is available
|
||||
(no need to include anything else).
|
||||
- Configuring SLJIT is easy
|
||||
(e.g. redefining SLJIT_MALLOC / SLJIT_FREE).
|
||||
- The SLJIT compiler API is hidden from the
|
||||
world which improves securtity.
|
||||
- The C compiler can optimize the SLJIT code
|
||||
generator (e.g. removing unused functions).
|
||||
|
||||
----------------------------------------------------------------
|
||||
Types and macros
|
||||
----------------------------------------------------------------
|
||||
|
||||
The sljitConfig.h contains those defines, which controls
|
||||
the compiler. The beginning of sljitConfigInternal.h
|
||||
lists architecture specific types and macros provided
|
||||
by SLJIT. Some of these macros:
|
||||
|
||||
SLJIT_DEBUG : enabled by default
|
||||
Enables assertions. Should be disabled in release mode.
|
||||
|
||||
SLJIT_VERBOSE : enabled by default
|
||||
When this macro is enabled, the sljit_compiler_verbose
|
||||
function can be used to dump SLJIT instructions.
|
||||
Otherwise this function is not available. Should be
|
||||
disabled in release mode.
|
||||
|
||||
SLJIT_SINGLE_THREADED : disabled by default
|
||||
Single threaded programs can define this flag which
|
||||
eliminates the pthread dependency.
|
||||
|
||||
sljit_sw, sljit_uw, etc. :
|
||||
It is recommended to use these types instead of long,
|
||||
intptr_t, etc. Improves readability / portability of
|
||||
the code.
|
|
@ -1,247 +0,0 @@
|
|||
##########################
|
||||
###
|
||||
### Severely updated version!
|
||||
### (now says "1 bottle" and
|
||||
### contains no extra "0" verse)
|
||||
###
|
||||
##########################
|
||||
### 99 Bottles of Beer ###
|
||||
### coded in Brainfuck ###
|
||||
### with explanations ###
|
||||
##########################
|
||||
#
|
||||
# This Bottles of Beer program
|
||||
# was written by Andrew Paczkowski
|
||||
# Coder Alias: thepacz
|
||||
# three_halves_plus_one@yahoo.com
|
||||
#####
|
||||
|
||||
> 0 in the zeroth cell
|
||||
+++++++>++++++++++[<+++++>-] 57 in the first cell or "9"
|
||||
+++++++>++++++++++[<+++++>-] 57 in second cell or "9"
|
||||
++++++++++ 10 in third cell
|
||||
>+++++++++ 9 in fourth cell
|
||||
|
||||
##########################################
|
||||
### create ASCII chars in higher cells ###
|
||||
##########################################
|
||||
|
||||
>>++++++++[<++++>-] " "
|
||||
>++++++++++++++[<+++++++>-] b
|
||||
+>+++++++++++[<++++++++++>-] o
|
||||
++>+++++++++++++++++++[<++++++>-] t
|
||||
++>+++++++++++++++++++[<++++++>-] t
|
||||
>++++++++++++[<+++++++++>-] l
|
||||
+>++++++++++[<++++++++++>-] e
|
||||
+>+++++++++++++++++++[<++++++>-] s
|
||||
>++++++++[<++++>-] " "
|
||||
+>+++++++++++[<++++++++++>-] o
|
||||
++>++++++++++[<++++++++++>-] f
|
||||
>++++++++[<++++>-] " "
|
||||
>++++++++++++++[<+++++++>-] b
|
||||
+>++++++++++[<++++++++++>-] e
|
||||
+>++++++++++[<++++++++++>-] e
|
||||
>+++++++++++++++++++[<++++++>-] r
|
||||
>++++++++[<++++>-] " "
|
||||
+>+++++++++++[<++++++++++>-] o
|
||||
>+++++++++++[<++++++++++>-] n
|
||||
>++++++++[<++++>-] " "
|
||||
++>+++++++++++++++++++[<++++++>-] t
|
||||
++++>++++++++++[<++++++++++>-] h
|
||||
+>++++++++++[<++++++++++>-] e
|
||||
>++++++++[<++++>-] " "
|
||||
++>+++++++++++++[<+++++++++>-] w
|
||||
+>++++++++++++[<++++++++>-] a
|
||||
>++++++++++++[<+++++++++>-] l
|
||||
>++++++++++++[<+++++++++>-] l
|
||||
>+++++[<++>-] LF
|
||||
++>+++++++++++++++++++[<++++++>-] t
|
||||
+>++++++++++++[<++++++++>-] a
|
||||
+++>+++++++++++++[<++++++++>-] k
|
||||
+>++++++++++[<++++++++++>-] e
|
||||
>++++++++[<++++>-] " "
|
||||
+>+++++++++++[<++++++++++>-] o
|
||||
>+++++++++++[<++++++++++>-] n
|
||||
+>++++++++++[<++++++++++>-] e
|
||||
>++++++++[<++++>-] " "
|
||||
>++++++++++[<++++++++++>-] d
|
||||
+>+++++++++++[<++++++++++>-] o
|
||||
++>+++++++++++++[<+++++++++>-] w
|
||||
>+++++++++++[<++++++++++>-] n
|
||||
>++++++++[<++++>-] " "
|
||||
+>++++++++++++[<++++++++>-] a
|
||||
>+++++++++++[<++++++++++>-] n
|
||||
>++++++++++[<++++++++++>-] d
|
||||
>++++++++[<++++>-] " "
|
||||
++>+++++++++++[<++++++++++>-] p
|
||||
+>++++++++++++[<++++++++>-] a
|
||||
+>+++++++++++++++++++[<++++++>-] s
|
||||
+>+++++++++++++++++++[<++++++>-] s
|
||||
>++++++++[<++++>-] " "
|
||||
+>+++++++++++++[<++++++++>-] i
|
||||
++>+++++++++++++++++++[<++++++>-] t
|
||||
>++++++++[<++++>-] " "
|
||||
+>++++++++++++[<++++++++>-] a
|
||||
>+++++++++++++++++++[<++++++>-] r
|
||||
+>+++++++++++[<++++++++++>-] o
|
||||
>+++++++++++++[<+++++++++>-] u
|
||||
>+++++++++++[<++++++++++>-] n
|
||||
>++++++++++[<++++++++++>-] d
|
||||
>+++++[<++>-] LF
|
||||
+++++++++++++ CR
|
||||
|
||||
[<]>>>> go back to fourth cell
|
||||
|
||||
#################################
|
||||
### initiate the display loop ###
|
||||
#################################
|
||||
|
||||
[ loop
|
||||
< back to cell 3
|
||||
[ loop
|
||||
[>]<< go to last cell and back to LF
|
||||
.. output 2 newlines
|
||||
[<]> go to first cell
|
||||
|
||||
###################################
|
||||
#### begin display of characters###
|
||||
###################################
|
||||
#
|
||||
#.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#X X b o t t l e s o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l N
|
||||
#[<]> go to first cell
|
||||
#.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>>>>>>>>>>>>>.>
|
||||
#X X b o t t l e s o f b e e r N
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#t a k e o n e d o w n a n d p a s s
|
||||
#.>.>.>.>.>.>.>.>.>.
|
||||
#i t a r o u n d N
|
||||
#####
|
||||
|
||||
[<]>> go to cell 2
|
||||
- subtract 1 from cell 2
|
||||
< go to cell 1
|
||||
|
||||
########################
|
||||
### display last line ##
|
||||
########################
|
||||
#
|
||||
#.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#X X b o t t l e s o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l
|
||||
#####
|
||||
|
||||
[<]>>>- go to cell 3/subtract 1
|
||||
] end loop when cell 3 is 0
|
||||
++++++++++ add 10 to cell 3
|
||||
<++++++++++ back to cell 2/add 10
|
||||
<- back to cell 1/subtract 1
|
||||
[>]<. go to last line/carriage return
|
||||
[<]> go to first line
|
||||
|
||||
########################
|
||||
### correct last line ##
|
||||
########################
|
||||
#
|
||||
#.>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#X X b o t t l e s o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l
|
||||
#####
|
||||
|
||||
[<]>>>>- go to cell 4/subtract 1
|
||||
] end loop when cell 4 is 0
|
||||
|
||||
##############################################################
|
||||
### By this point verses 9910 are displayed but to work ###
|
||||
### with the lower numbered verses in a more readable way ###
|
||||
### we initiate a new loop for verses 9{CODE} that will not ###
|
||||
### use the fourth cell at all ###
|
||||
##############################################################
|
||||
|
||||
+ add 1 to cell four (to keep it nonzero)
|
||||
<-- back to cell 3/subtract 2
|
||||
|
||||
[ loop
|
||||
[>]<< go to last cell and back to LF
|
||||
.. output 2 newlines
|
||||
[<]> go to first cell
|
||||
|
||||
###################################
|
||||
#### begin display of characters###
|
||||
###################################
|
||||
#
|
||||
#>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
# X b o t t l e s o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l N
|
||||
#[<]> go to first cell
|
||||
#>.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>>>>>>>>>>>>>.>
|
||||
# X b o t t l e s o f b e e r N
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#t a k e o n e d o w n a n d p a s s
|
||||
#.>.>.>.>.>.>.>.>.>.
|
||||
#i t a r o u n d N
|
||||
#####
|
||||
|
||||
[<]>> go to cell 2
|
||||
- subtract 1 from cell 2
|
||||
|
||||
########################
|
||||
### display last line ##
|
||||
########################
|
||||
#
|
||||
#.>>>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#X b o t t l e s o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l
|
||||
#####
|
||||
|
||||
[<]>>>- go to cell 3/subtract 1
|
||||
] end loop when cell 3 is 0
|
||||
+ add 1 to cell 3 to keep it nonzero
|
||||
|
||||
[>]<. go to last line/carriage return
|
||||
[<]> go to first line
|
||||
|
||||
########################
|
||||
### correct last line ##
|
||||
########################
|
||||
#
|
||||
#>.>>>.>.>.>.>.>.>.>>.>.>.>.>.>.>.>.>.>
|
||||
# X b o t t l e o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.<<<<.
|
||||
#o n t h e w a l l
|
||||
#####
|
||||
|
||||
[>]<< go to last cell and back to LF
|
||||
.. output 2 newlines
|
||||
[<]> go to first line
|
||||
|
||||
#########################
|
||||
### the final verse ##
|
||||
#########################
|
||||
#
|
||||
#>.>>>.>.>.>.>.>.>.>>.>.>.>.>.>.>.>.>.>
|
||||
# X b o t t l e o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l N
|
||||
#[<]> go to first cell
|
||||
#>.>>>.>.>.>.>.>.>.>>.>.>.>.>.>.>.>.>>>>>>>>>>>>>.>
|
||||
# X b o t t l e o f b e e r N
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
#t a k e o n e d o w n a n d p a s s
|
||||
#.>.>.>.>.>.>.>.>.>.
|
||||
#i t a r o u n d N
|
||||
#[>]< go to last line
|
||||
#<<<.<<.<<<.
|
||||
# n o
|
||||
#[<]>>>> go to fourth cell
|
||||
#>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>.>
|
||||
# b o t t l e s o f b e e r
|
||||
#.>.>.>.>.>.>.>.>.>.>.>.
|
||||
#o n t h e w a l l N
|
||||
#####fin##
|
|
@ -1,3 +0,0 @@
|
|||
These files were contributed by Wen Xichang.
|
||||
|
||||
Copyright 2015 Wen Xichang (wenxichang@163.com). All rights reserved.
|
|
@ -1,90 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef long (SLJIT_FUNC *func_arr_t)(long *arr, long narr);
|
||||
|
||||
static void SLJIT_FUNC print_num(long a)
|
||||
{
|
||||
printf("num = %ld\n", a);
|
||||
}
|
||||
|
||||
/*
|
||||
This example, we generate a function like this:
|
||||
|
||||
long func(long *array, long narray)
|
||||
{
|
||||
long i;
|
||||
for (i = 0; i < narray; ++i)
|
||||
print_num(array[i]);
|
||||
return narray;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
static int array_access(long *arr, long narr)
|
||||
{
|
||||
void *code;
|
||||
size_t len;
|
||||
func_arr_t func;
|
||||
struct sljit_label *loopstart;
|
||||
struct sljit_jump *out;
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS2(W, P, W), 1, 3, 0, 0, 0);
|
||||
/* opt arg R S FR FS local_size */
|
||||
|
||||
/* S2 = 0 */
|
||||
sljit_emit_op2(C, SLJIT_XOR, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_S2, 0);
|
||||
|
||||
/* S1 = narr */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_S1, 0, SLJIT_IMM, narr);
|
||||
|
||||
/* loopstart: */
|
||||
loopstart = sljit_emit_label(C);
|
||||
|
||||
/* S2 >= narr --> jumo out */
|
||||
out = sljit_emit_cmp(C, SLJIT_GREATER_EQUAL, SLJIT_S2, 0, SLJIT_S1, 0);
|
||||
|
||||
/* R0 = (long *)S0[S2]; */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM2(SLJIT_S0, SLJIT_S2), SLJIT_WORD_SHIFT);
|
||||
|
||||
/* print_num(R0) */
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1V(W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* S2 += 1 */
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_IMM, 1);
|
||||
|
||||
/* jump loopstart */
|
||||
sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loopstart);
|
||||
|
||||
/* out: */
|
||||
sljit_set_label(out, sljit_emit_label(C));
|
||||
|
||||
/* return S1 */
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_S1, 0);
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (func_arr_t)code;
|
||||
printf("func return %ld\n", func(arr, narr));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
long arr[8] = { 3, -10, 4, 6, 8, 12, 2000, 0 };
|
||||
return array_access(arr, 8);
|
||||
}
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
* Brainfuck interpreter with SLJIT
|
||||
*
|
||||
* Copyright 2015 Wen Xichang (wenxichang@163.com). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BF_CELL_SIZE 3000
|
||||
#define BF_LOOP_LEVEL 256
|
||||
|
||||
static int readvalid(FILE *src)
|
||||
{
|
||||
int chr;
|
||||
|
||||
while ((chr = fgetc(src)) != EOF) {
|
||||
switch (chr) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '>':
|
||||
case '<':
|
||||
case '.':
|
||||
case ',':
|
||||
case '[':
|
||||
case ']':
|
||||
return chr;
|
||||
}
|
||||
}
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
||||
/* reading same instruction, and count, for optimization */
|
||||
/* ++++ -> '+', 4 */
|
||||
static int gettoken(FILE *src, int *ntok)
|
||||
{
|
||||
int chr = readvalid(src);
|
||||
int chr2;
|
||||
int cnt = 1;
|
||||
|
||||
if (chr == EOF)
|
||||
return EOF;
|
||||
|
||||
if (chr == '.' || chr == ',' || chr == '[' || chr == ']') {
|
||||
*ntok = 1;
|
||||
return chr;
|
||||
}
|
||||
|
||||
while ((chr2 = readvalid(src)) == chr)
|
||||
cnt++;
|
||||
|
||||
if (chr2 != EOF)
|
||||
ungetc(chr2, src);
|
||||
|
||||
*ntok = cnt;
|
||||
return chr;
|
||||
}
|
||||
|
||||
/* maintaining loop matched [] */
|
||||
struct loop_node_st {
|
||||
struct sljit_label *loop_start;
|
||||
struct sljit_jump *loop_end;
|
||||
};
|
||||
|
||||
/* stack of loops */
|
||||
static struct loop_node_st loop_stack[BF_LOOP_LEVEL];
|
||||
static int loop_sp;
|
||||
|
||||
static int loop_push(struct sljit_label *loop_start, struct sljit_jump *loop_end)
|
||||
{
|
||||
if (loop_sp >= BF_LOOP_LEVEL)
|
||||
return -1;
|
||||
|
||||
loop_stack[loop_sp].loop_start = loop_start;
|
||||
loop_stack[loop_sp].loop_end = loop_end;
|
||||
loop_sp++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loop_pop(struct sljit_label **loop_start, struct sljit_jump **loop_end)
|
||||
{
|
||||
if (loop_sp <= 0)
|
||||
return -1;
|
||||
|
||||
loop_sp--;
|
||||
*loop_start = loop_stack[loop_sp].loop_start;
|
||||
*loop_end = loop_stack[loop_sp].loop_end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *SLJIT_FUNC my_alloc(size_t size, size_t n)
|
||||
{
|
||||
return calloc(size, n);
|
||||
}
|
||||
|
||||
static void SLJIT_FUNC my_putchar(long c)
|
||||
{
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
static long SLJIT_FUNC my_getchar(void)
|
||||
{
|
||||
return getchar();
|
||||
}
|
||||
|
||||
static void SLJIT_FUNC my_free(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
#define loop_empty() (loop_sp == 0)
|
||||
|
||||
/* compile bf source to a void func() */
|
||||
static void *compile(FILE *src, unsigned long *lcode)
|
||||
{
|
||||
void *code = NULL;
|
||||
int chr;
|
||||
int nchr;
|
||||
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
struct sljit_jump *end;
|
||||
struct sljit_label *loop_start;
|
||||
struct sljit_jump *loop_end;
|
||||
|
||||
int SP = SLJIT_S0; /* bf SP */
|
||||
int CELLS = SLJIT_S1; /* bf array */
|
||||
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS2V(W, W), 2, 2, 0, 0, 0);
|
||||
/* opt arg R S FR FS local_size */
|
||||
|
||||
/* SP = 0 */
|
||||
sljit_emit_op2(C, SLJIT_XOR, SP, 0, SP, 0, SP, 0);
|
||||
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, BF_CELL_SIZE);
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 1);
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS2(P, W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(my_alloc));/* calloc(BF_CELL_SIZE, 1) => R0 */
|
||||
|
||||
end = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); /* R0 == 0 --> jump end */
|
||||
|
||||
sljit_emit_op1(C, SLJIT_MOV, CELLS, 0, SLJIT_R0, 0); /* CELLS = R0 */
|
||||
|
||||
while ((chr = gettoken(src, &nchr)) != EOF) {
|
||||
switch (chr) {
|
||||
case '+':
|
||||
case '-':
|
||||
sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */
|
||||
sljit_emit_op2(C, chr == '+' ? SLJIT_ADD : SLJIT_SUB,
|
||||
SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, nchr); /* R0 ?= nchr */
|
||||
sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_MEM2(CELLS, SP), 0, SLJIT_R0, 0); /* CELLS[SP] = R0 */
|
||||
break;
|
||||
case '>':
|
||||
case '<':
|
||||
sljit_emit_op2(C, chr == '>' ? SLJIT_ADD : SLJIT_SUB,
|
||||
SP, 0, SP, 0, SLJIT_IMM, nchr); /* SP ?= nchr */
|
||||
break;
|
||||
case '.':
|
||||
sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(my_putchar)); /* putchar(R0) */
|
||||
break;
|
||||
case ',':
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS0(W), SLJIT_IMM, SLJIT_FUNC_ADDR(my_getchar)); /* R0 = getchar() */
|
||||
sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_MEM2(CELLS, SP), 0, SLJIT_R0, 0); /* CELLS[SP] = R0 */
|
||||
break;
|
||||
case '[':
|
||||
loop_start = sljit_emit_label(C); /* loop_start: */
|
||||
sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R0, 0, SLJIT_MEM2(CELLS, SP), 0); /* R0 = CELLS[SP] */
|
||||
loop_end = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0); /* IF R0 == 0 goto loop_end */
|
||||
|
||||
if (loop_push(loop_start, loop_end)) {
|
||||
fprintf(stderr, "Too many loop level\n");
|
||||
goto compile_failed;
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
if (loop_pop(&loop_start, &loop_end)) {
|
||||
fprintf(stderr, "Unmatch loop ]\n");
|
||||
goto compile_failed;
|
||||
}
|
||||
|
||||
sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loop_start); /* goto loop_start */
|
||||
sljit_set_label(loop_end, sljit_emit_label(C)); /* loop_end: */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loop_empty()) {
|
||||
fprintf(stderr, "Unmatch loop [\n");
|
||||
goto compile_failed;
|
||||
}
|
||||
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, CELLS, 0);
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(P, P), SLJIT_IMM, SLJIT_FUNC_ADDR(my_free)); /* free(CELLS) */
|
||||
|
||||
sljit_set_label(end, sljit_emit_label(C));
|
||||
sljit_emit_return_void(C);
|
||||
|
||||
code = sljit_generate_code(C);
|
||||
if (lcode)
|
||||
*lcode = sljit_get_generated_code_size(C);
|
||||
|
||||
compile_failed:
|
||||
sljit_free_compiler(C);
|
||||
return code;
|
||||
}
|
||||
|
||||
/* function prototype of bf compiled code */
|
||||
typedef void (*bf_entry_t)(void);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *code;
|
||||
bf_entry_t entry;
|
||||
FILE *fp;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <brainfuck program>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (!fp) {
|
||||
perror("open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
code = compile(fp, NULL);
|
||||
fclose(fp);
|
||||
|
||||
if (!code) {
|
||||
fprintf(stderr, "[Fatal]: Compile failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry = (bf_entry_t)code;
|
||||
entry();
|
||||
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef long (SLJIT_FUNC *func3_t)(long a, long b, long c);
|
||||
|
||||
/*
|
||||
This example, we generate a function like this:
|
||||
|
||||
long func(long a, long b, long c)
|
||||
{
|
||||
if ((a & 1) == 0)
|
||||
return c;
|
||||
return b;
|
||||
}
|
||||
|
||||
*/
|
||||
static int branch(long a, long b, long c)
|
||||
{
|
||||
void *code;
|
||||
unsigned long len;
|
||||
func3_t func;
|
||||
|
||||
struct sljit_jump *ret_c;
|
||||
struct sljit_jump *out;
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
/* 3 arg, 1 temp reg, 3 save reg */
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 1, 3, 0, 0, 0);
|
||||
|
||||
/* R0 = a & 1, S0 is argument a */
|
||||
sljit_emit_op2(C, SLJIT_AND, SLJIT_R0, 0, SLJIT_S0, 0, SLJIT_IMM, 1);
|
||||
|
||||
/* if R0 == 0 then jump to ret_c, where is ret_c? we assign it later */
|
||||
ret_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0);
|
||||
|
||||
/* R0 = b, S1 is argument b */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S1, 0);
|
||||
|
||||
/* jump to out */
|
||||
out = sljit_emit_jump(C, SLJIT_JUMP);
|
||||
|
||||
/* here is the 'ret_c' should jump, we emit a label and set it to ret_c */
|
||||
sljit_set_label(ret_c, sljit_emit_label(C));
|
||||
|
||||
/* R0 = c, S2 is argument c */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S2, 0);
|
||||
|
||||
/* here is the 'out' should jump */
|
||||
sljit_set_label(out, sljit_emit_label(C));
|
||||
|
||||
/* end of function */
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0);
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (func3_t)code;
|
||||
printf("func return %ld\n", func(a, b, c));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return branch(4, 5, 6);
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef long (SLJIT_FUNC *func3_t)(long a, long b, long c);
|
||||
|
||||
static int add3(long a, long b, long c)
|
||||
{
|
||||
void *code;
|
||||
unsigned long len;
|
||||
func3_t func;
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
/* Start a context(function entry), have 3 arguments, discuss later */
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 1, 3, 0, 0, 0);
|
||||
|
||||
/* The first arguments of function is register SLJIT_S0, 2nd, SLJIT_S1, etc. */
|
||||
/* R0 = first */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S0, 0);
|
||||
|
||||
/* R0 = R0 + second */
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S1, 0);
|
||||
|
||||
/* R0 = R0 + third */
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S2, 0);
|
||||
|
||||
/* This statement mov R0 to RETURN REG and return */
|
||||
/* in fact, R0 is RETURN REG itself */
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0);
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (func3_t)code;
|
||||
printf("func return %ld\n", func(a, b, c));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return add3(4, 5, 6);
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef long (SLJIT_FUNC *func3_t)(long a, long b, long c);
|
||||
|
||||
static long SLJIT_FUNC print_num(long a)
|
||||
{
|
||||
printf("a = %ld\n", a);
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
This example, we generate a function like this:
|
||||
|
||||
long func(long a, long b, long c)
|
||||
{
|
||||
if ((a & 1) == 0)
|
||||
return print_num(c);
|
||||
return print_num(b);
|
||||
}
|
||||
*/
|
||||
|
||||
static int func_call(long a, long b, long c)
|
||||
{
|
||||
void *code;
|
||||
unsigned long len;
|
||||
func3_t func;
|
||||
|
||||
struct sljit_jump *out;
|
||||
struct sljit_jump *print_c;
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 3, 3, 0, 0, 0);
|
||||
|
||||
/* a & 1 --> R0 */
|
||||
sljit_emit_op2(C, SLJIT_AND, SLJIT_R0, 0, SLJIT_S0, 0, SLJIT_IMM, 1);
|
||||
/* R0 == 0 --> jump print_c */
|
||||
print_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0);
|
||||
|
||||
/* R0 = S1; print_num(R0) */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S1, 0);
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* jump out */
|
||||
out = sljit_emit_jump(C, SLJIT_JUMP);
|
||||
/* print_c: */
|
||||
sljit_set_label(print_c, sljit_emit_label(C));
|
||||
|
||||
/* R0 = c; print_num(R0); */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S2, 0);
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* out: */
|
||||
sljit_set_label(out, sljit_emit_label(C));
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0);
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (func3_t)code;
|
||||
printf("func return %ld\n", func(a, b, c));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return func_call(4, 5, 6);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
+++++ +++++ initialize counter (cell #0) to 10\
|
||||
[ use loop to set the next four cells to 70/100/30/10\
|
||||
> +++++ ++ add 7 to cell #1\
|
||||
> +++++ +++++ add 10 to cell #2 \
|
||||
> +++ add 3 to cell #3\
|
||||
> + add 1 to cell #4\
|
||||
<<<< - decrement counter (cell #0)\
|
||||
]\
|
||||
> ++ . print 'H'\
|
||||
> + . print 'e'\
|
||||
+++++ ++ . print 'l'\
|
||||
. print 'l'\
|
||||
+++ . print 'o'\
|
||||
> ++ . print ' '\
|
||||
<< +++++ +++++ +++++ . print 'W'\
|
||||
> . print 'o'\
|
||||
+++ . print 'r'\
|
||||
----- - . print 'l'\
|
||||
----- --- . print 'd'\
|
||||
> + . print '!'\
|
||||
> . print '\n'\
|
|
@ -1,76 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef long (SLJIT_FUNC *func2_t)(long a, long b);
|
||||
|
||||
/*
|
||||
This example, we generate a function like this:
|
||||
|
||||
long func(long a, long b)
|
||||
{
|
||||
long i;
|
||||
long ret = 0;
|
||||
for (i = 0; i < a; ++i) {
|
||||
ret += b;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
static int loop(long a, long b)
|
||||
{
|
||||
void *code;
|
||||
unsigned long len;
|
||||
func2_t func;
|
||||
|
||||
struct sljit_label *loopstart;
|
||||
struct sljit_jump *out;
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
/* 2 arg, 2 temp reg, 2 saved reg */
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS2(W, W, W), 2, 2, 0, 0, 0);
|
||||
|
||||
/* R0 = 0 */
|
||||
sljit_emit_op2(C, SLJIT_XOR, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_R1, 0);
|
||||
/* RET = 0 */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
|
||||
/* loopstart: */
|
||||
loopstart = sljit_emit_label(C);
|
||||
/* R1 >= a --> jump out */
|
||||
out = sljit_emit_cmp(C, SLJIT_GREATER_EQUAL, SLJIT_R1, 0, SLJIT_S0, 0);
|
||||
/* RET += b */
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0, SLJIT_S1, 0);
|
||||
/* R1 += 1 */
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
|
||||
/* jump loopstart */
|
||||
sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loopstart);
|
||||
/* out: */
|
||||
sljit_set_label(out, sljit_emit_label(C));
|
||||
|
||||
/* return RET */
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0);
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (func2_t)code;
|
||||
printf("func return %ld\n", func(a, b));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return loop(4, 5);
|
||||
}
|
|
@ -1,584 +0,0 @@
|
|||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>SLJIT tutorial</title>
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #707070;
|
||||
color: #000000;
|
||||
font-family: "garamond"
|
||||
}
|
||||
td.main {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
font-family: "garamond"
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<table width="760" cellspacing=0 cellpadding=0>
|
||||
<tr height=20><td width=20 class="main"></td><td width=720 class="main"></td><td width=20 class="main"></td></tr>
|
||||
<tr><td width=20 class="main"></td><td width=720 class="main">
|
||||
|
||||
<center>
|
||||
<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=248047&type=2" width="125" height="37" border="0" alt="SourceForge.net Logo" /></a>
|
||||
</center>
|
||||
<h1><center>SLJIT tutorial</center></h1>
|
||||
|
||||
<h2>Before started</h2>
|
||||
|
||||
<a href="">Download the tutorial sources</a><br>
|
||||
<br>
|
||||
SLJIT is a light-weight, platform independent JIT compiler, it's easy to
|
||||
embed to your own project, as a result of its 'stack-less', SLJIT have
|
||||
some limit to register usage.<br>
|
||||
<br>
|
||||
Here is some other JIT compiler I digged these days, place here if you have interest:<br>
|
||||
|
||||
<ul>
|
||||
<b>Libjit/liblighning:</b> - the backend of GNU.net<br>
|
||||
<b>Libgccjit:</b> - introduced in GCC5.0, its different from other JIT lib, this
|
||||
one seems like constructing a C code, it use the backend of GCC.<br>
|
||||
<b>AsmJIT:</b> - branch from the famous V8 project (JavaScript engine in Chrome),
|
||||
support only X86/X86_64.<br>
|
||||
<b>DynASM:</b> - used in LuaJIT.<br>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
AsmJIT and DynASM work in the instruction level, look like coding with ASM language,
|
||||
SLJIT look like ASM also, but it hide the detail of the specific CPU, make it more
|
||||
common, and become portable, libjit work on higher layer, libgccjit as I mention,
|
||||
really you are constructing the C code.<br>
|
||||
|
||||
<h2>First program</h2>
|
||||
|
||||
Usage of SLJIT:
|
||||
<ul>
|
||||
1. #include "sljitLir.h" in the head of your C/C++ program<br>
|
||||
2. Compile with sljit_src/sljitLir.c<br>
|
||||
</ul>
|
||||
|
||||
ALL example can be compile like this:
|
||||
<ul>
|
||||
gcc -Wall -Ipath/to/sljit_src -DSLJIT_CONFIG_AUTO=1 \<br>
|
||||
<ul><b>xxx.c</b> path/to/sljit_src/sljitLir.c -o program</ul>
|
||||
</ul>
|
||||
|
||||
OK, let's take a look at the first program, this program we create a function that
|
||||
return the sum of 3 arguments.<br>
|
||||
<br>
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
#include "sljitLir.h"<br>
|
||||
<br>
|
||||
#include <stdio.h><br>
|
||||
#include <stdlib.h><br>
|
||||
<br>
|
||||
typedef sljit_sw (*func3_t)(sljit_sw a, sljit_sw b, sljit_sw c);<br>
|
||||
<br>
|
||||
static int add3(sljit_sw a, sljit_sw b, sljit_sw c)<br>
|
||||
{<br>
|
||||
<ul>
|
||||
void *code;<br>
|
||||
sljit_sw len;<br>
|
||||
func3_t func;<br>
|
||||
<br>
|
||||
/* Create a SLJIT compiler */<br>
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);<br>
|
||||
<br>
|
||||
/* Start a context(function entry), has 3 arguments, discuss later */<br>
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 1, 3, 0, 0, 0);<br>
|
||||
<br>
|
||||
/* The first arguments of function is register SLJIT_S0, 2nd, SLJIT_S1, etc. */<br>
|
||||
/* R0 = first */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S0, 0);<br>
|
||||
<br>
|
||||
/* R0 = R0 + second */<br>
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S1, 0);<br>
|
||||
<br>
|
||||
/* R0 = R0 + third */<br>
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S2, 0);<br>
|
||||
<br>
|
||||
/* This statement mov R0 to RETURN REG and return */<br>
|
||||
/* in fact, R0 is RETURN REG itself */<br>
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0);<br>
|
||||
<br>
|
||||
/* Generate machine code */<br>
|
||||
code = sljit_generate_code(C);<br>
|
||||
len = sljit_get_generated_code_size(C);<br>
|
||||
<br>
|
||||
/* Execute code */<br>
|
||||
func = (func3_t)code;<br>
|
||||
printf("func return %ld\n", func(a, b, c));<br>
|
||||
<br>
|
||||
/* dump_code(code, len); */<br>
|
||||
<br>
|
||||
/* Clean up */<br>
|
||||
sljit_free_compiler(C);<br>
|
||||
sljit_free_code(code, NULL);<br>
|
||||
return 0;<br>
|
||||
</ul>
|
||||
}<br>
|
||||
<br>
|
||||
int main()<br>
|
||||
{<br>
|
||||
<ul>
|
||||
return add3(4, 5, 6);<br>
|
||||
</ul>
|
||||
}<br>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
The function sljit_emit_enter create a context, save some registers to the stack,
|
||||
and create a call-frame, sljit_emit_return restore the saved-register and clean-up
|
||||
the frame. SLJIT is design to embed into other application, the code it generated
|
||||
has to follow some basic rule.<br>
|
||||
<br>
|
||||
The standard called Application Binary Interface, or ABI for short, here is a
|
||||
document for X86_64 CPU (<a href="http://www.x86-64.org/documentation/abi.pdf">ABI.pdf</a>),
|
||||
almost all Linux/Unix follow this standard. MS windows has its own, read this for more:
|
||||
<a href="http://en.wikipedia.org/wiki/X86_calling_conventions">X86_calling_conventions</a><br>
|
||||
<br>
|
||||
When reading the doc of sljit_emit_emter, the parameters 'saveds' and 'scratchs' make
|
||||
me confused. The fact is, the registers in CPU has different functions in the ABI spec,
|
||||
some of them used to pass arguments, some of them are 'callee-saved', some of them are
|
||||
'temporary used', take X86_64 for example, RAX, R10, R11 are temporary used, that means,
|
||||
they may be changed after a call instruction. And RBX, R12-R15 are callee-saved, those
|
||||
will remain the same values after the call. The rule is, every function should save
|
||||
those registers before using it.<br>
|
||||
<br>
|
||||
Fortunately, SLJIT have done the most for us, SLJIT_S[0-9] represent those 'safe'
|
||||
registers, SLJIT_R[0-9] however, only for 'temporary used'.<br>
|
||||
<br>
|
||||
When a function start, SLJIT move the function arguments to S0, S1, S2 register, it
|
||||
means function arguments are always 'safe' in the context; a maximum of 4
|
||||
arguments is supported by SLJIT.<br>
|
||||
<br>
|
||||
Sljit_emit_opX is easy to understand, in SLJIT a data value is represented by 2
|
||||
parameters, it can be a register, an In-memory data, or an immediate number.<br>
|
||||
<br>
|
||||
|
||||
<table align="center" cellspacing="0">
|
||||
<tr><td>First parameter</td> <td>Second parameter</td> <td>Meaning</td></tr>
|
||||
<tr><td>SLJIT_R*, SLJIT_S*</td> <td>0</td> <td>Temp/saved registers</td></tr>
|
||||
<tr><td>SLJIT_IMM</td> <td>Number</td> <td>Immediate number</td></tr>
|
||||
<tr><td>SLJIT_MEM</td> <td>Address</td> <td>In-mem data with Absolute address</td></tr>
|
||||
<tr><td>SLJIT_MEM1(r)</td> <td>Offset</td> <td>In-mem data in [R + offset]</td></tr>
|
||||
<tr><td>SLJIT_MEM2(r1, r2)</td> <td>Shift(size)</td> <td>In-mem array, R1 as base address, R2 as index, <br>
|
||||
Shift as size(0 for bytes, 1 for shorts, 2 for <br>
|
||||
4bytes, 3 for 8bytes)</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Branch</h2>
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
#include "sljitLir.h"<br>
|
||||
<br>
|
||||
#include <stdio.h><br>
|
||||
#include <stdlib.h><br>
|
||||
<br>
|
||||
typedef sljit_sw (*func3_t)(sljit_sw a, sljit_sw b, sljit_sw c);<br>
|
||||
<br>
|
||||
/*<br>
|
||||
This example, we generate a function like this:<br>
|
||||
<br>
|
||||
sljit_sw func(sljit_sw a, sljit_sw b, sljit_sw c)<br>
|
||||
{<br>
|
||||
<ul>
|
||||
if ((a & 1) == 0)<br>
|
||||
<ul>
|
||||
return c;<br>
|
||||
</ul>
|
||||
return b;<br>
|
||||
</ul>
|
||||
}<br>
|
||||
<br>
|
||||
*/<br>
|
||||
static int branch(sljit_sw a, sljit_sw b, sljit_sw c)<br>
|
||||
{<br>
|
||||
<ul>
|
||||
void *code;<br>
|
||||
sljit_uw len;<br>
|
||||
func3_t func;<br>
|
||||
<br>
|
||||
struct sljit_jump *ret_c;<br>
|
||||
struct sljit_jump *out;<br>
|
||||
<br>
|
||||
/* Create a SLJIT compiler */<br>
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);<br>
|
||||
<br>
|
||||
/* 3 arg, 1 temp reg, 3 save reg */<br>
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 1, 3, 0, 0, 0);<br>
|
||||
<br>
|
||||
/* R0 = a & 1, S0 is argument a */<br>
|
||||
sljit_emit_op2(C, SLJIT_AND, SLJIT_R0, 0, SLJIT_S0, 0, SLJIT_IMM, 1);<br>
|
||||
<br>
|
||||
/* if R0 == 0 then jump to ret_c, where is ret_c? we assign it later */<br>
|
||||
ret_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0);<br>
|
||||
<br>
|
||||
/* R0 = b, S1 is argument b */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S1, 0);<br>
|
||||
<br>
|
||||
/* jump to out */<br>
|
||||
out = sljit_emit_jump(C, SLJIT_JUMP);<br>
|
||||
<br>
|
||||
/* here is the 'ret_c' should jump, we emit a label and set it to ret_c */<br>
|
||||
sljit_set_label(ret_c, sljit_emit_label(C));<br>
|
||||
<br>
|
||||
/* R0 = c, S2 is argument c */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_S2, 0);<br>
|
||||
<br>
|
||||
/* here is the 'out' should jump */<br>
|
||||
sljit_set_label(out, sljit_emit_label(C));<br>
|
||||
<br>
|
||||
/* end of function */<br>
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0);<br>
|
||||
<br>
|
||||
/* Generate machine code */<br>
|
||||
code = sljit_generate_code(C);<br>
|
||||
len = sljit_get_generated_code_size(C);<br>
|
||||
<br>
|
||||
/* Execute code */<br>
|
||||
func = (func3_t)code;<br>
|
||||
printf("func return %ld\n", func(a, b, c));<br>
|
||||
<br>
|
||||
/* dump_code(code, len); */<br>
|
||||
<br>
|
||||
/* Clean up */<br>
|
||||
sljit_free_compiler(C);<br>
|
||||
sljit_free_code(code, NULL);<br>
|
||||
return 0;<br>
|
||||
</ul>
|
||||
}<br>
|
||||
<br>
|
||||
int main()<br>
|
||||
{<br>
|
||||
<ul>
|
||||
return branch(4, 5, 6);<br>
|
||||
</ul>
|
||||
}<br>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
The key to implement branch is 'struct sljit_jump' and 'struct sljit_label',
|
||||
the 'jump' contain a jump instruction, it does not know where to jump unless
|
||||
you set a label to it, the 'label' is a code address just like label in ASM
|
||||
language.<br>
|
||||
<br>
|
||||
sljit_emit_cmp/sljit_emit_jump generate a conditional/unconditional jump,
|
||||
take the statement<br>
|
||||
<ul>
|
||||
ret_c = sljit_emit_cmp(C, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0);<br>
|
||||
</ul>
|
||||
For example, it create a jump instruction, the condition is R0 equals 0, and
|
||||
the position of jumping will assign later with the sljit_set_label statement.<br>
|
||||
<br>
|
||||
In this example, it creates a branch like this:<br>
|
||||
<ul>
|
||||
<ul>
|
||||
R0 = a & 1;<br>
|
||||
if R0 == 0 then goto ret_c;<br>
|
||||
R0 = b;<br>
|
||||
goto out;<br>
|
||||
</ul>
|
||||
ret_c:<br>
|
||||
<ul>
|
||||
R0 = c;<br>
|
||||
</ul>
|
||||
out:<br>
|
||||
<ul>
|
||||
return R0;<br>
|
||||
</ul>
|
||||
</ul>
|
||||
<br>
|
||||
This is how high-level-language compiler handle branch.<br>
|
||||
<br>
|
||||
|
||||
<h2>Loop</h2>
|
||||
|
||||
Loop example is similar with Branch.
|
||||
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
/*
|
||||
This example, we generate a function like this:<br>
|
||||
<br>
|
||||
sljit_sw func(sljit_sw a, sljit_sw b)<br>
|
||||
{<br>
|
||||
<ul>
|
||||
sljit_sw i;<br>
|
||||
sljit_sw ret = 0;<br>
|
||||
for (i = 0; i < a; ++i) {<br>
|
||||
<ul>
|
||||
ret += b;<br>
|
||||
</ul>
|
||||
}<br>
|
||||
return ret;<br>
|
||||
</ul>
|
||||
}<br>
|
||||
*/<br>
|
||||
<br>
|
||||
<ul>
|
||||
/* 2 arg, 2 temp reg, 2 saved reg */<br>
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS2(W, W, W), 2, 2, 0, 0, 0);<br>
|
||||
<br>
|
||||
/* R0 = 0 */<br>
|
||||
sljit_emit_op2(C, SLJIT_XOR, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_R1, 0);<br>
|
||||
/* RET = 0 */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);<br>
|
||||
/* loopstart: */<br>
|
||||
loopstart = sljit_emit_label(C);<br>
|
||||
/* R1 >= a --> jump out */<br>
|
||||
out = sljit_emit_cmp(C, SLJIT_GREATER_EQUAL, SLJIT_R1, 0, SLJIT_S0, 0);<br>
|
||||
/* RET += b */<br>
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0, SLJIT_S1, 0);<br>
|
||||
/* R1 += 1 */<br>
|
||||
sljit_emit_op2(C, SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);<br>
|
||||
/* jump loopstart */<br>
|
||||
sljit_set_label(sljit_emit_jump(C, SLJIT_JUMP), loopstart);<br>
|
||||
/* out: */<br>
|
||||
sljit_set_label(out, sljit_emit_label(C));<br>
|
||||
<br>
|
||||
/* return RET */<br>
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_RETURN_REG, 0);<br>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
After this example, you are ready to construct any program that contain complex branch
|
||||
and loop.<br>
|
||||
<br>
|
||||
Here is an interesting fact, 'xor reg, reg' is better than 'mov reg, 0', it save 2 bytes
|
||||
in X86 machine.<br>
|
||||
<br>
|
||||
I will give only the key code in the rest of this tutorial, the full source of each
|
||||
chapter can be found in the attachment.<br>
|
||||
|
||||
|
||||
<h2>Call external function</h2>
|
||||
|
||||
It's easy to call an external function in SLJIT, we use sljit_emit_icall with SLJIT_CALL
|
||||
operation to do so.<br>
|
||||
<br>
|
||||
SLJIT_CALL is use to call a function with N arguments, the number of arguments
|
||||
and the return type are defined in the third parameter from sljit_emit_icall
|
||||
just like it is done for SLJIT defined dunctions.<br>
|
||||
the arguments for the callee function are passed from SLJIT_R0, R1 and R2. Keep in mind to maintain those 'temp registers'.<br>
|
||||
<br>
|
||||
Assume that we have an external function:<br>
|
||||
<ul>
|
||||
sljit_sw print_num(sljit_sw a);
|
||||
</ul>
|
||||
|
||||
JIT code to call print_num(S1):
|
||||
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
/* R0 = S1; */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_S1, 0);<br>
|
||||
/* print_num(R0) */<br>
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));<br>
|
||||
</ul>
|
||||
</div>
|
||||
<br>
|
||||
This code call a imm-data(address of print_num), which is linked properly when the
|
||||
program loaded. There no problem in 1-time compile and execute, but when you planning
|
||||
to save to file and load/execute next time, that address may not correct as you expect,
|
||||
in some platform that support PIC, the address of print_num may relocate to another
|
||||
address in run-time. Check this out:
|
||||
<a href="http://en.wikipedia.org/wiki/Position-independent_code">PIC</a><br>
|
||||
<br>
|
||||
|
||||
<h2>Structure access</h2>
|
||||
|
||||
SLJIT use SLJIT_MEM1 to implement [Reg + offset] memory access.<br>
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
struct point_st {<br>
|
||||
<ul>
|
||||
sljit_sw x;<br>
|
||||
int y;<br>
|
||||
short z;<br>
|
||||
char d;<br>
|
||||
</ul>
|
||||
};<br>
|
||||
<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV_S32, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0),<br>
|
||||
<ul>
|
||||
SLJIT_OFFSETOF(struct point_st, y));<br>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
In this case, SLJIT_S0 is the address of the point_st structure, offset of member 'y'
|
||||
is determined in compile time, the important MOV operation always comes with a
|
||||
'signed/size' postfix, like this one _S32 means 'signed 32bits integer', the postfix
|
||||
list:<br>
|
||||
<ul>
|
||||
<b>U8</b> = unsigned byte (8 bit)<br>
|
||||
<b>S8</b> = signed byte (8 bit)<br>
|
||||
<b>U16</b> = unsigned half (16 bit)<br>
|
||||
<b>S16</b> = signed half (16 bit)<br>
|
||||
<b>U32</b> = unsigned int (32 bit)<br>
|
||||
<b>S32</b> = signed int (32 bit)<br>
|
||||
<b>P</b> = pointer (sljit_p) size<br>
|
||||
</ul>
|
||||
|
||||
<h2>Array accessing</h2>
|
||||
|
||||
SLJIT use SLJIT_MEM2 to access arrays, like this:<br>
|
||||
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM2(SLJIT_S0, SLJIT_S2),<br>
|
||||
<ul>
|
||||
SLJIT_WORD_SHIFT);
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
This statement generates a code like this:<br>
|
||||
<ul>
|
||||
WORD S0[];<br>
|
||||
R0 = S0[S2]<br>
|
||||
</ul>
|
||||
<br>
|
||||
The array S0 is declared to be WORD (using SLJIT_WORD_SHIFT), which will be sizeof(sljit_sw) in length.
|
||||
SLJIT use a 'shift' for length representation: (0 for single byte, 1 for 2
|
||||
bytes, 2 for 4 bytes, 3 for 8bytes).<br>
|
||||
<br>
|
||||
The file array_access.c demonstrate a array-print example, should be easy
|
||||
to understand.<br>
|
||||
|
||||
<h2>Local variables</h2>
|
||||
|
||||
SLJIT provide SLJIT_MEM1(SLJIT_SP) to access the reserved space in
|
||||
sljit_emit_enter's last parameter.<br>
|
||||
In this example we have to pass the address to print_arr, local variable
|
||||
is the only choice.<br>
|
||||
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
/* reserved space in stack for sljit_sw arr[3] */<br>
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 2, 3, 0, 0, 3 * sizeof(sljit_sw));<br>
|
||||
/* opt arg R S FR FS local_size */<br>
|
||||
<br>
|
||||
/* arr[0] = S0, SLJIT_SP is the init address of local var */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_S0, 0);<br>
|
||||
/* arr[1] = S1 */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 1 * sizeof(sljit_sw), SLJIT_S1, 0);<br>
|
||||
/* arr[2] = S2 */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 2 * sizeof(sljit_sw), SLJIT_S2, 0);<br>
|
||||
<br>
|
||||
/* R0 = arr; in fact SLJIT_SP is the address of arr, but can't do so in SLJIT */<br>
|
||||
sljit_get_local_base(C, SLJIT_R0, 0, 0); /* get the address of local variables */<br>
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 3); /* R1 = 3; */<br>
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS2(W, P, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_arr));<br>
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0);<br>
|
||||
</ul>
|
||||
</div>
|
||||
<br>
|
||||
SLJIT_SP can only be used in SLJIT_MEM1(SLJIT_SP). In this case, SP is the
|
||||
address of 'arr', but we cannot assign it to Reg using SLJIT_MOV opr,
|
||||
instead, we use sljit_get_local_base, which load the address and offset of
|
||||
local variable to the target.<br>
|
||||
|
||||
<h2>Brainfuck compiler</h2>
|
||||
|
||||
Ok, the basic usage of SLJIT ends here, with more detail, I suggest reading
|
||||
sljitLir.h directly, having fun hacking the wonder of SLJIT!<br>
|
||||
<br>
|
||||
The brainfuck machine introduction can be found here:
|
||||
<a href="http://en.wikipedia.org/wiki/Brainfuck">Brainfuck</a><br>
|
||||
<br>
|
||||
|
||||
<h2>Extra</h2>
|
||||
|
||||
1. Dump_code function<br>
|
||||
SLJIT didn't provide disassemble functional, this is a simple function to do this(X86 only)<br>
|
||||
<br>
|
||||
|
||||
<div style='font-family:Courier New;font-size:11px'>
|
||||
<ul>
|
||||
static void dump_code(void *code, sljit_uw len)<br>
|
||||
{<br>
|
||||
<ul>
|
||||
FILE *fp = fopen("/tmp/slj_dump", "wb");<br>
|
||||
if (!fp)<br>
|
||||
<ul>
|
||||
return;<br>
|
||||
</ul>
|
||||
fwrite(code, len, 1, fp);<br>
|
||||
fclose(fp);<br>
|
||||
</ul>
|
||||
#if defined(SLJIT_CONFIG_X86_64)<br>
|
||||
<ul>
|
||||
system("objdump -b binary -m l1om -D /tmp/slj_dump");<br>
|
||||
</ul>
|
||||
#elif defined(SLJIT_CONFIG_X86_32)<br>
|
||||
<ul>
|
||||
system("objdump -b binary -m i386 -D /tmp/slj_dump");<br>
|
||||
</ul>
|
||||
#endif<br>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
The branch example disassembling:<br>
|
||||
<br>
|
||||
0000000000000000 <.data>:<br>
|
||||
<ul>
|
||||
<table>
|
||||
<tr><td>0:</td><td>53</td><td>push %rbx</td></tr>
|
||||
<tr><td>1:</td><td>41 57</td><td>push %r15</td></tr>
|
||||
<tr><td>3:</td><td>41 56</td><td>push %r14</td></tr>
|
||||
<tr><td>5:</td><td>48 8b df</td><td>mov %rdi,%rbx</td></tr>
|
||||
<tr><td>8:</td><td>4c 8b fe</td><td>mov %rsi,%r15</td></tr>
|
||||
<tr><td>b:</td><td>4c 8b f2</td><td>mov %rdx,%r14</td></tr>
|
||||
<tr><td>e:</td><td>48 83 ec 10</td><td>sub $0x10,%rsp</td></tr>
|
||||
<tr><td>12:</td><td>48 89 d8</td><td>mov %rbx,%rax</td></tr>
|
||||
<tr><td>15:</td><td>48 83 e0 01</td><td>and $0x1,%rax</td></tr>
|
||||
<tr><td>19:</td><td>48 83 f8 00</td><td>cmp $0x0,%rax</td></tr>
|
||||
<tr><td>1d:</td><td>74 05</td><td>je 0x24</td></tr>
|
||||
<tr><td>1f:</td><td>4c 89 f8</td><td>mov %r15,%rax</td></tr>
|
||||
<tr><td>22:</td><td>eb 03</td><td>jmp 0x27</td></tr>
|
||||
<tr><td>24:</td><td>4c 89 f0</td><td>mov %r14,%rax</td></tr>
|
||||
<tr><td>27:</td><td>48 83 c4 10</td><td>add $0x10,%rsp</td></tr>
|
||||
<tr><td>2b:</td><td>41 5e</td><td>pop %r14</td></tr>
|
||||
<tr><td>2d:</td><td>41 5f</td><td>pop %r15</td></tr>
|
||||
<tr><td>2f:</td><td>5b</td><td>pop %rbx</td></tr>
|
||||
<tr><td>30:</td><td>c3</td><td>retq</td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
<br>
|
||||
with GCC -O2<br>
|
||||
0000000000000000 <func>:<br>
|
||||
<ul>
|
||||
<table>
|
||||
<tr><td>0:</td><td>48 89 d0</td><td>mov %rdx,%rax</td></tr>
|
||||
<tr><td>3:</td><td>83 e7 01</td><td>and $0x1,%edi</td></tr>
|
||||
<tr><td>6:</td><td>48 0f 45 c6</td><td>cmovne %rsi,%rax</td></tr>
|
||||
<tr><td>a:</td><td>c3</td><td>retq</td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
<br>
|
||||
Err... Ok, the optimization here may be weak, or, optimization there is crazy... :-)<br>
|
||||
|
||||
<table width="100%" cellspacing=0 cellpadding=0>
|
||||
<tr><td align=right>Originally by wenxichang#163.com, 2015.5.10</td></tr>
|
||||
</table>
|
||||
|
||||
</td><td width=20 class="main"></td></tr>
|
||||
<tr height=20><td width=20 class="main"></td><td width=720 class="main"></td><td width=20 class="main"></td></tr>
|
||||
</table>
|
||||
</center>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,88 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct point_st {
|
||||
long x;
|
||||
int y;
|
||||
short z;
|
||||
char d;
|
||||
};
|
||||
|
||||
typedef long (SLJIT_FUNC *point_func_t)(struct point_st *point);
|
||||
|
||||
static long SLJIT_FUNC print_num(long a)
|
||||
{
|
||||
printf("a = %ld\n", a);
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
This example, we generate a function like this:
|
||||
|
||||
long func(struct point_st *point)
|
||||
{
|
||||
print_num(point->x);
|
||||
print_num(point->y);
|
||||
print_num(point->z);
|
||||
print_num(point->d);
|
||||
return point->x;
|
||||
}
|
||||
*/
|
||||
|
||||
static int struct_access()
|
||||
{
|
||||
void *code;
|
||||
unsigned long len;
|
||||
point_func_t func;
|
||||
|
||||
struct point_st point = {
|
||||
-5, -20, 5, 'a'
|
||||
};
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS1(W, W), 1, 1, 0, 0, 0);
|
||||
/* opt arg R S FR FS local_size */
|
||||
|
||||
/* S0->x --> R0; print_num(R0) */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, x));
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* S0->y --> R0; print_num(R0) */
|
||||
sljit_emit_op1(C, SLJIT_MOV_S32, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, y));
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* S0->z --> R0; print_num(R0) */
|
||||
sljit_emit_op1(C, SLJIT_MOV_S16, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, z));
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* S0->d --> R0; print_num(R0) */
|
||||
sljit_emit_op1(C, SLJIT_MOV_S8, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, d));
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS1(W, P), SLJIT_IMM, SLJIT_FUNC_ADDR(print_num));
|
||||
|
||||
/* return S0->x */
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(struct point_st, x));
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (point_func_t)code;
|
||||
printf("func return %ld\n", func(&point));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return struct_access();
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef long (SLJIT_FUNC *func3_t)(long a, long b, long c);
|
||||
|
||||
static long SLJIT_FUNC print_arr(long *a, long n)
|
||||
{
|
||||
long i;
|
||||
long sum = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
sum += a[i];
|
||||
printf("arr[%ld] = %ld\n", i, a[i]);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*
|
||||
This example, we generate a function like this:
|
||||
|
||||
long func(long a, long b, long c)
|
||||
{
|
||||
long arr[3] = { a, b, c };
|
||||
return print_arr(arr, 3);
|
||||
}
|
||||
*/
|
||||
|
||||
static int temp_var(long a, long b, long c)
|
||||
{
|
||||
void *code;
|
||||
unsigned long len;
|
||||
func3_t func;
|
||||
|
||||
/* Create a SLJIT compiler */
|
||||
struct sljit_compiler *C = sljit_create_compiler(NULL, NULL);
|
||||
|
||||
/* reserved space in stack for long arr[3] */
|
||||
sljit_emit_enter(C, 0, SLJIT_ARGS3(W, W, W, W), 2, 3, 0, 0, 3 * sizeof(long));
|
||||
/* opt arg R S FR FS local_size */
|
||||
|
||||
/* arr[0] = S0, SLJIT_SP is the init address of local var */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_S0, 0);
|
||||
/* arr[1] = S1 */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 1 * sizeof(long), SLJIT_S1, 0);
|
||||
/* arr[2] = S2 */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 2 * sizeof(long), SLJIT_S2, 0);
|
||||
|
||||
/* R0 = arr; in fact SLJIT_SP is the address of arr, but can't do so in SLJIT */
|
||||
sljit_get_local_base(C, SLJIT_R0, 0, 0); /* get the address of local variables */
|
||||
sljit_emit_op1(C, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 3); /* R1 = 3; */
|
||||
sljit_emit_icall(C, SLJIT_CALL, SLJIT_ARGS2(W, P, W), SLJIT_IMM, SLJIT_FUNC_ADDR(print_arr));
|
||||
sljit_emit_return(C, SLJIT_MOV, SLJIT_R0, 0);
|
||||
|
||||
/* Generate machine code */
|
||||
code = sljit_generate_code(C);
|
||||
len = sljit_get_generated_code_size(C);
|
||||
|
||||
/* Execute code */
|
||||
func = (func3_t)code;
|
||||
printf("func return %ld\n", func(a, b, c));
|
||||
|
||||
/* dump_code(code, len); */
|
||||
|
||||
/* Clean up */
|
||||
sljit_free_compiler(C);
|
||||
sljit_free_code(code, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return temp_var(7, 8, 9);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _REGEX_JIT_H_
|
||||
#define _REGEX_JIT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Character type config. */
|
||||
#define REGEX_USE_8BIT_CHARS
|
||||
|
||||
#ifdef REGEX_USE_8BIT_CHARS
|
||||
typedef char regex_char_t;
|
||||
#else
|
||||
typedef wchar_t regex_char_t;
|
||||
#endif
|
||||
|
||||
/* Error codes. */
|
||||
#define REGEX_NO_ERROR 0
|
||||
#define REGEX_MEMORY_ERROR 1
|
||||
#define REGEX_INVALID_REGEX 2
|
||||
|
||||
/* Note: large, nested {a,b} iterations can blow up the memory consumption
|
||||
a{n,m} is replaced by aa...aaa?a?a?a?a? (n >= 0, m > 0)
|
||||
\__n__/\____m___/
|
||||
a{n,} is replaced by aa...aaa+ (n > 0)
|
||||
\_n-1_/
|
||||
*/
|
||||
|
||||
/* The value returned by regex_compile. Can be used for multiple matching. */
|
||||
struct regex_machine;
|
||||
|
||||
/* A matching state. */
|
||||
struct regex_match;
|
||||
|
||||
/* Note: REGEX_MATCH_BEGIN and REGEX_MATCH_END does not change the parsing
|
||||
(Hence ^ and $ are parsed normally).
|
||||
Force matching to start from begining of the string (same as ^). */
|
||||
#define REGEX_MATCH_BEGIN 0x01
|
||||
/* Force matching to continue until the last character (same as $). */
|
||||
#define REGEX_MATCH_END 0x02
|
||||
/* Changes . to [^\r\n]
|
||||
Note: [...] and [^...] are NOT affected at all (as other regex engines do). */
|
||||
#define REGEX_NEWLINE 0x04
|
||||
/* Non greedy matching. In case of Thompson (non-recursive) algorithm,
|
||||
it (usually) does not have a significant speed gain. */
|
||||
#define REGEX_MATCH_NON_GREEDY 0x08
|
||||
/* Verbose. This define can be commented out, which disables all verbose features. */
|
||||
#define REGEX_MATCH_VERBOSE 0x10
|
||||
|
||||
/* If error occures the function returns NULL, and the error code returned in error variable.
|
||||
You can pass NULL to error if you don't care about the error code.
|
||||
The re_flags argument contains the default REGEX_MATCH flags. See above. */
|
||||
struct regex_machine* regex_compile(const regex_char_t *regex_string, int length, int re_flags, int *error);
|
||||
void regex_free_machine(struct regex_machine *machine);
|
||||
|
||||
/* Create and init match structure for a given machine. */
|
||||
struct regex_match* regex_begin_match(struct regex_machine *machine);
|
||||
void regex_reset_match(struct regex_match *match);
|
||||
void regex_free_match(struct regex_match *match);
|
||||
|
||||
/* Pattern matching.
|
||||
regex_continue_match does not support REGEX_MATCH_VERBOSE flag. */
|
||||
void regex_continue_match(struct regex_match *match, const regex_char_t *input_string, int length);
|
||||
int regex_get_result(struct regex_match *match, int *end, int *id);
|
||||
/* Returns true, if the best match has already found. */
|
||||
int regex_is_match_finished(struct regex_match *match);
|
||||
|
||||
/* Only exists if VERBOSE is defined in regexJIT.c
|
||||
Do both sanity check and verbose.
|
||||
(The latter only if REGEX_MATCH_VERBOSE was passed to regex_compile) */
|
||||
void regex_continue_match_debug(struct regex_match *match, const regex_char_t *input_string, int length);
|
||||
|
||||
/* Misc. */
|
||||
const char* regex_get_platform_name(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Must be the first one. Must not depend on any other include. */
|
||||
#include "sljitLir.h"
|
||||
#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
|
||||
#define S(str) L##str
|
||||
#endif
|
||||
|
||||
#ifdef REGEX_MATCH_VERBOSE
|
||||
void verbose_test(regex_char_t *pattern, regex_char_t *string)
|
||||
{
|
||||
int error;
|
||||
regex_char_t *ptr;
|
||||
struct regex_machine* machine;
|
||||
struct regex_match* match;
|
||||
int begin, end, id;
|
||||
|
||||
ptr = pattern;
|
||||
while (*ptr)
|
||||
ptr++;
|
||||
|
||||
printf("Start test '%s' matches to '%s'\n", pattern, string);
|
||||
machine = regex_compile(pattern, (int)(ptr - pattern), REGEX_MATCH_VERBOSE | REGEX_NEWLINE, &error);
|
||||
|
||||
if (error) {
|
||||
printf("WARNING: Error %d\n", error);
|
||||
return;
|
||||
}
|
||||
if (!machine) {
|
||||
printf("ERROR: machine must be exists. Report this bug, please\n");
|
||||
return;
|
||||
}
|
||||
|
||||
match = regex_begin_match(machine);
|
||||
if (!match) {
|
||||
printf("WARNING: Not enough memory for matching\n");
|
||||
regex_free_machine(machine);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = string;
|
||||
while (*ptr)
|
||||
ptr++;
|
||||
|
||||
regex_continue_match_debug(match, string, (int)(ptr - string));
|
||||
|
||||
begin = regex_get_result(match, &end, &id);
|
||||
printf("Math returns: %3d->%3d [%3d]\n", begin, end, id);
|
||||
|
||||
regex_free_match(match);
|
||||
regex_free_machine(machine);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct test_case {
|
||||
int begin; /* Expected begin. */
|
||||
int end; /* Expected end. */
|
||||
int id; /* Expected id. */
|
||||
int finished; /* -1 : don't care, 0 : false, 1 : true. */
|
||||
int flags; /* REGEX_MATCH_* */
|
||||
const regex_char_t *pattern; /* NULL : use the previous pattern. */
|
||||
const regex_char_t *string; /* NULL : end of tests. */
|
||||
};
|
||||
|
||||
static void run_tests(struct test_case* test, int verbose, int silent)
|
||||
{
|
||||
int error;
|
||||
const regex_char_t *ptr;
|
||||
struct regex_machine* machine = NULL;
|
||||
struct regex_match* match;
|
||||
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++) {
|
||||
if (verbose)
|
||||
printf("test: '%s' '%s': ", test->pattern ? test->pattern : "[[REUSE]]", test->string);
|
||||
fail++;
|
||||
|
||||
if (test->pattern) {
|
||||
if (machine)
|
||||
regex_free_machine(machine);
|
||||
|
||||
ptr = test->pattern;
|
||||
while (*ptr)
|
||||
ptr++;
|
||||
|
||||
machine = regex_compile(test->pattern, (int)(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;
|
||||
}
|
||||
|
||||
ptr = test->string;
|
||||
while (*ptr)
|
||||
ptr++;
|
||||
|
||||
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;
|
||||
}
|
||||
regex_continue_match_debug(match, test->string, (int)(ptr - test->string));
|
||||
begin = regex_get_result(match, &end, &id);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
regex_reset_match(match);
|
||||
regex_continue_match(match, test->string, (int)(ptr - test->string));
|
||||
begin = regex_get_result(match, &end, &id);
|
||||
finished = regex_is_match_finished(match);
|
||||
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;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("SUCCESS\n");
|
||||
fail--;
|
||||
success++;
|
||||
}
|
||||
if (machine)
|
||||
regex_free_machine(machine);
|
||||
|
||||
printf("REGEX tests: ");
|
||||
if (fail == 0)
|
||||
printf("all tests " COLOR_GREEN "PASSED" COLOR_DEFAULT " ");
|
||||
else
|
||||
printf(COLOR_RED "%d" COLOR_DEFAULT " (" COLOR_RED "%d%%" COLOR_DEFAULT ") tests failed ", fail, fail * 100 / (success + fail));
|
||||
printf("on " COLOR_ARCH "%s" COLOR_DEFAULT "\n", regex_get_platform_name());
|
||||
}
|
||||
|
||||
/* Testing. */
|
||||
|
||||
static struct test_case tests[] = {
|
||||
{ 3, 7, 0, -1, 0,
|
||||
S("text"), S("is textile") },
|
||||
{ 0, 10, 0, -1, 0,
|
||||
S("^(ab|c)*?d+(es)?"), S("abccabddeses") },
|
||||
{ -1, 0, 0, 1, 0,
|
||||
S("^a+"), S("saaaa") },
|
||||
{ 3, 6, 0, 0, 0,
|
||||
S("(a+|b+)$"), S("saabbb") },
|
||||
{ 1, 6, 0, 0, 0,
|
||||
S("(a+|b+){,2}$"), S("saabbb") },
|
||||
{ 1, 6, 0, 1, 0,
|
||||
S("(abcde|bc)(a+*|(b|c){2}+){0}"), S("babcdeaaaaaaaa") },
|
||||
{ 1, 6, 0, 1, 0,
|
||||
S("(abc(aa)?|(cab+){2})"), S("cabcaa") },
|
||||
{ -1, 0, 0, 1, 0,
|
||||
S("^(abc(aa)?|(cab+){2})$"), S("cabcaa") },
|
||||
{ 0, 3, 1, -1, 0,
|
||||
S("^(ab{001!})?c"), S("abcde") },
|
||||
{ 1, 15, 2, -1, 0,
|
||||
S("(c?(a|bb{2!}){2,3}()+d){2,3}"), S("ccabbadbbadcaadcaad") },
|
||||
{ 2, 9, 0, -1, 0,
|
||||
NULL, S("cacaadaadaa") },
|
||||
{ -1, 0, 0, -1, REGEX_MATCH_BEGIN,
|
||||
S("(((ab?c|d{1})))"), S("ad") },
|
||||
{ 0, 9, 3, -1, REGEX_MATCH_BEGIN,
|
||||
S("^((a{1!}|b{2!}|c{3!}){3,6}d)+"), S("cabadbacddaa") },
|
||||
{ 1, 6, 0, 0, REGEX_MATCH_END,
|
||||
S("(a+(bb|cc?)?){4,}"), S("maaaac") },
|
||||
{ 3, 12, 1, 0, REGEX_MATCH_END,
|
||||
S("(x+x+{02,03}(x+|{1!})){03,06}$"), S("aaaxxxxxxxxx") },
|
||||
{ 1, 2, 3, -1, 0,
|
||||
S("((c{1!})?|x+{2!}|{3!})(a|c)"), S("scs") },
|
||||
{ 1, 4, 2, 1, 0,
|
||||
NULL, S("sxxaxxxaccacca") },
|
||||
{ 0, 2, 1, 1, 0,
|
||||
NULL, S("ccdcdcdddddcdccccd") },
|
||||
{ 0, 3, 0, -1, REGEX_MATCH_NON_GREEDY,
|
||||
S("^a+a+a+"), S("aaaaaa") },
|
||||
{ 2, 5, 0, -1, REGEX_MATCH_NON_GREEDY,
|
||||
S("a+a+a+"), S("bbaaaaaa") },
|
||||
{ 1, 4, 0, 1, 0,
|
||||
S("baa|a+"), S("sbaaaaaa") },
|
||||
{ 0, 6, 0, 1, 0,
|
||||
S("baaa|baa|sbaaaa"), S("sbaaaaa") },
|
||||
{ 1, 4, 0, 1, REGEX_MATCH_NON_GREEDY,
|
||||
S("baaa|baa"), S("xbaaa") },
|
||||
{ 0, 0, 3, 1, 0,
|
||||
S("{3!}"), S("xx") },
|
||||
{ 0, 0, 1, 1, 0,
|
||||
S("{1!}(a{2!})*"), S("xx") },
|
||||
{ 0, 2, 2, 0, 0,
|
||||
NULL, S("aa") },
|
||||
{ 0, 0, 1, 1, REGEX_MATCH_NON_GREEDY,
|
||||
S("{1!}(a{2!})*"), S("aaxx") },
|
||||
{ 4, 12, 0, 1, 0,
|
||||
S("(.[]-]){3}[^]-]{2}"), S("ax-xs-[][]lmn") },
|
||||
{ 3, 7, 1, 1, 0,
|
||||
S("([ABC]|[abc]{1!}){3,5}"), S("AbSAabbx") },
|
||||
{ 0, 8, 3, 0, 0,
|
||||
S("^[x\\-y[\\]]+([[\\]]{3!})*$"), S("x-y[-][]") },
|
||||
{ 0, 9, 0, 0, 0,
|
||||
NULL, S("x-y[-][]x") },
|
||||
{ 2, 8, 0, 1, 0,
|
||||
S("<(/{1!})?[^>]+>"), S(" <html></html> ") },
|
||||
{ 2, 9, 1, 1, 0,
|
||||
NULL, S(" </html><html> ") },
|
||||
{ 2, 9, 0, 1, 0,
|
||||
S("[A-Z0-9a-z]+"), S("[(Iden9aA)]") },
|
||||
{ 1, 4, 0, 1, 0,
|
||||
S("[^x-y]+[a-c_]{2,3}"), S("x_a_y") },
|
||||
{ 4, 11, 0, 0, 0,
|
||||
NULL, S("ssaymmaa_ccl") },
|
||||
{ 3, 6, 0, 1, REGEX_NEWLINE,
|
||||
S(".a[^k]"), S("\na\nxa\ns") },
|
||||
{ 0, 2, 0, 1, REGEX_NEWLINE,
|
||||
S("^a+"), S("aa\n") },
|
||||
{ 1, 4, 0, 1, 0 /* =REGEX_NEWLINE */,
|
||||
NULL, S("\naaa\n") },
|
||||
{ 2, 3, 0, 1, 0 /* =REGEX_NEWLINE */,
|
||||
NULL, S("\n\na\n") },
|
||||
{ 0, 2, 0, 1, REGEX_NEWLINE,
|
||||
S("a+$"), S("aa\n") },
|
||||
{ 0, 3, 0, 0, 0 /* =REGEX_NEWLINE */,
|
||||
NULL, S("aaa") },
|
||||
{ 2, 4, 1, 1, REGEX_NEWLINE,
|
||||
S("^a(a{1!})*$"), S("\n\naa\n\n") },
|
||||
{ 0, 1, 0, 0, 0 /* REGEX_NEWLINE */,
|
||||
NULL, S("a") },
|
||||
{ -1, 0, 0, -1, 0 /* REGEX_NEWLINE */,
|
||||
NULL, S("ab\nba") },
|
||||
{ -1, 0, 0, 0, 0,
|
||||
NULL, NULL }
|
||||
};
|
||||
|
||||
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!}){,"); */
|
||||
/* verbose_test("(s(ab){2,4}t){2,}*S(a*(b)(c()|)d+){3,4}{0,0}*M"); */
|
||||
/* verbose_test("^a({2!})*b+(a|{1!}b)+d$"); */
|
||||
/* verbose_test("((a|b|c)*(xy)+)+", "asbcxyxy"); */
|
||||
|
||||
run_tests(tests, has_arg && argv[1][1] == 'v', has_arg && argv[1][1] == 's');
|
||||
|
||||
#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
sljit_free_unused_memory_exec();
|
||||
#endif /* !SLJIT_CONFIG_UNSUPPORTED */
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SLJIT_CONFIG_POST_H_
|
||||
#define SLJIT_CONFIG_POST_H_
|
||||
|
||||
void *sljit_test_malloc_exec(sljit_uw size, void *exec_allocator_data);
|
||||
void sljit_test_free_code(void* code, void *exec_allocator_data);
|
||||
|
||||
#endif /* SLJIT_CONFIG_POST_H_ */
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SLJIT_CONFIG_PRE_H_
|
||||
#define SLJIT_CONFIG_PRE_H_
|
||||
|
||||
#define SLJIT_HAVE_CONFIG_POST 1
|
||||
|
||||
#define SLJIT_MALLOC_EXEC(size, exec_allocator_data) sljit_test_malloc_exec((size), (exec_allocator_data))
|
||||
#define SLJIT_FREE_EXEC(ptr, exec_allocator_data) sljit_test_free_code((ptr), (exec_allocator_data))
|
||||
|
||||
#endif /* SLJIT_CONFIG_PRE_H_ */
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright 2009-2010 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.
|
||||
*/
|
||||
|
||||
#include "sljitLir.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int sljit_test(int argc, char* argv[]);
|
||||
|
||||
union executable_code {
|
||||
void* code;
|
||||
sljit_sw (SLJIT_FUNC *func)(sljit_sw* a);
|
||||
};
|
||||
typedef union executable_code executable_code;
|
||||
|
||||
static void error(const char* str)
|
||||
{
|
||||
printf("An error occured: %s\n", str);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void devel(void)
|
||||
{
|
||||
executable_code code;
|
||||
|
||||
struct sljit_compiler *compiler = sljit_create_compiler(NULL, NULL);
|
||||
sljit_sw buf[4];
|
||||
|
||||
if (!compiler)
|
||||
error("Not enough of memory");
|
||||
buf[0] = 5;
|
||||
buf[1] = 12;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
sljit_compiler_verbose(compiler, stdout);
|
||||
#endif
|
||||
sljit_emit_enter(compiler, 0, SLJIT_ARGS1(W, P), 4, 5, 4, 0, 2 * sizeof(sljit_sw));
|
||||
|
||||
sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0);
|
||||
|
||||
code.code = sljit_generate_code(compiler);
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
printf("Code at: %p\n", (void*)SLJIT_FUNC_ADDR(code.code));
|
||||
|
||||
printf("Function returned with %ld\n", (long)code.func((sljit_sw*)buf));
|
||||
printf("buf[0] = %ld\n", (long)buf[0]);
|
||||
printf("buf[1] = %ld\n", (long)buf[1]);
|
||||
printf("buf[2] = %ld\n", (long)buf[2]);
|
||||
printf("buf[3] = %ld\n", (long)buf[3]);
|
||||
sljit_free_code(code.code, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
/* devel(); */
|
||||
return sljit_test(argc, argv);
|
||||
}
|
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
|
@ -1,361 +0,0 @@
|
|||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
static void test_serialize1(void)
|
||||
{
|
||||
/* Test serializing large code. */
|
||||
executable_code code;
|
||||
struct sljit_compiler* compiler = sljit_create_compiler(NULL, NULL);
|
||||
struct sljit_label *label;
|
||||
struct sljit_jump *jump1;
|
||||
struct sljit_jump *jump2;
|
||||
struct sljit_jump *mov_addr;
|
||||
sljit_sw executable_offset;
|
||||
sljit_uw const_addr;
|
||||
sljit_uw jump_addr;
|
||||
sljit_uw label_addr;
|
||||
sljit_sw buf[3];
|
||||
sljit_uw* serialized_buffer;
|
||||
sljit_uw serialized_size;
|
||||
sljit_s32 i;
|
||||
|
||||
if (verbose)
|
||||
printf("Run test_serialize1\n");
|
||||
|
||||
FAILED(!compiler, "cannot create compiler\n");
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
|
||||
sljit_emit_enter(compiler, 0, SLJIT_ARGS1V(P), 3, 2, 0, 0, 0);
|
||||
|
||||
jump1 = sljit_emit_jump(compiler, SLJIT_JUMP);
|
||||
label = sljit_emit_label(compiler);
|
||||
jump2 = sljit_emit_jump(compiler, SLJIT_JUMP);
|
||||
sljit_set_label(jump2, label);
|
||||
label = sljit_emit_label(compiler);
|
||||
sljit_set_label(jump1, label);
|
||||
|
||||
mov_addr = sljit_emit_mov_addr(compiler, SLJIT_R2, 0);
|
||||
/* buf[0] */
|
||||
sljit_emit_const(compiler, SLJIT_MEM1(SLJIT_S0), 0, -1234);
|
||||
|
||||
sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_R2, 0);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 0, SLJIT_IMM, -1234);
|
||||
|
||||
label = sljit_emit_label(compiler);
|
||||
sljit_set_label(mov_addr, label);
|
||||
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, 7);
|
||||
for (i = 0; i < 4096; i++)
|
||||
sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 3);
|
||||
|
||||
/* buf[1] */
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw), SLJIT_R1, 0);
|
||||
|
||||
/* buf[2] */
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 2 * sizeof(sljit_sw), SLJIT_IMM, -56789);
|
||||
jump1 = sljit_emit_jump(compiler, SLJIT_JUMP | SLJIT_REWRITABLE_JUMP);
|
||||
label = sljit_emit_label(compiler);
|
||||
sljit_set_label(jump1, label);
|
||||
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw), SLJIT_IMM, 0);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 2 * sizeof(sljit_sw), SLJIT_IMM, 0);
|
||||
label = sljit_emit_label(compiler);
|
||||
|
||||
serialized_buffer = sljit_serialize_compiler(compiler, 0, &serialized_size);
|
||||
FAILED(!serialized_buffer, "cannot serialize compiler\n");
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
/* Continue code generation. */
|
||||
compiler = sljit_deserialize_compiler(serialized_buffer, serialized_size, 0, NULL, NULL);
|
||||
SLJIT_FREE(serialized_buffer, NULL);
|
||||
FAILED(!compiler, "cannot deserialize compiler\n");
|
||||
|
||||
jump1 = sljit_emit_jump(compiler, SLJIT_JUMP);
|
||||
label = sljit_emit_label(compiler);
|
||||
jump2 = sljit_emit_jump(compiler, SLJIT_JUMP);
|
||||
sljit_set_label(jump2, label);
|
||||
label = sljit_emit_label(compiler);
|
||||
sljit_set_label(jump1, label);
|
||||
|
||||
sljit_emit_return_void(compiler);
|
||||
|
||||
code.code = sljit_generate_code(compiler);
|
||||
CHECK(compiler);
|
||||
executable_offset = sljit_get_executable_offset(compiler);
|
||||
const_addr = sljit_get_const_addr(sljit_get_first_const(compiler));
|
||||
jump1 = sljit_get_next_jump(sljit_get_next_jump(sljit_get_next_jump(sljit_get_first_jump(compiler))));
|
||||
SLJIT_ASSERT(!sljit_jump_is_mov_addr(jump1));
|
||||
jump_addr = sljit_get_jump_addr(jump1);
|
||||
label = sljit_get_next_label(sljit_get_next_label(sljit_get_next_label(sljit_get_next_label(sljit_get_first_label(compiler)))));
|
||||
label_addr = sljit_get_label_addr(label);
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
sljit_set_const(const_addr, 87654, executable_offset);
|
||||
sljit_set_jump_addr(jump_addr, label_addr, executable_offset);
|
||||
|
||||
code.func1((sljit_sw)&buf);
|
||||
FAILED(buf[0] != 87654, "test_serialize1 case 1 failed\n");
|
||||
FAILED(buf[1] != 7 + 4096 * 3, "test_serialize1 case 2 failed\n");
|
||||
FAILED(buf[2] != -56789, "test_serialize1 case 3 failed\n");
|
||||
|
||||
sljit_free_code(code.code, NULL);
|
||||
successful_tests++;
|
||||
}
|
||||
|
||||
static void test_serialize2(void)
|
||||
{
|
||||
/* Test serializing jumps/labels. */
|
||||
executable_code code;
|
||||
struct sljit_compiler* compiler = sljit_create_compiler(NULL, NULL);
|
||||
struct sljit_label *label;
|
||||
struct sljit_jump *jump;
|
||||
sljit_uw* serialized_buffer;
|
||||
sljit_uw serialized_size;
|
||||
sljit_sw buf[3];
|
||||
|
||||
if (verbose)
|
||||
printf("Run test_serialize2\n");
|
||||
|
||||
FAILED(!compiler, "cannot create compiler\n");
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
|
||||
sljit_emit_enter(compiler, 0, SLJIT_ARGS2V(P, W), 3, 3, 0, 0, 32);
|
||||
sljit_emit_cmp(compiler, SLJIT_EQUAL, SLJIT_S1, 0, SLJIT_IMM, 37);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 0);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), 0);
|
||||
|
||||
sljit_emit_label(compiler);
|
||||
/* buf[0] */
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 0, SLJIT_IMM, -5678);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), 16, SLJIT_IMM, -8765);
|
||||
|
||||
sljit_emit_mov_addr(compiler, SLJIT_S2, 0);
|
||||
sljit_emit_cmp(compiler, SLJIT_NOT_EQUAL, SLJIT_S2, 0, SLJIT_IMM, 0);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 0);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), 0);
|
||||
|
||||
serialized_buffer = sljit_serialize_compiler(compiler, 0, &serialized_size);
|
||||
FAILED(!serialized_buffer, "cannot serialize compiler\n");
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
/* Continue code generation. */
|
||||
compiler = sljit_deserialize_compiler(serialized_buffer, serialized_size, 0, NULL, NULL);
|
||||
SLJIT_FREE(serialized_buffer, NULL);
|
||||
FAILED(!compiler, "cannot deserialize compiler\n");
|
||||
|
||||
label = sljit_emit_label(compiler);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 1);
|
||||
jump = sljit_get_first_jump(compiler);
|
||||
SLJIT_ASSERT(!sljit_jump_is_mov_addr(jump));
|
||||
SLJIT_ASSERT(!sljit_jump_has_label(jump) && !sljit_jump_has_target(jump));
|
||||
sljit_set_label(jump, label);
|
||||
|
||||
/* buf[1] */
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw), SLJIT_IMM, 3456);
|
||||
|
||||
label = sljit_get_first_label(compiler);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 0);
|
||||
jump = sljit_emit_jump(compiler, SLJIT_JUMP);
|
||||
sljit_set_label(jump, label);
|
||||
|
||||
sljit_emit_label(compiler);
|
||||
|
||||
serialized_buffer = sljit_serialize_compiler(compiler, 0, &serialized_size);
|
||||
FAILED(!serialized_buffer, "cannot serialize compiler\n");
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
/* Continue code generation. */
|
||||
compiler = sljit_deserialize_compiler(serialized_buffer, serialized_size, 0, NULL, NULL);
|
||||
SLJIT_FREE(serialized_buffer, NULL);
|
||||
FAILED(!compiler, "cannot deserialize compiler\n");
|
||||
|
||||
sljit_emit_return_void(compiler);
|
||||
|
||||
jump = sljit_get_first_jump(compiler);
|
||||
SLJIT_ASSERT(sljit_jump_has_label(jump) && !sljit_jump_has_target(jump));
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(sljit_jump_is_mov_addr(jump));
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(!sljit_jump_is_mov_addr(jump));
|
||||
SLJIT_ASSERT(!sljit_jump_has_label(jump) && !sljit_jump_has_target(jump));
|
||||
|
||||
label = sljit_emit_label(compiler);
|
||||
sljit_set_label(jump, label);
|
||||
|
||||
/* buf[2] */
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 2 * sizeof(sljit_sw), SLJIT_MEM1(SLJIT_SP), 16);
|
||||
sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_S2, 0);
|
||||
|
||||
label = sljit_get_first_label(compiler);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 0);
|
||||
label = sljit_get_next_label(label);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 1);
|
||||
label = sljit_get_next_label(label);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 2);
|
||||
jump = sljit_get_next_jump(sljit_get_first_jump(compiler));
|
||||
SLJIT_ASSERT(sljit_jump_is_mov_addr(jump));
|
||||
sljit_set_label(jump, label);
|
||||
label = sljit_get_next_label(label);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 3);
|
||||
SLJIT_ASSERT(sljit_get_next_label(label) == NULL);
|
||||
|
||||
code.code = sljit_generate_code(compiler);
|
||||
CHECK(compiler);
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
code.func2((sljit_sw)&buf, 37);
|
||||
FAILED(buf[0] != -5678, "test_serialize2 case 1 failed\n");
|
||||
FAILED(buf[1] != 3456, "test_serialize2 case 2 failed\n");
|
||||
FAILED(buf[2] != -8765, "test_serialize2 case 3 failed\n");
|
||||
|
||||
sljit_free_code(code.code, NULL);
|
||||
successful_tests++;
|
||||
}
|
||||
|
||||
static void test_serialize3_f1(sljit_sw a, sljit_sw b, sljit_sw c)
|
||||
{
|
||||
sljit_sw* ptr = (sljit_sw*)c;
|
||||
ptr[0] = a;
|
||||
ptr[1] = b;
|
||||
}
|
||||
|
||||
static void test_serialize3(void)
|
||||
{
|
||||
/* Test serializing consts/calls. */
|
||||
executable_code code;
|
||||
struct sljit_compiler* compiler = sljit_create_compiler(NULL, NULL);
|
||||
struct sljit_label *label;
|
||||
struct sljit_jump *jump;
|
||||
struct sljit_const *const_;
|
||||
sljit_sw executable_offset;
|
||||
sljit_uw* serialized_buffer;
|
||||
sljit_uw serialized_size;
|
||||
sljit_sw buf[6];
|
||||
sljit_sw label_addr;
|
||||
sljit_s32 i;
|
||||
|
||||
if (verbose)
|
||||
printf("Run test_serialize3\n");
|
||||
|
||||
FAILED(!compiler, "cannot create compiler\n");
|
||||
for (i = 0; i < 6 ; i++)
|
||||
buf[i] = 0;
|
||||
|
||||
sljit_emit_enter(compiler, 0, SLJIT_ARGS1V(P), 3, 3, 0, 0, 32);
|
||||
|
||||
sljit_emit_mov_addr(compiler, SLJIT_R0, 0);
|
||||
sljit_emit_const(compiler, SLJIT_R1, 0, 0);
|
||||
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_S0, 0);
|
||||
jump = sljit_emit_call(compiler, SLJIT_CALL, SLJIT_ARGS3V(W, W, W));
|
||||
/* buf[0], buf[1] */
|
||||
sljit_set_target(jump, SLJIT_FUNC_UADDR(test_serialize3_f1));
|
||||
|
||||
serialized_buffer = sljit_serialize_compiler(compiler, 0, &serialized_size);
|
||||
FAILED(!serialized_buffer, "cannot serialize compiler\n");
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
/* Continue code generation. */
|
||||
compiler = sljit_deserialize_compiler(serialized_buffer, serialized_size, 0, NULL, NULL);
|
||||
SLJIT_FREE(serialized_buffer, NULL);
|
||||
FAILED(!compiler, "cannot deserialize compiler\n");
|
||||
|
||||
sljit_emit_mov_addr(compiler, SLJIT_R0, 0);
|
||||
sljit_emit_const(compiler, SLJIT_R1, 0, 0);
|
||||
sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R2, 0, SLJIT_S0, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
|
||||
jump = sljit_emit_call(compiler, SLJIT_CALL, SLJIT_ARGS3V(W, W, W));
|
||||
/* buf[2], buf[3] */
|
||||
sljit_set_target(jump, SLJIT_FUNC_UADDR(test_serialize3_f1));
|
||||
|
||||
serialized_buffer = sljit_serialize_compiler(compiler, 0, &serialized_size);
|
||||
FAILED(!serialized_buffer, "cannot serialize compiler\n");
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
/* Continue code generation. */
|
||||
compiler = sljit_deserialize_compiler(serialized_buffer, serialized_size, 0, NULL, NULL);
|
||||
SLJIT_FREE(serialized_buffer, NULL);
|
||||
FAILED(!compiler, "cannot deserialize compiler\n");
|
||||
|
||||
sljit_emit_mov_addr(compiler, SLJIT_R0, 0);
|
||||
sljit_emit_const(compiler, SLJIT_R1, 0, 0);
|
||||
sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R2, 0, SLJIT_S0, 0, SLJIT_IMM, 4 * sizeof(sljit_sw));
|
||||
jump = sljit_emit_call(compiler, SLJIT_CALL, SLJIT_ARGS3V(W, W, W));
|
||||
/* buf[4], buf[5] */
|
||||
sljit_set_target(jump, SLJIT_FUNC_UADDR(test_serialize3_f1));
|
||||
|
||||
sljit_emit_return_void(compiler);
|
||||
SLJIT_ASSERT(sljit_get_first_label(compiler) == NULL);
|
||||
label = sljit_emit_label(compiler);
|
||||
SLJIT_ASSERT(sljit_get_label_index(label) == 0);
|
||||
|
||||
jump = sljit_get_first_jump(compiler);
|
||||
SLJIT_ASSERT(sljit_jump_is_mov_addr(jump));
|
||||
sljit_set_label(jump, label);
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(!sljit_jump_is_mov_addr(jump));
|
||||
SLJIT_ASSERT(sljit_jump_has_target(jump) && sljit_jump_get_target(jump) == SLJIT_FUNC_UADDR(test_serialize3_f1));
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(sljit_jump_is_mov_addr(jump));
|
||||
sljit_set_label(jump, label);
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(!sljit_jump_is_mov_addr(jump));
|
||||
SLJIT_ASSERT(sljit_jump_has_target(jump) && sljit_jump_get_target(jump) == SLJIT_FUNC_UADDR(test_serialize3_f1));
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(sljit_jump_is_mov_addr(jump));
|
||||
sljit_set_label(jump, label);
|
||||
jump = sljit_get_next_jump(jump);
|
||||
SLJIT_ASSERT(sljit_jump_has_target(jump) && sljit_jump_get_target(jump) == SLJIT_FUNC_UADDR(test_serialize3_f1));
|
||||
SLJIT_ASSERT(sljit_get_next_jump(jump) == NULL);
|
||||
|
||||
code.code = sljit_generate_code(compiler);
|
||||
CHECK(compiler);
|
||||
executable_offset = sljit_get_executable_offset(compiler);
|
||||
|
||||
const_ = sljit_get_first_const(compiler);
|
||||
sljit_set_const(sljit_get_const_addr(const_), 0x5678, executable_offset);
|
||||
const_ = sljit_get_next_const(const_);
|
||||
sljit_set_const(sljit_get_const_addr(const_), -0x9876, executable_offset);
|
||||
const_ = sljit_get_next_const(const_);
|
||||
sljit_set_const(sljit_get_const_addr(const_), 0x2345, executable_offset);
|
||||
SLJIT_ASSERT(sljit_get_next_const(const_) == NULL);
|
||||
|
||||
label_addr = (sljit_sw)sljit_get_label_addr(label);
|
||||
sljit_free_compiler(compiler);
|
||||
|
||||
code.func1((sljit_sw)&buf);
|
||||
FAILED(buf[0] != label_addr, "test_serialize3 case 1 failed\n");
|
||||
FAILED(buf[1] != 0x5678, "test_serialize3 case 2 failed\n");
|
||||
FAILED(buf[2] != label_addr, "test_serialize3 case 3 failed\n");
|
||||
FAILED(buf[3] != -0x9876, "test_serialize3 case 4 failed\n");
|
||||
FAILED(buf[4] != label_addr, "test_serialize3 case 5 failed\n");
|
||||
FAILED(buf[5] != 0x2345, "test_serialize3 case 6 failed\n");
|
||||
|
||||
sljit_free_code(code.code, NULL);
|
||||
successful_tests++;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue