-
Notifications
You must be signed in to change notification settings - Fork 80
/
Copy pathsljitLir.h
2710 lines (2258 loc) · 118 KB
/
sljitLir.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Stack-less Just-In-Time compiler
*
* Copyright Zoltan Herczeg ([email protected]). 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_LIR_H_
#define SLJIT_LIR_H_
/*
------------------------------------------------------------------------
Stack-Less JIT compiler for multiple architectures (x86, ARM, PowerPC)
------------------------------------------------------------------------
Short description
Advantages:
- The execution can be continued from any LIR instruction. In other
words, it is possible to jump to any label from anywhere, even from
a code fragment, which is compiled later, as long as the compiling
context is the same. See sljit_emit_enter for more details.
- Supports self modifying code: target of any jump and call
instructions and some constant values can be dynamically modified
during runtime. See SLJIT_REWRITABLE_JUMP.
- although it is not suggested to do it frequently
- can be used for inline caching: save an important value once
in the instruction stream
- A fixed stack space can be allocated for local variables
- The compiler is thread-safe
- The compiler is highly configurable through preprocessor macros.
You can disable unneeded features (multithreading in single
threaded applications), and you can use your own system functions
(including memory allocators). See sljitConfig.h.
Disadvantages:
- The compiler is more like a platform independent assembler, so
there is no built-in variable management. Registers and stack must
be managed manually (the name of the compiler refers to this).
In practice:
- This approach is very effective for interpreters
- One of the saved registers typically points to a stack interface
- It can jump to any exception handler anytime (even if it belongs
to another function)
- Hot paths can be modified during runtime reflecting the changes
of the fastest execution path of the dynamic language
- SLJIT supports complex memory addressing modes
- mainly position and context independent code (except some cases)
For valgrind users:
- pass --smc-check=all argument to valgrind, since JIT is a "self-modifying code"
*/
#if (defined SLJIT_HAVE_CONFIG_PRE && SLJIT_HAVE_CONFIG_PRE)
#include "sljitConfigPre.h"
#endif /* SLJIT_HAVE_CONFIG_PRE */
#include "sljitConfigCPU.h"
#include "sljitConfig.h"
/* The following header file defines useful macros for fine tuning
SLJIT based code generators. They are listed in the beginning
of sljitConfigInternal.h */
#include "sljitConfigInternal.h"
#if (defined SLJIT_HAVE_CONFIG_POST && SLJIT_HAVE_CONFIG_POST)
#include "sljitConfigPost.h"
#endif /* SLJIT_HAVE_CONFIG_POST */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Version numbers. */
#define SLJIT_MAJOR_VERSION 0
#define SLJIT_MINOR_VERSION 95
/* --------------------------------------------------------------------- */
/* Error codes */
/* --------------------------------------------------------------------- */
/* Indicates no error. */
#define SLJIT_SUCCESS 0
/* After the call of sljit_generate_code(), the error code of the compiler
is set to this value to avoid further code generation.
The complier should be freed after sljit_generate_code(). */
#define SLJIT_ERR_COMPILED 1
/* Cannot allocate non-executable memory. */
#define SLJIT_ERR_ALLOC_FAILED 2
/* Cannot allocate executable memory.
Only sljit_generate_code() returns with this error code. */
#define SLJIT_ERR_EX_ALLOC_FAILED 3
/* Unsupported instruction form. */
#define SLJIT_ERR_UNSUPPORTED 4
/* An invalid argument is passed to any SLJIT function. */
#define SLJIT_ERR_BAD_ARGUMENT 5
/* --------------------------------------------------------------------- */
/* Registers */
/* --------------------------------------------------------------------- */
/*
Scratch (R) registers: registers which may not preserve their values
across function calls.
Saved (S) registers: registers which preserve their values across
function calls.
The scratch and saved register sets overlap. The last scratch register
is the first saved register, the one before the last is the second saved
register, and so on.
For example, in an architecture with only five registers (A-E), if two
are scratch and three saved registers, they will be defined as follows:
A | R0 | | R0 always represent scratch register A
B | R1 | | R1 always represent scratch register B
C | [R2] | S2 | R2 and S2 represent the same physical register C
D | [R3] | S1 | R3 and S1 represent the same physical register D
E | [R4] | S0 | R4 and S0 represent the same physical register E
Note: SLJIT_NUMBER_OF_SCRATCH_REGISTERS will be 2 and
SLJIT_NUMBER_OF_SAVED_REGISTERS will be 3.
Note: For all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 12
and SLJIT_NUMBER_OF_SAVED_REGISTERS >= 6. However, 6 registers
are virtual on x86-32. See below.
The purpose of this definition is convenience: saved registers can
be used as extra scratch registers. For example, building in the
previous example, four registers can be specified as scratch registers
and the fifth one as saved register, allowing any user code which requires
four scratch registers to run unmodified. The SLJIT compiler automatically
saves the content of the two extra scratch register on the stack. Scratch
registers can also be preserved by saving their value on the stack but
that needs to be done manually.
Note: To emphasize that registers assigned to R2-R4 are saved
registers, they are enclosed by square brackets.
Note: sljit_emit_enter and sljit_set_context define whether a register
is S or R register. E.g: if in the previous example 3 scratches and
1 saved are mapped by sljit_emit_enter, the allowed register set
will be: R0-R2 and S0. Although S2 is mapped to the same register
than R2, it is not available in that configuration. Furthermore
the S1 register cannot be used at all.
*/
/* Scratch registers. */
#define SLJIT_R0 1
#define SLJIT_R1 2
#define SLJIT_R2 3
/* Note: on x86-32, R3 - R6 (same as S3 - S6) are emulated (they
are allocated on the stack). These registers are called virtual
and cannot be used for memory addressing (cannot be part of
any SLJIT_MEM1, SLJIT_MEM2 construct). There is no such
limitation on other CPUs. See sljit_get_register_index(). */
#define SLJIT_R3 4
#define SLJIT_R4 5
#define SLJIT_R5 6
#define SLJIT_R6 7
#define SLJIT_R7 8
#define SLJIT_R8 9
#define SLJIT_R9 10
/* All R registers provided by the architecture can be accessed by SLJIT_R(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_REGISTERS. */
#define SLJIT_R(i) (1 + (i))
/* Saved registers. */
#define SLJIT_S0 (SLJIT_NUMBER_OF_REGISTERS)
#define SLJIT_S1 (SLJIT_NUMBER_OF_REGISTERS - 1)
#define SLJIT_S2 (SLJIT_NUMBER_OF_REGISTERS - 2)
/* Note: on x86-32, S3 - S6 (same as R3 - R6) are emulated (they
are allocated on the stack). These registers are called virtual
and cannot be used for memory addressing (cannot be part of
any SLJIT_MEM1, SLJIT_MEM2 construct). There is no such
limitation on other CPUs. See sljit_get_register_index(). */
#define SLJIT_S3 (SLJIT_NUMBER_OF_REGISTERS - 3)
#define SLJIT_S4 (SLJIT_NUMBER_OF_REGISTERS - 4)
#define SLJIT_S5 (SLJIT_NUMBER_OF_REGISTERS - 5)
#define SLJIT_S6 (SLJIT_NUMBER_OF_REGISTERS - 6)
#define SLJIT_S7 (SLJIT_NUMBER_OF_REGISTERS - 7)
#define SLJIT_S8 (SLJIT_NUMBER_OF_REGISTERS - 8)
#define SLJIT_S9 (SLJIT_NUMBER_OF_REGISTERS - 9)
/* All S registers provided by the architecture can be accessed by SLJIT_S(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_REGISTERS. */
#define SLJIT_S(i) (SLJIT_NUMBER_OF_REGISTERS - (i))
/* Registers >= SLJIT_FIRST_SAVED_REG are saved registers. */
#define SLJIT_FIRST_SAVED_REG (SLJIT_S0 - SLJIT_NUMBER_OF_SAVED_REGISTERS + 1)
/* The SLJIT_SP provides direct access to the linear stack space allocated by
sljit_emit_enter. It can only be used in the following form: SLJIT_MEM1(SLJIT_SP).
The immediate offset is extended by the relative stack offset automatically.
sljit_get_local_base can be used to obtain the real address of a value. */
#define SLJIT_SP (SLJIT_NUMBER_OF_REGISTERS + 1)
/* Return with machine word. */
#define SLJIT_RETURN_REG SLJIT_R0
/* --------------------------------------------------------------------- */
/* Floating point registers */
/* --------------------------------------------------------------------- */
/* Each floating point register can store a 32 or a 64 bit precision
value. The FR and FS register sets overlap in the same way as R
and S register sets. See above. */
/* Floating point scratch registers. */
#define SLJIT_FR0 1
#define SLJIT_FR1 2
#define SLJIT_FR2 3
#define SLJIT_FR3 4
#define SLJIT_FR4 5
#define SLJIT_FR5 6
#define SLJIT_FR6 7
#define SLJIT_FR7 8
#define SLJIT_FR8 9
#define SLJIT_FR9 10
/* All FR registers provided by the architecture can be accessed by SLJIT_FR(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_FLOAT_REGISTERS. */
#define SLJIT_FR(i) (1 + (i))
/* Floating point saved registers. */
#define SLJIT_FS0 (SLJIT_NUMBER_OF_FLOAT_REGISTERS)
#define SLJIT_FS1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 1)
#define SLJIT_FS2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 2)
#define SLJIT_FS3 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 3)
#define SLJIT_FS4 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 4)
#define SLJIT_FS5 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 5)
#define SLJIT_FS6 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 6)
#define SLJIT_FS7 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 7)
#define SLJIT_FS8 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 8)
#define SLJIT_FS9 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 9)
/* All FS registers provided by the architecture can be accessed by SLJIT_FS(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS. */
#define SLJIT_FS(i) (SLJIT_NUMBER_OF_FLOAT_REGISTERS - (i))
/* Float registers >= SLJIT_FIRST_SAVED_FLOAT_REG are saved registers. */
#define SLJIT_FIRST_SAVED_FLOAT_REG (SLJIT_FS0 - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS + 1)
/* Return with floating point arg. */
#define SLJIT_RETURN_FREG SLJIT_FR0
/* --------------------------------------------------------------------- */
/* Vector registers */
/* --------------------------------------------------------------------- */
/* Vector registers are storage areas, which are used for Single Instruction
Multiple Data (SIMD) computations. The VR and VS register sets overlap
in the same way as R and S register sets. See above.
The storage space of vector registers often overlap with floating point
registers. In this case setting the value of SLJIT_VR(i) destroys the
value of SLJIT_FR(i) and vice versa. See SLJIT_SEPARATE_VECTOR_REGISTERS
macro. */
/* Vector scratch registers. */
#define SLJIT_VR0 1
#define SLJIT_VR1 2
#define SLJIT_VR2 3
#define SLJIT_VR3 4
#define SLJIT_VR4 5
#define SLJIT_VR5 6
#define SLJIT_VR6 7
#define SLJIT_VR7 8
#define SLJIT_VR8 9
#define SLJIT_VR9 10
/* All VR registers provided by the architecture can be accessed by SLJIT_VR(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_VECTOR_REGISTERS. */
#define SLJIT_VR(i) (1 + (i))
/* Vector saved registers. */
#define SLJIT_VS0 (SLJIT_NUMBER_OF_VECTOR_REGISTERS)
#define SLJIT_VS1 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 1)
#define SLJIT_VS2 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 2)
#define SLJIT_VS3 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 3)
#define SLJIT_VS4 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 4)
#define SLJIT_VS5 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 5)
#define SLJIT_VS6 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 6)
#define SLJIT_VS7 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 7)
#define SLJIT_VS8 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 8)
#define SLJIT_VS9 (SLJIT_NUMBER_OF_VECTOR_REGISTERS - 9)
/* All VS registers provided by the architecture can be accessed by SLJIT_VS(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_VECTOR_REGISTERS. */
#define SLJIT_VS(i) (SLJIT_NUMBER_OF_VECTOR_REGISTERS - (i))
/* Vector registers >= SLJIT_FIRST_SAVED_VECTOR_REG are saved registers. */
#define SLJIT_FIRST_SAVED_VECTOR_REG (SLJIT_VS0 - SLJIT_NUMBER_OF_SAVED_VECTOR_REGISTERS + 1)
/* --------------------------------------------------------------------- */
/* Argument type definitions */
/* --------------------------------------------------------------------- */
/* The following argument type definitions are used by sljit_emit_enter,
sljit_set_context, sljit_emit_call, and sljit_emit_icall functions.
For sljit_emit_call and sljit_emit_icall, the first integer argument
must be placed into SLJIT_R0, the second one into SLJIT_R1, and so on.
Similarly the first floating point argument must be placed into SLJIT_FR0,
the second one into SLJIT_FR1, and so on.
For sljit_emit_enter, the integer arguments can be stored in scratch
or saved registers. Scratch registers are identified by a _R suffix.
If only saved registers are used, then the allocation mirrors what is
done for the "call" functions but using saved registers, meaning that
the first integer argument goes to SLJIT_S0, the second one goes into
SLJIT_S1, and so on.
If scratch registers are used, then the way the integer registers are
allocated changes so that SLJIT_S0, SLJIT_S1, etc; will be assigned
only for the arguments not using scratch registers, while SLJIT_R<n>
will be used for the ones using scratch registers.
Furthermore, the index (shown as "n" above) that will be used for the
scratch register depends on how many previous integer registers
(scratch or saved) were used already, starting with SLJIT_R0.
Eventhough some indexes will be likely skipped, they still need to be
accounted for in the scratches parameter of sljit_emit_enter. See below
for some examples.
The floating point arguments always use scratch registers (but not the
_R suffix like the integer arguments) and must use SLJIT_FR0, SLJIT_FR1,
just like in the "call" functions.
Note: the mapping for scratch registers is part of the compiler context
and therefore a new context after sljit_emit_call/sljit_emit_icall
could remove access to some scratch registers that were used as
arguments.
Example function definition:
sljit_f32 SLJIT_FUNC example_c_callback(void *arg_a,
sljit_f64 arg_b, sljit_u32 arg_c, sljit_f32 arg_d);
Argument type definition:
SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_F32)
| SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_P, 1) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F64, 2)
| SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_32, 3) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F32, 4)
Short form of argument type definition:
SLJIT_ARGS4(F32, P, F64, 32, F32)
Argument passing:
arg_a must be placed in SLJIT_R0
arg_b must be placed in SLJIT_FR0
arg_c must be placed in SLJIT_R1
arg_d must be placed in SLJIT_FR1
Examples for argument processing by sljit_emit_enter:
SLJIT_ARGS4V(P, 32_R, F32, W)
Arguments are placed into: SLJIT_S0, SLJIT_R1, SLJIT_FR0, SLJIT_S1
The type of the result is void.
SLJIT_ARGS4(F32, W, W_R, W, W_R)
Arguments are placed into: SLJIT_S0, SLJIT_R1, SLJIT_S1, SLJIT_R3
The type of the result is sljit_f32.
SLJIT_ARGS4(P, W, F32, P_R)
Arguments are placed into: SLJIT_FR0, SLJIT_S0, SLJIT_FR1, SLJIT_R1
The type of the result is pointer.
Note: it is recommended to pass the scratch arguments first
followed by the saved arguments:
SLJIT_ARGS4(W, W_R, W_R, W, W)
Arguments are placed into: SLJIT_R0, SLJIT_R1, SLJIT_S0, SLJIT_S1
The type of the result is sljit_sw / sljit_uw.
*/
/* The following flag is only allowed for the integer arguments of
sljit_emit_enter. When the flag is set, the integer argument is
stored in a scratch register instead of a saved register. */
#define SLJIT_ARG_TYPE_SCRATCH_REG 0x8
/* No return value, only supported by SLJIT_ARG_RETURN. */
#define SLJIT_ARG_TYPE_RET_VOID 0
/* Machine word sized integer argument or result. */
#define SLJIT_ARG_TYPE_W 1
#define SLJIT_ARG_TYPE_W_R (SLJIT_ARG_TYPE_W | SLJIT_ARG_TYPE_SCRATCH_REG)
/* 32 bit integer argument or result. */
#define SLJIT_ARG_TYPE_32 2
#define SLJIT_ARG_TYPE_32_R (SLJIT_ARG_TYPE_32 | SLJIT_ARG_TYPE_SCRATCH_REG)
/* Pointer sized integer argument or result. */
#define SLJIT_ARG_TYPE_P 3
#define SLJIT_ARG_TYPE_P_R (SLJIT_ARG_TYPE_P | SLJIT_ARG_TYPE_SCRATCH_REG)
/* 64 bit floating point argument or result. */
#define SLJIT_ARG_TYPE_F64 4
/* 32 bit floating point argument or result. */
#define SLJIT_ARG_TYPE_F32 5
#define SLJIT_ARG_SHIFT 4
#define SLJIT_ARG_RETURN(type) (type)
#define SLJIT_ARG_VALUE(type, idx) ((type) << ((idx) * SLJIT_ARG_SHIFT))
/* Simplified argument list definitions.
The following definition:
SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_W) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F32, 1)
can be shortened to:
SLJIT_ARGS1(W, F32)
Another example where no value is returned:
SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_RET_VOID) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_W_R, 1)
can be shortened to:
SLJIT_ARGS1V(W_R)
*/
#define SLJIT_ARG_TO_TYPE(type) SLJIT_ARG_TYPE_ ## type
#define SLJIT_ARGS0(ret) \
SLJIT_ARG_RETURN(SLJIT_ARG_TO_TYPE(ret))
#define SLJIT_ARGS0V() \
SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_RET_VOID)
#define SLJIT_ARGS1(ret, arg1) \
(SLJIT_ARGS0(ret) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg1), 1))
#define SLJIT_ARGS1V(arg1) \
(SLJIT_ARGS0V() | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg1), 1))
#define SLJIT_ARGS2(ret, arg1, arg2) \
(SLJIT_ARGS1(ret, arg1) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg2), 2))
#define SLJIT_ARGS2V(arg1, arg2) \
(SLJIT_ARGS1V(arg1) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg2), 2))
#define SLJIT_ARGS3(ret, arg1, arg2, arg3) \
(SLJIT_ARGS2(ret, arg1, arg2) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg3), 3))
#define SLJIT_ARGS3V(arg1, arg2, arg3) \
(SLJIT_ARGS2V(arg1, arg2) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg3), 3))
#define SLJIT_ARGS4(ret, arg1, arg2, arg3, arg4) \
(SLJIT_ARGS3(ret, arg1, arg2, arg3) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg4), 4))
#define SLJIT_ARGS4V(arg1, arg2, arg3, arg4) \
(SLJIT_ARGS3V(arg1, arg2, arg3) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg4), 4))
/* --------------------------------------------------------------------- */
/* Main structures and functions */
/* --------------------------------------------------------------------- */
/*
The following structures are private, and can be changed in the
future. Keeping them here allows code inlining.
*/
struct sljit_memory_fragment {
struct sljit_memory_fragment *next;
sljit_uw used_size;
/* Must be aligned to sljit_sw. */
sljit_u8 memory[1];
};
struct sljit_label {
struct sljit_label *next;
union {
sljit_uw index;
sljit_uw addr;
} u;
/* The maximum size difference. */
sljit_uw size;
};
struct sljit_jump {
struct sljit_jump *next;
sljit_uw addr;
/* Architecture dependent flags. */
sljit_uw flags;
union {
sljit_uw target;
struct sljit_label *label;
} u;
};
struct sljit_const {
struct sljit_const *next;
sljit_uw addr;
};
struct sljit_generate_code_buffer {
void *buffer;
sljit_uw size;
sljit_sw executable_offset;
};
struct sljit_read_only_buffer {
struct sljit_read_only_buffer *next;
sljit_uw size;
/* Label can be replaced by address after sljit_generate_code. */
union {
struct sljit_label *label;
sljit_uw addr;
} u;
};
struct sljit_compiler {
sljit_s32 error;
sljit_s32 options;
struct sljit_label *labels;
struct sljit_jump *jumps;
struct sljit_const *consts;
struct sljit_label *last_label;
struct sljit_jump *last_jump;
struct sljit_const *last_const;
void *allocator_data;
void *user_data;
struct sljit_memory_fragment *buf;
struct sljit_memory_fragment *abuf;
/* Number of labels created by the compiler. */
sljit_uw label_count;
/* Available scratch registers. */
sljit_s32 scratches;
/* Available saved registers. */
sljit_s32 saveds;
/* Available float scratch registers. */
sljit_s32 fscratches;
/* Available float saved registers. */
sljit_s32 fsaveds;
#if (defined SLJIT_SEPARATE_VECTOR_REGISTERS && SLJIT_SEPARATE_VECTOR_REGISTERS) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG) \
|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
/* Available vector scratch registers. */
sljit_s32 vscratches;
/* Available vector saved registers. */
sljit_s32 vsaveds;
#endif /* SLJIT_SEPARATE_VECTOR_REGISTERS || SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG || SLJIT_VERBOSE */
/* Local stack size. */
sljit_s32 local_size;
/* Maximum code size. */
sljit_uw size;
/* Relative offset of the executable mapping from the writable mapping. */
sljit_sw executable_offset;
/* Executable size for statistical purposes. */
sljit_uw executable_size;
#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
sljit_s32 status_flags_state;
#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
sljit_s32 args_size;
#endif /* SLJIT_CONFIG_X86_32 */
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
/* Temporary fields. */
sljit_s32 mode32;
#endif /* SLJIT_CONFIG_X86_64 */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
/* Constant pool handling. */
sljit_uw *cpool;
sljit_u8 *cpool_unique;
sljit_uw cpool_diff;
sljit_uw cpool_fill;
/* Other members. */
/* Contains pointer, "ldr pc, [...]" pairs. */
sljit_uw patches;
#endif /* SLJIT_CONFIG_ARM_V6 */
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
/* Temporary fields. */
sljit_uw shift_imm;
#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V6 */
#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)
sljit_uw args_size;
#endif /* SLJIT_CONFIG_ARM_32 && __SOFTFP__ */
#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
/* Temporary fields. */
sljit_u32 imm;
#endif /* SLJIT_CONFIG_PPC */
#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
sljit_s32 delay_slot;
/* Temporary fields. */
sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif /* SLJIT_CONFIG_MIPS */
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
sljit_uw args_size;
#endif /* SLJIT_CONFIG_MIPS_32 */
#if (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
/* Temporary fields. */
sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif /* SLJIT_CONFIG_RISCV */
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
/* Need to allocate register save area to make calls. */
/* Temporary fields. */
sljit_s32 mode;
#endif /* SLJIT_CONFIG_S390X */
#if (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
/* Temporary fields. */
sljit_s32 cache_arg;
sljit_sw cache_argw;
#endif /* SLJIT_CONFIG_LOONGARCH */
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
FILE* verbose;
#endif /* SLJIT_VERBOSE */
/* Note: SLJIT_DEBUG enables SLJIT_ARGUMENT_CHECKS. */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG)
/* Flags specified by the last arithmetic instruction.
It contains the type of the variable flag. */
sljit_s32 last_flags;
/* Return value type set by entry functions. */
sljit_s32 last_return;
/* Local size passed to entry functions. */
sljit_s32 logical_local_size;
#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG) \
|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
#if !(defined SLJIT_SEPARATE_VECTOR_REGISTERS && SLJIT_SEPARATE_VECTOR_REGISTERS)
/* Available float scratch registers. */
sljit_s32 real_fscratches;
/* Available float saved registers. */
sljit_s32 real_fsaveds;
#endif /* !SLJIT_SEPARATE_VECTOR_REGISTERS */
/* Trust arguments when an API function is called.
Used internally for calling API functions. */
sljit_s32 skip_checks;
#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG || SLJIT_VERBOSE */
};
/* --------------------------------------------------------------------- */
/* Main functions */
/* --------------------------------------------------------------------- */
/* Creates an SLJIT compiler. The allocator_data is required by some
custom memory managers. This pointer is passed to SLJIT_MALLOC
and SLJIT_FREE macros. Most allocators (including the default
one) ignores this value, and it is recommended to pass NULL
as a dummy value for allocator_data.
Returns NULL if failed. */
SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data);
/* Frees everything except the compiled machine code. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler);
/* Returns the current error code. If an error occurres, future calls
which uses the same compiler argument returns early with the same
error code. Thus there is no need for checking the error after every
call, it is enough to do it after the code is compiled. Removing
these checks increases the performance of the compiling process. */
static SLJIT_INLINE sljit_s32 sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; }
/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED except
if an error was detected before. After the error code is set
the compiler behaves as if the allocation failure happened
during an SLJIT function call. This can greatly simplify error
checking, since it is enough to check the compiler status
after the code is compiled. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler);
/* Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit,
and <= 128 bytes on 64 bit architectures. The memory area is owned by the
compiler, and freed by sljit_free_compiler. The returned pointer is
sizeof(sljit_sw) aligned. Excellent for allocating small blocks during
compiling, and no need to worry about freeing them. The size is enough
to contain at most 16 pointers. If the size is outside of the range,
the function will return with NULL. However, this return value does not
indicate that there is no more memory (does not set the current error code
of the compiler to out-of-memory status). */
SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size);
/* Returns the allocator data passed to sljit_create_compiler. */
static SLJIT_INLINE void* sljit_compiler_get_allocator_data(struct sljit_compiler *compiler) { return compiler->allocator_data; }
/* Sets/get the user data for a compiler. */
static SLJIT_INLINE void sljit_compiler_set_user_data(struct sljit_compiler *compiler, void *user_data) { compiler->user_data = user_data; }
static SLJIT_INLINE void* sljit_compiler_get_user_data(struct sljit_compiler *compiler) { return compiler->user_data; }
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
/* Passing NULL disables verbose. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose);
#endif /* SLJIT_VERBOSE */
/* Option bits for sljit_generate_code. */
/* The exec_allocator_data points to a pre-allocated
buffer which type is sljit_generate_code_buffer. */
#define SLJIT_GENERATE_CODE_BUFFER 0x1
/* Create executable code from the instruction stream. This is the final step
of the code generation, and no more instructions can be emitted after this call.
options is the combination of SLJIT_GENERATE_CODE_* bits
exec_allocator_data is passed to SLJIT_MALLOC_EXEC and
SLJIT_MALLOC_FREE functions */
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data);
/* Free executable code. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data);
/* When the protected executable allocator is used the JIT code is mapped
twice. The first mapping has read/write and the second mapping has read/exec
permissions. This function returns with the relative offset of the executable
mapping using the writable mapping as the base after the machine code is
successfully generated. The returned value is always 0 for the normal executable
allocator, since it uses only one mapping with read/write/exec permissions.
Dynamic code modifications requires this value.
Before a successful code generation, this function returns with 0. */
static SLJIT_INLINE sljit_sw sljit_get_executable_offset(struct sljit_compiler *compiler) { return compiler->executable_offset; }
/* The executable memory consumption of the generated code can be retrieved by
this function. The returned value can be used for statistical purposes.
Before a successful code generation, this function returns with 0. */
static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler *compiler) { return compiler->executable_size; }
/* Returns with non-zero if the feature or limitation type passed as its
argument is present on the current CPU. The return value is one, if a
feature is fully supported, and it is two, if partially supported.
Some features (e.g. floating point operations) require hardware (CPU)
support while others (e.g. move with update) are emulated if not available.
However, even when a feature is emulated, specialized code paths may be
faster than the emulation. Some limitations are emulated as well so their
general case is supported but it has extra performance costs.
Note: sljitConfigInternal.h also provides several feature detection macros. */
/* [Not emulated] Floating-point support is available. */
#define SLJIT_HAS_FPU 0
/* [Limitation] Some registers are virtual registers. */
#define SLJIT_HAS_VIRTUAL_REGISTERS 1
/* [Emulated] Has zero register (setting a memory location to zero is efficient). */
#define SLJIT_HAS_ZERO_REGISTER 2
/* [Emulated] Count leading zero is supported. */
#define SLJIT_HAS_CLZ 3
/* [Emulated] Count trailing zero is supported. */
#define SLJIT_HAS_CTZ 4
/* [Emulated] Reverse the order of bytes is supported. */
#define SLJIT_HAS_REV 5
/* [Emulated] Rotate left/right is supported. */
#define SLJIT_HAS_ROT 6
/* [Emulated] Conditional move is supported. */
#define SLJIT_HAS_CMOV 7
/* [Emulated] Prefetch instruction is available (emulated as a nop). */
#define SLJIT_HAS_PREFETCH 8
/* [Emulated] Copy from/to f32 operation is available (see sljit_emit_fcopy). */
#define SLJIT_HAS_COPY_F32 9
/* [Emulated] Copy from/to f64 operation is available (see sljit_emit_fcopy). */
#define SLJIT_HAS_COPY_F64 10
/* [Not emulated] The 64 bit floating point registers can be used as
two separate 32 bit floating point registers (e.g. ARM32). The
second 32 bit part can be accessed by SLJIT_F64_SECOND. */
#define SLJIT_HAS_F64_AS_F32_PAIR 11
/* [Not emulated] Some SIMD operations are supported by the compiler. */
#define SLJIT_HAS_SIMD 12
/* [Not emulated] SIMD registers are mapped to a pair of double precision
floating point registers. E.g. passing either SLJIT_FR0 or SLJIT_FR1 to
a simd operation represents the same 128 bit register, and both SLJIT_FR0
and SLJIT_FR1 are overwritten. */
#define SLJIT_SIMD_REGS_ARE_PAIRS 13
/* [Not emulated] Atomic support is available. */
#define SLJIT_HAS_ATOMIC 14
/* [Not emulated] Memory barrier support is available. */
#define SLJIT_HAS_MEMORY_BARRIER 15
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
/* [Not emulated] AVX support is available on x86. */
#define SLJIT_HAS_AVX 100
/* [Not emulated] AVX2 support is available on x86. */
#define SLJIT_HAS_AVX2 101
#endif /* SLJIT_CONFIG_X86 */
#if (defined SLJIT_CONFIG_LOONGARCH)
/* [Not emulated] LASX support is available on LoongArch */
#define SLJIT_HAS_LASX 201
#endif /* SLJIT_CONFIG_LOONGARCH */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type);
/* If type is between SLJIT_ORDERED_EQUAL and SLJIT_ORDERED_LESS_EQUAL,
sljit_cmp_info returns with:
zero - if the cpu supports the floating point comparison type
one - if the comparison requires two machine instructions
two - if the comparison requires more than two machine instructions
When the result is non-zero, it is recommended to avoid
using the specified comparison type if it is easy to do so.
Otherwise it returns zero. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type);
/* The following functions generate machine code. If there is no
error, they return with SLJIT_SUCCESS, otherwise they return
with an error code. */
/*
The executable code is a callable function from the viewpoint
of the C language. Function calls must conform with the ABI
(Application Binary Interface) of the target platform, which
specify the purpose of machine registers and stack handling
among other things. The sljit_emit_enter function emits the
necessary instructions for setting up an entry point for the
executable code. This is often called as function prologue.
The "options" argument can be used to pass configuration options
to the sljit compiler which affects the generated code, until
another sljit_emit_enter or sljit_set_context is called. The
available options are listed before sljit_emit_enter.
The function argument list is specified by the SLJIT_ARGSx
(SLJIT_ARGS0 .. SLJIT_ARGS4) macros. Currently maximum four
arguments are supported. See the description of SLJIT_ARGSx
macros about argument passing.
The register set used by the function must be declared as well.
The number of scratch and saved registers available to the
function must be passed to sljit_emit_enter. Only R registers
between R0 and "scratches" argument can be used later. E.g.
if "scratches" is set to two, the scratch register set will
be limited to SLJIT_R0 and SLJIT_R1. The S registers are
declared in a similar manner, but their count is specified
by "saveds" argument. The floating point scratch and saved
registers can be set by using "scratches" and "saveds" argument
as well, but their value must be passed to the SLJIT_ENTER_FLOAT
macro, see below.
The sljit_emit_enter is also capable of allocating a stack
space for local data. The "local_size" argument contains the
size in bytes of this local area, and it can be accessed using
SLJIT_MEM1(SLJIT_SP). The memory area between SLJIT_SP (inclusive)
and SLJIT_SP + local_size (exclusive) can be modified freely
until the function returns. The alocated stack space is an
uninitialized memory area.
Floating point scratch and saved registers must be specified
by the SLJIT_ENTER_FLOAT macro, which result value should be
combined with scratches / saveds argument.
Examples:
To use three scratch and four floating point scratch
registers, the "scratches" argument must be set to:
3 | SLJIT_ENTER_FLOAT(4)
To use six saved and five floating point saved
registers, the "saveds" argument must be set to:
6 | SLJIT_ENTER_FLOAT(5)
Note: the following conditions must met:
0 <= scratches <= SLJIT_NUMBER_OF_REGISTERS
0 <= saveds <= SLJIT_NUMBER_OF_SAVED_REGISTERS
scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS
0 <= float scratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS
0 <= float saveds <= SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS
float scratches + float saveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS
Note: the compiler can use saved registers as scratch registers,
but the opposite is not supported
Note: every call of sljit_emit_enter and sljit_set_context
overwrites the previous context.
*/
/* The following options are available for sljit_emit_enter. */
/* Saved registers between SLJIT_S0 and SLJIT_S(n - 1) (inclusive)
are not saved / restored on function enter / return. Instead,
these registers can be used to pass / return data (such as
global / local context pointers) across function calls. The
value of n must be between 1 and 3. This option is only
supported by SLJIT_ENTER_REG_ARG calling convention. */
#define SLJIT_ENTER_KEEP(n) (n)
/* The compiled function uses an SLJIT specific register argument
calling convention. This is a lightweight function call type where
both the caller and the called functions must be compiled by
SLJIT. The type argument of the call must be SLJIT_CALL_REG_ARG
and all arguments must be stored in scratch registers. */
#define SLJIT_ENTER_REG_ARG 0x00000004
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
/* Use VEX prefix for all SIMD operations on x86. */
#define SLJIT_ENTER_USE_VEX 0x00010000
#endif /* !SLJIT_CONFIG_X86 */
/* Macros for other sljit_emit_enter arguments. */
/* Floating point scratch and saved registers can be
specified by SLJIT_ENTER_FLOAT. */
#define SLJIT_ENTER_FLOAT(regs) ((regs) << 8)
/* Vector scratch and saved registers can be specified
by SLJIT_ENTER_VECTOR. */
#define SLJIT_ENTER_VECTOR(regs) ((regs) << 16)
/* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */
#define SLJIT_MAX_LOCAL_SIZE 1048576
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types,
sljit_s32 scratches, sljit_s32 saveds, sljit_s32 local_size);
/* The SLJIT compiler has a current context (which contains the local
stack space size, number of used registers, etc.) which is initialized
by sljit_emit_enter. Several functions (such as sljit_emit_return)
requires this context to be able to generate the appropriate code.
However, some code fragments (compiled separately) may have no
normal entry point so their context is unknown to the compiler.
sljit_set_context and sljit_emit_enter have the same arguments,
but sljit_set_context does not generate any machine code.
Note: every call of sljit_emit_enter and sljit_set_context overwrites
the previous context. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types,
sljit_s32 scratches, sljit_s32 saveds, sljit_s32 local_size);
/* Return to the caller function. The sljit_emit_return_void function
does not return with any value. The sljit_emit_return function returns
with a single value loaded from its source operand. The load operation
can be between SLJIT_MOV and SLJIT_MOV_P (see sljit_emit_op1) and
SLJIT_MOV_F32/SLJIT_MOV_F64 (see sljit_emit_fop1) depending on the
return value specified by sljit_emit_enter/sljit_set_context. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler);
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src, sljit_sw srcw);
/* Restores the saved registers and free the stack area, then the execution
continues from the address specified by the source operand. This
operation is similar to sljit_emit_return, but it ignores the return
address. The code where the exection continues should use the same context
as the caller function (see sljit_set_context). A word (pointer) value
can be passed in the SLJIT_RETURN_REG register. This function can be used
to jump to exception handlers. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
sljit_s32 src, sljit_sw srcw);
/*
Source and destination operands for arithmetical instructions
imm - a simple immediate value (cannot be used as a destination)
reg - any of the available registers (immediate argument must be 0)
[imm] - absolute memory address
[reg+imm] - indirect memory address
[reg+(reg<<imm)] - indirect indexed memory address (shift must be between 0 and 3)
useful for accessing arrays (fully supported by both x86 and
ARM architectures, and cheap operation on others)
*/
/*
IMPORTANT NOTE: memory accesses MUST be naturally aligned unless
SLJIT_UNALIGNED macro is defined and its value is 1.
length | alignment
---------+-----------
byte | 1 byte (any physical_address is accepted)
half | 2 byte (physical_address & 0x1 == 0)
int | 4 byte (physical_address & 0x3 == 0)
word | 4 byte if SLJIT_32BIT_ARCHITECTURE is defined and its value is 1
| 8 byte if SLJIT_64BIT_ARCHITECTURE is defined and its value is 1
pointer | size of sljit_up type (4 byte on 32 bit machines, 4 or 8 byte
| on 64 bit machines)
Note: Different architectures have different addressing limitations.