2 * Stack-less Just-In-Time compiler
4 * Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
6 * Redistribution and use in source and binary forms, with or without modification, are
7 * permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice, this list of
10 * conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 * of conditions and the following disclaimer in the documentation and/or other materials
14 * provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST
char* sljit_get_platform_name(void)
29 #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
30 return "ARMv7" SLJIT_CPUINFO
;
31 #elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
32 return "ARMv5" SLJIT_CPUINFO
;
34 #error "Internal error: Unknown ARM architecture"
38 /* Last register + 1. */
39 #define TMP_REG1 (SLJIT_NO_REGISTERS + 1)
40 #define TMP_REG2 (SLJIT_NO_REGISTERS + 2)
41 #define TMP_REG3 (SLJIT_NO_REGISTERS + 3)
42 #define TMP_PC (SLJIT_NO_REGISTERS + 4)
44 #define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1)
45 #define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2)
47 /* In ARM instruction words.
48 Cache lines are usually 32 byte aligned. */
49 #define CONST_POOL_ALIGNMENT 8
50 #define CONST_POOL_EMPTY 0xffffffff
52 #define ALIGN_INSTRUCTION(ptr) \
53 (sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1))
54 #define MAX_DIFFERENCE(max_diff) \
55 (((max_diff) / (int)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1))
57 /* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
58 static SLJIT_CONST sljit_ub reg_map
[SLJIT_NO_REGISTERS
+ 5] = {
59 0, 0, 1, 2, 10, 11, 4, 5, 6, 7, 8, 13, 3, 12, 14, 15
62 #define RM(rm) (reg_map[rm])
63 #define RD(rd) (reg_map[rd] << 12)
64 #define RN(rn) (reg_map[rn] << 16)
66 /* --------------------------------------------------------------------- */
67 /* Instrucion forms */
68 /* --------------------------------------------------------------------- */
70 /* The instruction includes the AL condition.
71 INST_NAME - CONDITIONAL remove this flag. */
72 #define COND_MASK 0xf0000000
73 #define CONDITIONAL 0xe0000000
74 #define PUSH_POOL 0xff000000
76 /* DP - Data Processing instruction (use with EMIT_DATA_PROCESS_INS). */
83 #define BLX 0xe12fff30
85 #define CLZ 0xe16f0f10
87 #define BKPT 0xe1200070
90 #define MUL 0xe0000090
92 #define NOP 0xe1a00000
94 #define PUSH 0xe92d0000
95 #define POP 0xe8bd0000
99 #define SMULL 0xe0c00090
101 #define UMULL 0xe0800090
102 #define VABS_F64 0xeeb00bc0
103 #define VADD_F64 0xee300b00
104 #define VCMP_F64 0xeeb40b40
105 #define VDIV_F64 0xee800b00
106 #define VMOV_F64 0xeeb00b40
107 #define VMRS 0xeef1fa10
108 #define VMUL_F64 0xee200b00
109 #define VNEG_F64 0xeeb10b40
110 #define VSTR 0xed000b00
111 #define VSUB_F64 0xee300b40
113 #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
114 /* Arm v7 specific instructions. */
115 #define MOVW 0xe3000000
116 #define MOVT 0xe3400000
117 #define SXTB 0xe6af0070
118 #define SXTH 0xe6bf0070
119 #define UXTB 0xe6ef0070
120 #define UXTH 0xe6ff0070
123 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
125 static int push_cpool(struct sljit_compiler
*compiler
)
127 /* Pushing the constant pool into the instruction stream. */
133 /* The label could point the address after the constant pool. */
134 if (compiler
->last_label
&& compiler
->last_label
->size
== compiler
->size
)
135 compiler
->last_label
->size
+= compiler
->cpool_fill
+ (CONST_POOL_ALIGNMENT
- 1) + 1;
137 SLJIT_ASSERT(compiler
->cpool_fill
> 0 && compiler
->cpool_fill
<= CPOOL_SIZE
);
138 inst
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
141 *inst
= 0xff000000 | compiler
->cpool_fill
;
143 for (i
= 0; i
< CONST_POOL_ALIGNMENT
- 1; i
++) {
144 inst
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
150 cpool_ptr
= compiler
->cpool
;
151 cpool_end
= cpool_ptr
+ compiler
->cpool_fill
;
152 while (cpool_ptr
< cpool_end
) {
153 inst
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
156 *inst
= *cpool_ptr
++;
158 compiler
->cpool_diff
= CONST_POOL_EMPTY
;
159 compiler
->cpool_fill
= 0;
160 return SLJIT_SUCCESS
;
163 static int push_inst(struct sljit_compiler
*compiler
, sljit_uw inst
)
167 if (SLJIT_UNLIKELY(compiler
->cpool_diff
!= CONST_POOL_EMPTY
&& compiler
->size
- compiler
->cpool_diff
>= MAX_DIFFERENCE(4092)))
168 FAIL_IF(push_cpool(compiler
));
170 ptr
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
174 return SLJIT_SUCCESS
;
177 static int push_inst_with_literal(struct sljit_compiler
*compiler
, sljit_uw inst
, sljit_uw literal
)
180 sljit_uw cpool_index
= CPOOL_SIZE
;
183 sljit_ub
* cpool_unique_ptr
;
185 if (SLJIT_UNLIKELY(compiler
->cpool_diff
!= CONST_POOL_EMPTY
&& compiler
->size
- compiler
->cpool_diff
>= MAX_DIFFERENCE(4092)))
186 FAIL_IF(push_cpool(compiler
));
187 else if (compiler
->cpool_fill
> 0) {
188 cpool_ptr
= compiler
->cpool
;
189 cpool_end
= cpool_ptr
+ compiler
->cpool_fill
;
190 cpool_unique_ptr
= compiler
->cpool_unique
;
192 if ((*cpool_ptr
== literal
) && !(*cpool_unique_ptr
)) {
193 cpool_index
= cpool_ptr
- compiler
->cpool
;
198 } while (cpool_ptr
< cpool_end
);
201 if (cpool_index
== CPOOL_SIZE
) {
202 /* Must allocate a new entry in the literal pool. */
203 if (compiler
->cpool_fill
< CPOOL_SIZE
) {
204 cpool_index
= compiler
->cpool_fill
;
205 compiler
->cpool_fill
++;
208 FAIL_IF(push_cpool(compiler
));
210 compiler
->cpool_fill
= 1;
214 SLJIT_ASSERT((inst
& 0xfff) == 0);
215 ptr
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
218 *ptr
= inst
| cpool_index
;
220 compiler
->cpool
[cpool_index
] = literal
;
221 compiler
->cpool_unique
[cpool_index
] = 0;
222 if (compiler
->cpool_diff
== CONST_POOL_EMPTY
)
223 compiler
->cpool_diff
= compiler
->size
;
224 return SLJIT_SUCCESS
;
227 static int push_inst_with_unique_literal(struct sljit_compiler
*compiler
, sljit_uw inst
, sljit_uw literal
)
230 if (SLJIT_UNLIKELY((compiler
->cpool_diff
!= CONST_POOL_EMPTY
&& compiler
->size
- compiler
->cpool_diff
>= MAX_DIFFERENCE(4092)) || compiler
->cpool_fill
>= CPOOL_SIZE
))
231 FAIL_IF(push_cpool(compiler
));
233 SLJIT_ASSERT(compiler
->cpool_fill
< CPOOL_SIZE
&& (inst
& 0xfff) == 0);
234 ptr
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
237 *ptr
= inst
| compiler
->cpool_fill
;
239 compiler
->cpool
[compiler
->cpool_fill
] = literal
;
240 compiler
->cpool_unique
[compiler
->cpool_fill
] = 1;
241 compiler
->cpool_fill
++;
242 if (compiler
->cpool_diff
== CONST_POOL_EMPTY
)
243 compiler
->cpool_diff
= compiler
->size
;
244 return SLJIT_SUCCESS
;
247 static SLJIT_INLINE
int prepare_blx(struct sljit_compiler
*compiler
)
249 /* Place for at least two instruction (doesn't matter whether the first has a literal). */
250 if (SLJIT_UNLIKELY(compiler
->cpool_diff
!= CONST_POOL_EMPTY
&& compiler
->size
- compiler
->cpool_diff
>= MAX_DIFFERENCE(4088)))
251 return push_cpool(compiler
);
252 return SLJIT_SUCCESS
;
255 static SLJIT_INLINE
int emit_blx(struct sljit_compiler
*compiler
)
257 /* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */
258 SLJIT_ASSERT(compiler
->cpool_diff
== CONST_POOL_EMPTY
|| compiler
->size
- compiler
->cpool_diff
< MAX_DIFFERENCE(4092));
259 return push_inst(compiler
, BLX
| RM(TMP_REG1
));
262 static sljit_uw
patch_pc_relative_loads(sljit_uw
*last_pc_patch
, sljit_uw
*code_ptr
, sljit_uw
* const_pool
, sljit_uw cpool_size
)
266 sljit_uw counter
= 0;
267 sljit_uw
* clear_const_pool
= const_pool
;
268 sljit_uw
* clear_const_pool_end
= const_pool
+ cpool_size
;
270 SLJIT_ASSERT(const_pool
- code_ptr
<= CONST_POOL_ALIGNMENT
);
271 /* Set unused flag for all literals in the constant pool.
272 I.e.: unused literals can belong to branches, which can be encoded as B or BL.
273 We can "compress" the constant pool by discarding these literals. */
274 while (clear_const_pool
< clear_const_pool_end
)
275 *clear_const_pool
++ = (sljit_uw
)(-1);
277 while (last_pc_patch
< code_ptr
) {
278 /* Data transfer instruction with Rn == r15. */
279 if ((*last_pc_patch
& 0x0c0f0000) == 0x040f0000) {
280 diff
= const_pool
- last_pc_patch
;
281 ind
= (*last_pc_patch
) & 0xfff;
283 /* Must be a load instruction with immediate offset. */
284 SLJIT_ASSERT(ind
< cpool_size
&& !(*last_pc_patch
& (1 << 25)) && (*last_pc_patch
& (1 << 20)));
285 if ((int)const_pool
[ind
] < 0) {
286 const_pool
[ind
] = counter
;
291 ind
= const_pool
[ind
];
293 SLJIT_ASSERT(diff
>= 1);
294 if (diff
>= 2 || ind
> 0) {
295 diff
= (diff
+ ind
- 2) << 2;
296 SLJIT_ASSERT(diff
<= 0xfff);
297 *last_pc_patch
= (*last_pc_patch
& ~0xfff) | diff
;
300 *last_pc_patch
= (*last_pc_patch
& ~(0xfff | (1 << 23))) | 0x004;
307 /* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */
308 struct future_patch
{
309 struct future_patch
* next
;
314 static SLJIT_INLINE
int resolve_const_pool_index(struct future_patch
**first_patch
, sljit_uw cpool_current_index
, sljit_uw
*cpool_start_address
, sljit_uw
*buf_ptr
)
317 struct future_patch
*curr_patch
, *prev_patch
;
319 /* Using the values generated by patch_pc_relative_loads. */
321 value
= (int)cpool_start_address
[cpool_current_index
];
323 curr_patch
= *first_patch
;
327 value
= (int)cpool_start_address
[cpool_current_index
];
330 if ((sljit_uw
)curr_patch
->index
== cpool_current_index
) {
331 value
= curr_patch
->value
;
333 prev_patch
->next
= curr_patch
->next
;
335 *first_patch
= curr_patch
->next
;
336 SLJIT_FREE(curr_patch
);
339 prev_patch
= curr_patch
;
340 curr_patch
= curr_patch
->next
;
345 if ((sljit_uw
)value
> cpool_current_index
) {
346 curr_patch
= (struct future_patch
*)SLJIT_MALLOC(sizeof(struct future_patch
));
348 while (*first_patch
) {
349 curr_patch
= *first_patch
;
350 *first_patch
= (*first_patch
)->next
;
351 SLJIT_FREE(curr_patch
);
353 return SLJIT_ERR_ALLOC_FAILED
;
355 curr_patch
->next
= *first_patch
;
356 curr_patch
->index
= value
;
357 curr_patch
->value
= cpool_start_address
[value
];
358 *first_patch
= curr_patch
;
360 cpool_start_address
[value
] = *buf_ptr
;
362 return SLJIT_SUCCESS
;
367 static int push_inst(struct sljit_compiler
*compiler
, sljit_uw inst
)
371 ptr
= (sljit_uw
*)ensure_buf(compiler
, sizeof(sljit_uw
));
375 return SLJIT_SUCCESS
;
378 static SLJIT_INLINE
int emit_imm(struct sljit_compiler
*compiler
, int reg
, sljit_w imm
)
380 FAIL_IF(push_inst(compiler
, MOVW
| RD(reg
) | ((imm
<< 4) & 0xf0000) | (imm
& 0xfff)));
381 return push_inst(compiler
, MOVT
| RD(reg
) | ((imm
>> 12) & 0xf0000) | ((imm
>> 16) & 0xfff));
386 static SLJIT_INLINE
int detect_jump_type(struct sljit_jump
*jump
, sljit_uw
*code_ptr
, sljit_uw
*code
)
390 if (jump
->flags
& SLJIT_REWRITABLE_JUMP
)
393 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
394 if (jump
->flags
& IS_BL
)
397 if (jump
->flags
& JUMP_ADDR
)
398 diff
= ((sljit_w
)jump
->u
.target
- (sljit_w
)(code_ptr
+ 2));
400 SLJIT_ASSERT(jump
->flags
& JUMP_LABEL
);
401 diff
= ((sljit_w
)(code
+ jump
->u
.label
->size
) - (sljit_w
)(code_ptr
+ 2));
404 /* Branch to Thumb code has not been optimized yet. */
409 if (jump
->flags
& IS_BL
) {
410 if (diff
<= 0x01ffffff && diff
>= -0x02000000) {
411 *code_ptr
= (BL
- CONDITIONAL
) | (*(code_ptr
+ 1) & COND_MASK
);
412 jump
->flags
|= PATCH_B
;
417 if (diff
<= 0x01ffffff && diff
>= -0x02000000) {
418 *code_ptr
= (B
- CONDITIONAL
) | (*code_ptr
& COND_MASK
);
419 jump
->flags
|= PATCH_B
;
423 if (jump
->flags
& JUMP_ADDR
)
424 diff
= ((sljit_w
)jump
->u
.target
- (sljit_w
)code_ptr
);
426 SLJIT_ASSERT(jump
->flags
& JUMP_LABEL
);
427 diff
= ((sljit_w
)(code
+ jump
->u
.label
->size
) - (sljit_w
)code_ptr
);
430 /* Branch to Thumb code has not been optimized yet. */
435 if (diff
<= 0x01ffffff && diff
>= -0x02000000) {
437 *code_ptr
= ((jump
->flags
& IS_BL
) ? (BL
- CONDITIONAL
) : (B
- CONDITIONAL
)) | (code_ptr
[2] & COND_MASK
);
438 jump
->flags
|= PATCH_B
;
445 static SLJIT_INLINE
void inline_set_jump_addr(sljit_uw addr
, sljit_uw new_addr
, int flush
)
447 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
448 sljit_uw
*ptr
= (sljit_uw
*)addr
;
449 sljit_uw
*inst
= (sljit_uw
*)ptr
[0];
450 sljit_uw mov_pc
= ptr
[1];
451 int bl
= (mov_pc
& 0x0000f000) != RD(TMP_PC
);
452 sljit_w diff
= (sljit_w
)(((sljit_w
)new_addr
- (sljit_w
)(inst
+ 2)) >> 2);
454 if (diff
<= 0x7fffff && diff
>= -0x800000) {
455 /* Turn to branch. */
457 inst
[0] = (mov_pc
& COND_MASK
) | (B
- CONDITIONAL
) | (diff
& 0xffffff);
459 SLJIT_CACHE_FLUSH(inst
, inst
+ 1);
462 inst
[0] = (mov_pc
& COND_MASK
) | (BL
- CONDITIONAL
) | (diff
& 0xffffff);
465 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
469 /* Get the position of the constant. */
470 if (mov_pc
& (1 << 23))
471 ptr
= inst
+ ((mov_pc
& 0xfff) >> 2) + 2;
475 if (*inst
!= mov_pc
) {
479 SLJIT_CACHE_FLUSH(inst
, inst
+ 1);
482 inst
[1] = BLX
| RM(TMP_REG1
);
484 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
491 sljit_uw
*inst
= (sljit_uw
*)addr
;
492 SLJIT_ASSERT((inst
[0] & 0xfff00000) == MOVW
&& (inst
[1] & 0xfff00000) == MOVT
);
493 inst
[0] = MOVW
| (inst
[0] & 0xf000) | ((new_addr
<< 4) & 0xf0000) | (new_addr
& 0xfff);
494 inst
[1] = MOVT
| (inst
[1] & 0xf000) | ((new_addr
>> 12) & 0xf0000) | ((new_addr
>> 16) & 0xfff);
496 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
501 static sljit_uw
get_immediate(sljit_uw imm
);
503 static SLJIT_INLINE
void inline_set_const(sljit_uw addr
, sljit_w new_constant
, int flush
)
505 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
506 sljit_uw
*ptr
= (sljit_uw
*)addr
;
507 sljit_uw
*inst
= (sljit_uw
*)ptr
[0];
508 sljit_uw ldr_literal
= ptr
[1];
511 src2
= get_immediate(new_constant
);
513 *inst
= 0xe3a00000 | (ldr_literal
& 0xf000) | src2
;
515 SLJIT_CACHE_FLUSH(inst
, inst
+ 1);
520 src2
= get_immediate(~new_constant
);
522 *inst
= 0xe3e00000 | (ldr_literal
& 0xf000) | src2
;
524 SLJIT_CACHE_FLUSH(inst
, inst
+ 1);
529 if (ldr_literal
& (1 << 23))
530 ptr
= inst
+ ((ldr_literal
& 0xfff) >> 2) + 2;
534 if (*inst
!= ldr_literal
) {
537 SLJIT_CACHE_FLUSH(inst
, inst
+ 1);
542 sljit_uw
*inst
= (sljit_uw
*)addr
;
543 SLJIT_ASSERT((inst
[0] & 0xfff00000) == MOVW
&& (inst
[1] & 0xfff00000) == MOVT
);
544 inst
[0] = MOVW
| (inst
[0] & 0xf000) | ((new_constant
<< 4) & 0xf0000) | (new_constant
& 0xfff);
545 inst
[1] = MOVT
| (inst
[1] & 0xf000) | ((new_constant
>> 12) & 0xf0000) | ((new_constant
>> 16) & 0xfff);
547 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
552 SLJIT_API_FUNC_ATTRIBUTE
void* sljit_generate_code(struct sljit_compiler
*compiler
)
554 struct sljit_memory_fragment
*buf
;
561 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
563 sljit_uw cpool_skip_alignment
;
564 sljit_uw cpool_current_index
;
565 sljit_uw
*cpool_start_address
;
566 sljit_uw
*last_pc_patch
;
567 struct future_patch
*first_patch
;
570 struct sljit_label
*label
;
571 struct sljit_jump
*jump
;
572 struct sljit_const
*const_
;
575 check_sljit_generate_code(compiler
);
576 reverse_buf(compiler
);
578 /* Second code generation pass. */
579 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
580 size
= compiler
->size
+ (compiler
->patches
<< 1);
581 if (compiler
->cpool_fill
> 0)
582 size
+= compiler
->cpool_fill
+ CONST_POOL_ALIGNMENT
- 1;
584 size
= compiler
->size
;
586 code
= (sljit_uw
*)SLJIT_MALLOC_EXEC(size
* sizeof(sljit_uw
));
587 PTR_FAIL_WITH_EXEC_IF(code
);
590 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
592 cpool_skip_alignment
= 0;
593 cpool_current_index
= 0;
594 cpool_start_address
= NULL
;
596 last_pc_patch
= code
;
602 label
= compiler
->labels
;
603 jump
= compiler
->jumps
;
604 const_
= compiler
->consts
;
606 if (label
&& label
->size
== 0) {
607 label
->addr
= (sljit_uw
)code
;
613 buf_ptr
= (sljit_uw
*)buf
->memory
;
614 buf_end
= buf_ptr
+ (buf
->used_size
>> 2);
617 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
618 if (cpool_size
> 0) {
619 if (cpool_skip_alignment
> 0) {
621 cpool_skip_alignment
--;
624 if (SLJIT_UNLIKELY(resolve_const_pool_index(&first_patch
, cpool_current_index
, cpool_start_address
, buf_ptr
))) {
625 SLJIT_FREE_EXEC(code
);
626 compiler
->error
= SLJIT_ERR_ALLOC_FAILED
;
630 if (++cpool_current_index
>= cpool_size
) {
631 SLJIT_ASSERT(!first_patch
);
633 if (label
&& label
->size
== word_count
) {
634 /* Points after the current instruction. */
635 label
->addr
= (sljit_uw
)code_ptr
;
636 label
->size
= code_ptr
- code
;
642 else if ((*buf_ptr
& 0xff000000) != PUSH_POOL
) {
644 *code_ptr
= *buf_ptr
++;
645 /* These structures are ordered by their address. */
646 SLJIT_ASSERT(!label
|| label
->size
>= word_count
);
647 SLJIT_ASSERT(!jump
|| jump
->addr
>= word_count
);
648 SLJIT_ASSERT(!const_
|| const_
->addr
>= word_count
);
649 if (jump
&& jump
->addr
== word_count
) {
650 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
651 if (detect_jump_type(jump
, code_ptr
, code
))
653 jump
->addr
= (sljit_uw
)code_ptr
;
655 jump
->addr
= (sljit_uw
)(code_ptr
- 2);
656 if (detect_jump_type(jump
, code_ptr
, code
))
661 if (label
&& label
->size
== word_count
) {
662 /* code_ptr can be affected above. */
663 label
->addr
= (sljit_uw
)(code_ptr
+ 1);
664 label
->size
= (code_ptr
+ 1) - code
;
667 if (const_
&& const_
->addr
== word_count
) {
668 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
669 const_
->addr
= (sljit_uw
)code_ptr
;
671 const_
->addr
= (sljit_uw
)(code_ptr
- 1);
673 const_
= const_
->next
;
676 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
679 /* Fortunately, no need to shift. */
680 cpool_size
= *buf_ptr
++ & ~PUSH_POOL
;
681 SLJIT_ASSERT(cpool_size
> 0);
682 cpool_start_address
= ALIGN_INSTRUCTION(code_ptr
+ 1);
683 cpool_current_index
= patch_pc_relative_loads(last_pc_patch
, code_ptr
, cpool_start_address
, cpool_size
);
684 if (cpool_current_index
> 0) {
685 /* Unconditional branch. */
686 *code_ptr
= B
| (((cpool_start_address
- code_ptr
) + cpool_current_index
- 2) & ~PUSH_POOL
);
687 code_ptr
= cpool_start_address
+ cpool_current_index
;
689 cpool_skip_alignment
= CONST_POOL_ALIGNMENT
- 1;
690 cpool_current_index
= 0;
691 last_pc_patch
= code_ptr
;
694 } while (buf_ptr
< buf_end
);
698 SLJIT_ASSERT(!label
);
700 SLJIT_ASSERT(!const_
);
702 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
703 SLJIT_ASSERT(cpool_size
== 0);
704 if (compiler
->cpool_fill
> 0) {
705 cpool_start_address
= ALIGN_INSTRUCTION(code_ptr
);
706 cpool_current_index
= patch_pc_relative_loads(last_pc_patch
, code_ptr
, cpool_start_address
, compiler
->cpool_fill
);
707 if (cpool_current_index
> 0)
708 code_ptr
= cpool_start_address
+ cpool_current_index
;
710 buf_ptr
= compiler
->cpool
;
711 buf_end
= buf_ptr
+ compiler
->cpool_fill
;
712 cpool_current_index
= 0;
713 while (buf_ptr
< buf_end
) {
714 if (SLJIT_UNLIKELY(resolve_const_pool_index(&first_patch
, cpool_current_index
, cpool_start_address
, buf_ptr
))) {
715 SLJIT_FREE_EXEC(code
);
716 compiler
->error
= SLJIT_ERR_ALLOC_FAILED
;
720 cpool_current_index
++;
722 SLJIT_ASSERT(!first_patch
);
726 jump
= compiler
->jumps
;
728 buf_ptr
= (sljit_uw
*)jump
->addr
;
730 if (jump
->flags
& PATCH_B
) {
731 if (!(jump
->flags
& JUMP_ADDR
)) {
732 SLJIT_ASSERT(jump
->flags
& JUMP_LABEL
);
733 SLJIT_ASSERT(((sljit_w
)jump
->u
.label
->addr
- (sljit_w
)(buf_ptr
+ 2)) <= 0x01ffffff && ((sljit_w
)jump
->u
.label
->addr
- (sljit_w
)(buf_ptr
+ 2)) >= -0x02000000);
734 *buf_ptr
|= (((sljit_w
)jump
->u
.label
->addr
- (sljit_w
)(buf_ptr
+ 2)) >> 2) & 0x00ffffff;
737 SLJIT_ASSERT(((sljit_w
)jump
->u
.target
- (sljit_w
)(buf_ptr
+ 2)) <= 0x01ffffff && ((sljit_w
)jump
->u
.target
- (sljit_w
)(buf_ptr
+ 2)) >= -0x02000000);
738 *buf_ptr
|= (((sljit_w
)jump
->u
.target
- (sljit_w
)(buf_ptr
+ 2)) >> 2) & 0x00ffffff;
741 else if (jump
->flags
& SLJIT_REWRITABLE_JUMP
) {
742 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
743 jump
->addr
= (sljit_uw
)code_ptr
;
744 code_ptr
[0] = (sljit_uw
)buf_ptr
;
745 code_ptr
[1] = *buf_ptr
;
746 inline_set_jump_addr((sljit_uw
)code_ptr
, (jump
->flags
& JUMP_LABEL
) ? jump
->u
.label
->addr
: jump
->u
.target
, 0);
749 inline_set_jump_addr((sljit_uw
)buf_ptr
, (jump
->flags
& JUMP_LABEL
) ? jump
->u
.label
->addr
: jump
->u
.target
, 0);
753 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
754 if (jump
->flags
& IS_BL
)
756 if (*buf_ptr
& (1 << 23))
757 buf_ptr
+= ((*buf_ptr
& 0xfff) >> 2) + 2;
760 *buf_ptr
= (jump
->flags
& JUMP_LABEL
) ? jump
->u
.label
->addr
: jump
->u
.target
;
762 inline_set_jump_addr((sljit_uw
)buf_ptr
, (jump
->flags
& JUMP_LABEL
) ? jump
->u
.label
->addr
: jump
->u
.target
, 0);
768 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
769 const_
= compiler
->consts
;
771 buf_ptr
= (sljit_uw
*)const_
->addr
;
772 const_
->addr
= (sljit_uw
)code_ptr
;
774 code_ptr
[0] = (sljit_uw
)buf_ptr
;
775 code_ptr
[1] = *buf_ptr
;
776 if (*buf_ptr
& (1 << 23))
777 buf_ptr
+= ((*buf_ptr
& 0xfff) >> 2) + 2;
780 /* Set the value again (can be a simple constant). */
781 inline_set_const((sljit_uw
)code_ptr
, *buf_ptr
, 0);
784 const_
= const_
->next
;
788 SLJIT_ASSERT(code_ptr
- code
<= (int)size
);
790 SLJIT_CACHE_FLUSH(code
, code_ptr
);
791 compiler
->error
= SLJIT_ERR_COMPILED
;
792 compiler
->executable_size
= size
* sizeof(sljit_uw
);
796 /* --------------------------------------------------------------------- */
798 /* --------------------------------------------------------------------- */
800 /* emit_op inp_flags.
801 WRITE_BACK must be the first, since it is a flag. */
802 #define WRITE_BACK 0x01
803 #define ALLOW_IMM 0x02
804 #define ALLOW_INV_IMM 0x04
805 #define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM)
806 #define ARG_TEST 0x08
808 /* Creates an index in data_transfer_insts array. */
809 #define WORD_DATA 0x00
810 #define BYTE_DATA 0x10
811 #define HALF_DATA 0x20
812 #define SIGNED_DATA 0x40
813 #define LOAD_DATA 0x80
815 #define EMIT_INSTRUCTION(inst) \
816 FAIL_IF(push_inst(compiler, (inst)))
819 #define EMIT_DATA_PROCESS_INS(opcode, set_flags, dst, src1, src2) \
820 (0xe0000000 | ((opcode) << 21) | (set_flags) | RD(dst) | RN(src1) | (src2))
822 static int emit_op(struct sljit_compiler
*compiler
, int op
, int inp_flags
,
823 int dst
, sljit_w dstw
,
824 int src1
, sljit_w src1w
,
825 int src2
, sljit_w src2w
);
827 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_enter(struct sljit_compiler
*compiler
, int args
, int temporaries
, int saveds
, int local_size
)
833 check_sljit_emit_enter(compiler
, args
, temporaries
, saveds
, local_size
);
835 compiler
->temporaries
= temporaries
;
836 compiler
->saveds
= saveds
;
837 #if (defined SLJIT_DEBUG && SLJIT_DEBUG)
838 compiler
->logical_local_size
= local_size
;
841 /* Push saved registers, temporary registers
842 stmdb sp!, {..., lr} */
843 push
= PUSH
| (1 << 14);
844 if (temporaries
>= 5)
846 if (temporaries
>= 4)
858 EMIT_INSTRUCTION(push
);
860 /* Stack must be aligned to 8 bytes: */
861 size
= (1 + saveds
) * sizeof(sljit_uw
);
862 if (temporaries
>= 4)
863 size
+= (temporaries
- 3) * sizeof(sljit_uw
);
865 local_size
= (local_size
+ 7) & ~7;
867 compiler
->local_size
= local_size
;
869 FAIL_IF(emit_op(compiler
, SLJIT_SUB
, ALLOW_IMM
, SLJIT_LOCALS_REG
, 0, SLJIT_LOCALS_REG
, 0, SLJIT_IMM
, local_size
));
872 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, SLJIT_SAVED_REG1
, SLJIT_UNUSED
, RM(SLJIT_TEMPORARY_REG1
)));
874 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, SLJIT_SAVED_REG2
, SLJIT_UNUSED
, RM(SLJIT_TEMPORARY_REG2
)));
876 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, SLJIT_SAVED_REG3
, SLJIT_UNUSED
, RM(SLJIT_TEMPORARY_REG3
)));
878 return SLJIT_SUCCESS
;
881 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_context(struct sljit_compiler
*compiler
, int args
, int temporaries
, int saveds
, int local_size
)
886 check_sljit_set_context(compiler
, args
, temporaries
, saveds
, local_size
);
888 compiler
->temporaries
= temporaries
;
889 compiler
->saveds
= saveds
;
890 #if (defined SLJIT_DEBUG && SLJIT_DEBUG)
891 compiler
->logical_local_size
= local_size
;
894 size
= (1 + saveds
) * sizeof(sljit_uw
);
895 if (temporaries
>= 4)
896 size
+= (temporaries
- 3) * sizeof(sljit_uw
);
898 local_size
= (local_size
+ 7) & ~7;
900 compiler
->local_size
= local_size
;
903 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_return(struct sljit_compiler
*compiler
, int op
, int src
, sljit_w srcw
)
908 check_sljit_emit_return(compiler
, op
, src
, srcw
);
910 FAIL_IF(emit_mov_before_return(compiler
, op
, src
, srcw
));
912 if (compiler
->local_size
> 0)
913 FAIL_IF(emit_op(compiler
, SLJIT_ADD
, ALLOW_IMM
, SLJIT_LOCALS_REG
, 0, SLJIT_LOCALS_REG
, 0, SLJIT_IMM
, compiler
->local_size
));
915 pop
= POP
| (1 << 15);
916 /* Push saved registers, temporary registers
917 ldmia sp!, {..., pc} */
918 if (compiler
->temporaries
>= 5)
920 if (compiler
->temporaries
>= 4)
922 if (compiler
->saveds
>= 5)
924 if (compiler
->saveds
>= 4)
926 if (compiler
->saveds
>= 3)
928 if (compiler
->saveds
>= 2)
930 if (compiler
->saveds
>= 1)
933 return push_inst(compiler
, pop
);
936 /* --------------------------------------------------------------------- */
938 /* --------------------------------------------------------------------- */
940 /* s/l - store/load (1 bit)
941 u/s - signed/unsigned (1 bit)
942 w/b/h/N - word/byte/half/NOT allowed (2 bit)
943 It contans 16 items, but not all are different. */
945 static sljit_w data_transfer_insts
[16] = {
946 /* s u w */ 0xe5000000 /* str */,
947 /* s u b */ 0xe5400000 /* strb */,
948 /* s u h */ 0xe10000b0 /* strh */,
949 /* s u N */ 0x00000000 /* not allowed */,
950 /* s s w */ 0xe5000000 /* str */,
951 /* s s b */ 0xe5400000 /* strb */,
952 /* s s h */ 0xe10000b0 /* strh */,
953 /* s s N */ 0x00000000 /* not allowed */,
955 /* l u w */ 0xe5100000 /* ldr */,
956 /* l u b */ 0xe5500000 /* ldrb */,
957 /* l u h */ 0xe11000b0 /* ldrh */,
958 /* l u N */ 0x00000000 /* not allowed */,
959 /* l s w */ 0xe5100000 /* ldr */,
960 /* l s b */ 0xe11000d0 /* ldrsb */,
961 /* l s h */ 0xe11000f0 /* ldrsh */,
962 /* l s N */ 0x00000000 /* not allowed */,
965 #define EMIT_DATA_TRANSFER(type, add, wb, target, base1, base2) \
966 (data_transfer_insts[(type) >> 4] | ((add) << 23) | ((wb) << 21) | (reg_map[target] << 12) | (reg_map[base1] << 16) | (base2))
967 /* Normal ldr/str instruction.
968 Type2: ldrsb, ldrh, ldrsh */
969 #define IS_TYPE1_TRANSFER(type) \
970 (data_transfer_insts[(type) >> 4] & 0x04000000)
971 #define TYPE2_TRANSFER_IMM(imm) \
972 (((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))
975 /* Arguments are swapped. */
976 #define ARGS_SWAPPED 0x01
977 /* Inverted immediate. */
979 /* Source and destination is register. */
980 #define REG_DEST 0x04
981 #define REG_SOURCE 0x08
982 /* One instruction is enough. */
983 #define FAST_DEST 0x10
984 /* Multiple instructions are required. */
985 #define SLOW_DEST 0x20
986 /* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */
987 #define SET_FLAGS (1 << 20)
990 src2: reg or imm (if allowed)
991 SRC2_IMM must be (1 << 25) as it is also the value of I bit (can be used for optimization). */
992 #define SRC2_IMM (1 << 25)
994 #define EMIT_DATA_PROCESS_INS_AND_RETURN(opcode) \
995 return push_inst(compiler, EMIT_DATA_PROCESS_INS(opcode, flags & SET_FLAGS, dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)))
997 #define EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(opcode, dst, src1, src2) \
998 return push_inst(compiler, EMIT_DATA_PROCESS_INS(opcode, flags & SET_FLAGS, dst, src1, src2))
1000 #define EMIT_SHIFT_INS_AND_RETURN(opcode) \
1001 SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); \
1002 if (compiler->shift_imm != 0x20) { \
1003 SLJIT_ASSERT(src1 == TMP_REG1); \
1004 SLJIT_ASSERT(!(flags & ARGS_SWAPPED)); \
1005 if (compiler->shift_imm != 0) \
1006 return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (compiler->shift_imm << 7) | (opcode << 5) | reg_map[src2])); \
1007 return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, reg_map[src2])); \
1009 return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (reg_map[(flags & ARGS_SWAPPED) ? src1 : src2] << 8) | (opcode << 5) | 0x10 | ((flags & ARGS_SWAPPED) ? reg_map[src2] : reg_map[src1])));
1011 static SLJIT_INLINE
int emit_single_op(struct sljit_compiler
*compiler
, int op
, int flags
,
1012 int dst
, int src1
, int src2
)
1016 switch (GET_OPCODE(op
)) {
1018 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& ARGS_SWAPPED
));
1020 if (src2
& SRC2_IMM
) {
1021 if (flags
& INV_IMM
)
1022 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP
, dst
, SLJIT_UNUSED
, src2
);
1023 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP
, dst
, SLJIT_UNUSED
, src2
);
1025 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP
, dst
, SLJIT_UNUSED
, reg_map
[src2
]);
1027 return SLJIT_SUCCESS
;
1031 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& ARGS_SWAPPED
));
1032 if ((flags
& (REG_DEST
| REG_SOURCE
)) == (REG_DEST
| REG_SOURCE
)) {
1033 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
1034 if (op
== SLJIT_MOV_UB
)
1035 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(AND_DP
, 0, dst
, src2
, SRC2_IMM
| 0xff));
1036 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst
, SLJIT_UNUSED
, (24 << 7) | reg_map
[src2
]));
1037 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst
, SLJIT_UNUSED
, (24 << 7) | (op
== SLJIT_MOV_UB
? 0x20 : 0x40) | reg_map
[dst
]));
1039 return push_inst(compiler
, (op
== SLJIT_MOV_UB
? UXTB
: SXTB
) | RD(dst
) | RM(src2
));
1042 else if (dst
!= src2
) {
1043 SLJIT_ASSERT(src2
& SRC2_IMM
);
1044 if (flags
& INV_IMM
)
1045 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP
, dst
, SLJIT_UNUSED
, src2
);
1046 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP
, dst
, SLJIT_UNUSED
, src2
);
1048 return SLJIT_SUCCESS
;
1052 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& ARGS_SWAPPED
));
1053 if ((flags
& (REG_DEST
| REG_SOURCE
)) == (REG_DEST
| REG_SOURCE
)) {
1054 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
1055 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst
, SLJIT_UNUSED
, (16 << 7) | reg_map
[src2
]));
1056 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst
, SLJIT_UNUSED
, (16 << 7) | (op
== SLJIT_MOV_UH
? 0x20 : 0x40) | reg_map
[dst
]));
1058 return push_inst(compiler
, (op
== SLJIT_MOV_UH
? UXTH
: SXTH
) | RD(dst
) | RM(src2
));
1061 else if (dst
!= src2
) {
1062 SLJIT_ASSERT(src2
& SRC2_IMM
);
1063 if (flags
& INV_IMM
)
1064 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP
, dst
, SLJIT_UNUSED
, src2
);
1065 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP
, dst
, SLJIT_UNUSED
, src2
);
1067 return SLJIT_SUCCESS
;
1070 if (src2
& SRC2_IMM
) {
1071 if (flags
& INV_IMM
)
1072 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP
, dst
, SLJIT_UNUSED
, src2
);
1073 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP
, dst
, SLJIT_UNUSED
, src2
);
1075 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP
, dst
, SLJIT_UNUSED
, RM(src2
));
1078 SLJIT_ASSERT(!(flags
& INV_IMM
));
1079 SLJIT_ASSERT(!(src2
& SRC2_IMM
));
1080 FAIL_IF(push_inst(compiler
, CLZ
| RD(dst
) | RM(src2
)));
1081 if (flags
& SET_FLAGS
)
1082 EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(CMP_DP
, SLJIT_UNUSED
, dst
, SRC2_IMM
);
1083 return SLJIT_SUCCESS
;
1086 SLJIT_ASSERT(!(flags
& INV_IMM
));
1087 EMIT_DATA_PROCESS_INS_AND_RETURN(ADD_DP
);
1090 SLJIT_ASSERT(!(flags
& INV_IMM
));
1091 EMIT_DATA_PROCESS_INS_AND_RETURN(ADC_DP
);
1094 SLJIT_ASSERT(!(flags
& INV_IMM
));
1095 if (!(flags
& ARGS_SWAPPED
))
1096 EMIT_DATA_PROCESS_INS_AND_RETURN(SUB_DP
);
1097 EMIT_DATA_PROCESS_INS_AND_RETURN(RSB_DP
);
1100 SLJIT_ASSERT(!(flags
& INV_IMM
));
1101 if (!(flags
& ARGS_SWAPPED
))
1102 EMIT_DATA_PROCESS_INS_AND_RETURN(SBC_DP
);
1103 EMIT_DATA_PROCESS_INS_AND_RETURN(RSC_DP
);
1106 SLJIT_ASSERT(!(flags
& INV_IMM
));
1107 SLJIT_ASSERT(!(src2
& SRC2_IMM
));
1108 if (SLJIT_UNLIKELY(op
& SLJIT_SET_O
))
1109 mul_inst
= SMULL
| (reg_map
[TMP_REG3
] << 16) | (reg_map
[dst
] << 12);
1111 mul_inst
= MUL
| (reg_map
[dst
] << 16);
1114 FAIL_IF(push_inst(compiler
, mul_inst
| (reg_map
[src1
] << 8) | reg_map
[src2
]));
1115 else if (dst
!= src1
)
1116 FAIL_IF(push_inst(compiler
, mul_inst
| (reg_map
[src2
] << 8) | reg_map
[src1
]));
1118 /* Rm and Rd must not be the same register. */
1119 SLJIT_ASSERT(dst
!= TMP_REG1
);
1120 FAIL_IF(push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG1
, SLJIT_UNUSED
, reg_map
[src2
])));
1121 FAIL_IF(push_inst(compiler
, mul_inst
| (reg_map
[src2
] << 8) | reg_map
[TMP_REG1
]));
1124 if (!(op
& SLJIT_SET_O
))
1125 return SLJIT_SUCCESS
;
1127 /* We need to use TMP_REG3. */
1128 compiler
->cache_arg
= 0;
1129 compiler
->cache_argw
= 0;
1130 /* cmp TMP_REG2, dst asr #31. */
1131 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(CMP_DP
, SET_FLAGS
, SLJIT_UNUSED
, TMP_REG3
, RM(dst
) | 0xfc0));
1134 if (!(flags
& INV_IMM
))
1135 EMIT_DATA_PROCESS_INS_AND_RETURN(AND_DP
);
1136 EMIT_DATA_PROCESS_INS_AND_RETURN(BIC_DP
);
1139 SLJIT_ASSERT(!(flags
& INV_IMM
));
1140 EMIT_DATA_PROCESS_INS_AND_RETURN(ORR_DP
);
1143 SLJIT_ASSERT(!(flags
& INV_IMM
));
1144 EMIT_DATA_PROCESS_INS_AND_RETURN(EOR_DP
);
1147 EMIT_SHIFT_INS_AND_RETURN(0);
1150 EMIT_SHIFT_INS_AND_RETURN(1);
1153 EMIT_SHIFT_INS_AND_RETURN(2);
1155 SLJIT_ASSERT_STOP();
1156 return SLJIT_SUCCESS
;
1159 #undef EMIT_DATA_PROCESS_INS_AND_RETURN
1160 #undef EMIT_FULL_DATA_PROCESS_INS_AND_RETURN
1161 #undef EMIT_SHIFT_INS_AND_RETURN
1163 /* Tests whether the immediate can be stored in the 12 bit imm field.
1164 Returns with 0 if not possible. */
1165 static sljit_uw
get_immediate(sljit_uw imm
)
1170 return SRC2_IMM
| imm
;
1172 if (!(imm
& 0xff000000)) {
1177 imm
= (imm
<< 24) | (imm
>> 8);
1181 if (!(imm
& 0xff000000)) {
1186 if (!(imm
& 0xf0000000)) {
1191 if (!(imm
& 0xc0000000)) {
1196 if (!(imm
& 0x00ffffff))
1197 return SRC2_IMM
| (imm
>> 24) | (rol
<< 8);
1202 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
1203 static int generate_int(struct sljit_compiler
*compiler
, int reg
, sljit_uw imm
, int positive
)
1210 /* Step1: Search a zero byte (8 continous zero bit). */
1214 if (!(imm
& mask
)) {
1215 /* Rol imm by rol. */
1216 imm
= (imm
<< rol
) | (imm
>> (32 - rol
));
1217 /* Calculate arm rol. */
1218 rol
= 4 + (rol
>> 1);
1225 imm
= (imm
<< 8) | (imm
>> 24);
1229 if (!(imm
& mask
)) {
1230 /* Rol imm by rol. */
1231 imm
= (imm
<< rol
) | (imm
>> (32 - rol
));
1232 /* Calculate arm rol. */
1233 rol
= (rol
>> 1) - 8;
1245 /* The low 8 bit must be zero. */
1246 SLJIT_ASSERT(!(imm
& 0xff));
1248 if (!(imm
& 0xff000000)) {
1249 imm1
= SRC2_IMM
| ((imm
>> 16) & 0xff) | (((rol
+ 4) & 0xf) << 8);
1250 imm2
= SRC2_IMM
| ((imm
>> 8) & 0xff) | (((rol
+ 8) & 0xf) << 8);
1252 else if (imm
& 0xc0000000) {
1253 imm1
= SRC2_IMM
| ((imm
>> 24) & 0xff) | ((rol
& 0xf) << 8);
1257 if (!(imm
& 0xff000000)) {
1262 if (!(imm
& 0xf0000000)) {
1267 if (!(imm
& 0xc0000000)) {
1272 if (!(imm
& 0x00ffffff))
1273 imm2
= SRC2_IMM
| (imm
>> 24) | ((rol
& 0xf) << 8);
1278 if (!(imm
& 0xf0000000)) {
1283 if (!(imm
& 0xc0000000)) {
1288 imm1
= SRC2_IMM
| ((imm
>> 24) & 0xff) | ((rol
& 0xf) << 8);
1292 if (!(imm
& 0xf0000000)) {
1297 if (!(imm
& 0xc0000000)) {
1302 if (!(imm
& 0x00ffffff))
1303 imm2
= SRC2_IMM
| (imm
>> 24) | ((rol
& 0xf) << 8);
1308 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(positive
? MOV_DP
: MVN_DP
, 0, reg
, SLJIT_UNUSED
, imm1
));
1309 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(positive
? ORR_DP
: BIC_DP
, 0, reg
, reg
, imm2
));
1314 static int load_immediate(struct sljit_compiler
*compiler
, int reg
, sljit_uw imm
)
1318 #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
1319 if (!(imm
& ~0xffff))
1320 return push_inst(compiler
, MOVW
| RD(reg
) | ((imm
<< 4) & 0xf0000) | (imm
& 0xfff));
1323 /* Create imm by 1 inst. */
1324 tmp
= get_immediate(imm
);
1326 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, reg
, SLJIT_UNUSED
, tmp
));
1327 return SLJIT_SUCCESS
;
1330 tmp
= get_immediate(~imm
);
1332 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MVN_DP
, 0, reg
, SLJIT_UNUSED
, tmp
));
1333 return SLJIT_SUCCESS
;
1336 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
1337 /* Create imm by 2 inst. */
1338 FAIL_IF(generate_int(compiler
, reg
, imm
, 1));
1339 FAIL_IF(generate_int(compiler
, reg
, ~imm
, 0));
1342 return push_inst_with_literal(compiler
, EMIT_DATA_TRANSFER(WORD_DATA
| LOAD_DATA
, 1, 0, reg
, TMP_PC
, 0), imm
);
1344 return emit_imm(compiler
, reg
, imm
);
1348 /* Can perform an operation using at most 1 instruction. */
1349 static int getput_arg_fast(struct sljit_compiler
*compiler
, int inp_flags
, int reg
, int arg
, sljit_w argw
)
1353 if (arg
& SLJIT_IMM
) {
1354 imm
= get_immediate(argw
);
1356 if (inp_flags
& ARG_TEST
)
1358 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, reg
, SLJIT_UNUSED
, imm
));
1361 imm
= get_immediate(~argw
);
1363 if (inp_flags
& ARG_TEST
)
1365 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MVN_DP
, 0, reg
, SLJIT_UNUSED
, imm
));
1368 return (inp_flags
& ARG_TEST
) ? SLJIT_SUCCESS
: 0;
1371 SLJIT_ASSERT(arg
& SLJIT_MEM
);
1373 /* Fast loads/stores. */
1375 if (!(arg
& 0xf0)) {
1376 if (IS_TYPE1_TRANSFER(inp_flags
)) {
1377 if (argw
>= 0 && argw
<= 0xfff) {
1378 if (inp_flags
& ARG_TEST
)
1380 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, argw
));
1383 if (argw
< 0 && argw
>= -0xfff) {
1384 if (inp_flags
& ARG_TEST
)
1386 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 0, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, -argw
));
1391 if (argw
>= 0 && argw
<= 0xff) {
1392 if (inp_flags
& ARG_TEST
)
1394 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, TYPE2_TRANSFER_IMM(argw
)));
1397 if (argw
< 0 && argw
>= -0xff) {
1398 if (inp_flags
& ARG_TEST
)
1401 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 0, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, TYPE2_TRANSFER_IMM(argw
)));
1406 else if ((argw
& 0x3) == 0 || IS_TYPE1_TRANSFER(inp_flags
)) {
1407 if (inp_flags
& ARG_TEST
)
1409 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf,
1410 RM((arg
>> 4) & 0xf) | (IS_TYPE1_TRANSFER(inp_flags
) ? SRC2_IMM
: 0) | ((argw
& 0x3) << 7)));
1415 return (inp_flags
& ARG_TEST
) ? SLJIT_SUCCESS
: 0;
1418 /* See getput_arg below.
1419 Note: can_cache is called only for binary operators. Those
1420 operators always uses word arguments without write back. */
1421 static int can_cache(int arg
, sljit_w argw
, int next_arg
, sljit_w next_argw
)
1423 /* Immediate caching is not supported as it would be an operation on constant arguments. */
1424 if (arg
& SLJIT_IMM
)
1427 /* Always a simple operation. */
1432 /* Immediate access. */
1433 if ((next_arg
& SLJIT_MEM
) && ((sljit_uw
)argw
- (sljit_uw
)next_argw
<= 0xfff || (sljit_uw
)next_argw
- (sljit_uw
)argw
<= 0xfff))
1438 if (argw
<= 0xfffff && argw
>= -0xfffff)
1441 if (argw
== next_argw
&& (next_arg
& SLJIT_MEM
))
1444 if (arg
== next_arg
&& ((sljit_uw
)argw
- (sljit_uw
)next_argw
<= 0xfff || (sljit_uw
)next_argw
- (sljit_uw
)argw
<= 0xfff))
1450 #define GETPUT_ARG_DATA_TRANSFER(add, wb, target, base, imm) \
1451 if (max_delta & 0xf00) \
1452 FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, imm))); \
1454 FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, TYPE2_TRANSFER_IMM(imm))));
1456 #define TEST_WRITE_BACK() \
1457 if (inp_flags & WRITE_BACK) { \
1458 tmp_r = arg & 0xf; \
1459 if (reg == tmp_r) { \
1460 /* This can only happen for stores */ \
1461 /* since ldr reg, [reg, ...]! has no meaning */ \
1462 SLJIT_ASSERT(!(inp_flags & LOAD_DATA)); \
1463 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(reg))); \
1468 /* Emit the necessary instructions. See can_cache above. */
1469 static int getput_arg(struct sljit_compiler
*compiler
, int inp_flags
, int reg
, int arg
, sljit_w argw
, int next_arg
, sljit_w next_argw
)
1475 if (arg
& SLJIT_IMM
) {
1476 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1477 return load_immediate(compiler
, reg
, argw
);
1480 SLJIT_ASSERT(arg
& SLJIT_MEM
);
1482 tmp_r
= (inp_flags
& LOAD_DATA
) ? reg
: TMP_REG3
;
1483 max_delta
= IS_TYPE1_TRANSFER(inp_flags
) ? 0xfff : 0xff;
1485 if ((arg
& 0xf) == SLJIT_UNUSED
) {
1486 /* Write back is not used. */
1487 if ((compiler
->cache_arg
& SLJIT_IMM
) && (((sljit_uw
)argw
- (sljit_uw
)compiler
->cache_argw
) <= (sljit_uw
)max_delta
|| ((sljit_uw
)compiler
->cache_argw
- (sljit_uw
)argw
) <= (sljit_uw
)max_delta
)) {
1488 if (((sljit_uw
)argw
- (sljit_uw
)compiler
->cache_argw
) <= (sljit_uw
)max_delta
) {
1490 argw
= argw
- compiler
->cache_argw
;
1494 argw
= compiler
->cache_argw
- argw
;
1497 if (max_delta
& 0xf00) {
1498 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, sign
, 0, reg
, TMP_REG3
, argw
));
1501 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, sign
, 0, reg
, TMP_REG3
, TYPE2_TRANSFER_IMM(argw
)));
1503 return SLJIT_SUCCESS
;
1506 /* With write back, we can create some sophisticated loads, but
1507 it is hard to decide whether we should convert downward (0s) or upward (1s). */
1508 if ((next_arg
& SLJIT_MEM
) && ((sljit_uw
)argw
- (sljit_uw
)next_argw
<= (sljit_uw
)max_delta
|| (sljit_uw
)next_argw
- (sljit_uw
)argw
<= (sljit_uw
)max_delta
)) {
1509 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1511 compiler
->cache_arg
= SLJIT_IMM
;
1512 compiler
->cache_argw
= argw
;
1516 FAIL_IF(load_immediate(compiler
, tmp_r
, argw
));
1517 GETPUT_ARG_DATA_TRANSFER(1, 0, reg
, tmp_r
, 0);
1518 return SLJIT_SUCCESS
;
1521 /* Extended imm addressing for [reg+imm] format. */
1522 sign
= (max_delta
<< 8) | 0xff;
1523 if (!(arg
& 0xf0) && argw
<= sign
&& argw
>= -sign
) {
1533 /* Optimization: add is 0x4, sub is 0x2. Sign is 1 for add and 0 for sub. */
1534 if (max_delta
& 0xf00)
1535 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP
<< sign
, 0, tmp_r
, arg
& 0xf, SRC2_IMM
| (argw
>> 12) | 0xa00));
1537 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP
<< sign
, 0, tmp_r
, arg
& 0xf, SRC2_IMM
| (argw
>> 8) | 0xc00));
1540 GETPUT_ARG_DATA_TRANSFER(sign
, inp_flags
& WRITE_BACK
, reg
, tmp_r
, argw
);
1541 return SLJIT_SUCCESS
;
1545 SLJIT_ASSERT((argw
& 0x3) && !(max_delta
& 0xf00));
1546 if (inp_flags
& WRITE_BACK
)
1548 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, tmp_r
, arg
& 0xf, RM((arg
>> 4) & 0xf) | ((argw
& 0x3) << 7)));
1549 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, 0, reg
, tmp_r
, TYPE2_TRANSFER_IMM(0)));
1550 return SLJIT_SUCCESS
;
1553 if (compiler
->cache_arg
== arg
&& ((sljit_uw
)argw
- (sljit_uw
)compiler
->cache_argw
) <= (sljit_uw
)max_delta
) {
1554 SLJIT_ASSERT(!(inp_flags
& WRITE_BACK
));
1555 argw
= argw
- compiler
->cache_argw
;
1556 GETPUT_ARG_DATA_TRANSFER(1, 0, reg
, TMP_REG3
, argw
);
1557 return SLJIT_SUCCESS
;
1560 if (compiler
->cache_arg
== arg
&& ((sljit_uw
)compiler
->cache_argw
- (sljit_uw
)argw
) <= (sljit_uw
)max_delta
) {
1561 SLJIT_ASSERT(!(inp_flags
& WRITE_BACK
));
1562 argw
= compiler
->cache_argw
- argw
;
1563 GETPUT_ARG_DATA_TRANSFER(0, 0, reg
, TMP_REG3
, argw
);
1564 return SLJIT_SUCCESS
;
1567 if ((compiler
->cache_arg
& SLJIT_IMM
) && compiler
->cache_argw
== argw
) {
1569 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, RM(TMP_REG3
) | (max_delta
& 0xf00 ? SRC2_IMM
: 0)));
1570 return SLJIT_SUCCESS
;
1573 if (argw
== next_argw
&& (next_arg
& SLJIT_MEM
)) {
1574 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1575 FAIL_IF(load_immediate(compiler
, TMP_REG3
, argw
));
1577 compiler
->cache_arg
= SLJIT_IMM
;
1578 compiler
->cache_argw
= argw
;
1581 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, RM(TMP_REG3
) | (max_delta
& 0xf00 ? SRC2_IMM
: 0)));
1582 return SLJIT_SUCCESS
;
1585 if (arg
== next_arg
&& !(inp_flags
& WRITE_BACK
) && ((sljit_uw
)argw
- (sljit_uw
)next_argw
<= (sljit_uw
)max_delta
|| (sljit_uw
)next_argw
- (sljit_uw
)argw
<= (sljit_uw
)max_delta
)) {
1586 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1587 FAIL_IF(load_immediate(compiler
, TMP_REG3
, argw
));
1588 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG3
, TMP_REG3
, reg_map
[arg
& 0xf]));
1590 compiler
->cache_arg
= arg
;
1591 compiler
->cache_argw
= argw
;
1593 GETPUT_ARG_DATA_TRANSFER(1, 0, reg
, TMP_REG3
, 0);
1594 return SLJIT_SUCCESS
;
1597 if ((arg
& 0xf) == tmp_r
) {
1598 compiler
->cache_arg
= SLJIT_IMM
;
1599 compiler
->cache_argw
= argw
;
1603 FAIL_IF(load_immediate(compiler
, tmp_r
, argw
));
1604 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, reg_map
[tmp_r
] | (max_delta
& 0xf00 ? SRC2_IMM
: 0)));
1605 return SLJIT_SUCCESS
;
1608 static int emit_op(struct sljit_compiler
*compiler
, int op
, int inp_flags
,
1609 int dst
, sljit_w dstw
,
1610 int src1
, sljit_w src1w
,
1611 int src2
, sljit_w src2w
)
1613 /* arg1 goes to TMP_REG1 or src reg
1614 arg2 goes to TMP_REG2, imm or src reg
1615 TMP_REG3 can be used for caching
1616 result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
1618 /* We prefers register and simple consts. */
1622 int sugg_src2_r
= TMP_REG2
;
1623 int flags
= GET_FLAGS(op
) ? SET_FLAGS
: 0;
1625 compiler
->cache_arg
= 0;
1626 compiler
->cache_argw
= 0;
1628 /* Destination check. */
1629 if (dst
>= SLJIT_TEMPORARY_REG1
&& dst
<= TMP_REG3
) {
1632 if (op
>= SLJIT_MOV
&& op
<= SLJIT_MOVU_SI
)
1633 sugg_src2_r
= dst_r
;
1635 else if (dst
== SLJIT_UNUSED
) {
1636 if (op
>= SLJIT_MOV
&& op
<= SLJIT_MOVU_SI
&& !(src2
& SLJIT_MEM
))
1637 return SLJIT_SUCCESS
;
1641 SLJIT_ASSERT(dst
& SLJIT_MEM
);
1642 if (getput_arg_fast(compiler
, inp_flags
| ARG_TEST
, TMP_REG2
, dst
, dstw
)) {
1653 if (src1
>= SLJIT_TEMPORARY_REG1
&& src1
<= TMP_REG3
)
1655 else if (src2
>= SLJIT_TEMPORARY_REG1
&& src2
<= TMP_REG3
) {
1656 flags
|= ARGS_SWAPPED
;
1661 else do { /* do { } while(0) is used because of breaks. */
1663 if ((inp_flags
& ALLOW_ANY_IMM
) && (src1
& SLJIT_IMM
)) {
1664 /* The second check will generate a hit. */
1665 src2_r
= get_immediate(src1w
);
1667 flags
|= ARGS_SWAPPED
;
1672 if (inp_flags
& ALLOW_INV_IMM
) {
1673 src2_r
= get_immediate(~src1w
);
1675 flags
|= ARGS_SWAPPED
| INV_IMM
;
1681 if (GET_OPCODE(op
) == SLJIT_ADD
) {
1682 src2_r
= get_immediate(-src1w
);
1684 /* Note: ARGS_SWAPPED is intentionally not applied! */
1687 op
= SLJIT_SUB
| GET_ALL_FLAGS(op
);
1693 if (getput_arg_fast(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
)) {
1694 FAIL_IF(compiler
->error
);
1701 if (src2
>= SLJIT_TEMPORARY_REG1
&& src2
<= TMP_REG3
) {
1703 flags
|= REG_SOURCE
;
1704 if (!(flags
& REG_DEST
) && op
>= SLJIT_MOV
&& op
<= SLJIT_MOVU_SI
)
1707 else do { /* do { } while(0) is used because of breaks. */
1708 if ((inp_flags
& ALLOW_ANY_IMM
) && (src2
& SLJIT_IMM
)) {
1709 src2_r
= get_immediate(src2w
);
1712 if (inp_flags
& ALLOW_INV_IMM
) {
1713 src2_r
= get_immediate(~src2w
);
1719 if (GET_OPCODE(op
) == SLJIT_ADD
) {
1720 src2_r
= get_immediate(-src2w
);
1722 op
= SLJIT_SUB
| GET_ALL_FLAGS(op
);
1723 flags
&= ~ARGS_SWAPPED
;
1727 if (GET_OPCODE(op
) == SLJIT_SUB
&& !(flags
& ARGS_SWAPPED
)) {
1728 src2_r
= get_immediate(-src2w
);
1730 op
= SLJIT_ADD
| GET_ALL_FLAGS(op
);
1731 flags
&= ~ARGS_SWAPPED
;
1738 if (getput_arg_fast(compiler
, inp_flags
| LOAD_DATA
, sugg_src2_r
, src2
, src2w
)) {
1739 FAIL_IF(compiler
->error
);
1740 src2_r
= sugg_src2_r
;
1745 /* src1_r, src2_r and dst_r can be zero (=unprocessed) or non-zero.
1746 If they are zero, they must not be registers. */
1747 if (src1_r
== 0 && src2_r
== 0 && dst_r
== 0) {
1748 if (!can_cache(src1
, src1w
, src2
, src2w
) && can_cache(src1
, src1w
, dst
, dstw
)) {
1749 SLJIT_ASSERT(!(flags
& ARGS_SWAPPED
));
1750 flags
|= ARGS_SWAPPED
;
1751 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src2
, src2w
, src1
, src1w
));
1752 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG2
, src1
, src1w
, dst
, dstw
));
1755 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, src2
, src2w
));
1756 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG2
, src2
, src2w
, dst
, dstw
));
1761 else if (src1_r
== 0 && src2_r
== 0) {
1762 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, src2
, src2w
));
1765 else if (src1_r
== 0 && dst_r
== 0) {
1766 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, dst
, dstw
));
1769 else if (src2_r
== 0 && dst_r
== 0) {
1770 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, sugg_src2_r
, src2
, src2w
, dst
, dstw
));
1771 src2_r
= sugg_src2_r
;
1778 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, 0, 0));
1783 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, sugg_src2_r
, src2
, src2w
, 0, 0));
1784 src2_r
= sugg_src2_r
;
1787 FAIL_IF(emit_single_op(compiler
, op
, flags
, dst_r
, src1_r
, src2_r
));
1789 if (flags
& (FAST_DEST
| SLOW_DEST
)) {
1790 if (flags
& FAST_DEST
)
1791 FAIL_IF(getput_arg_fast(compiler
, inp_flags
, dst_r
, dst
, dstw
));
1793 FAIL_IF(getput_arg(compiler
, inp_flags
, dst_r
, dst
, dstw
, 0, 0));
1795 return SLJIT_SUCCESS
;
1802 #if defined(__GNUC__)
1803 extern unsigned int __aeabi_uidivmod(unsigned numerator
, unsigned denominator
);
1804 extern unsigned int __aeabi_idivmod(unsigned numerator
, unsigned denominator
);
1806 #error "Software divmod functions are needed"
1813 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_op0(struct sljit_compiler
*compiler
, int op
)
1816 check_sljit_emit_op0(compiler
, op
);
1818 op
= GET_OPCODE(op
);
1820 case SLJIT_BREAKPOINT
:
1821 EMIT_INSTRUCTION(BKPT
);
1824 EMIT_INSTRUCTION(NOP
);
1828 #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
1829 return push_inst(compiler
, (op
== SLJIT_UMUL
? UMULL
: SMULL
)
1830 | (reg_map
[SLJIT_TEMPORARY_REG2
] << 16)
1831 | (reg_map
[SLJIT_TEMPORARY_REG1
] << 12)
1832 | (reg_map
[SLJIT_TEMPORARY_REG1
] << 8)
1833 | reg_map
[SLJIT_TEMPORARY_REG2
]);
1835 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG1
, SLJIT_UNUSED
, RM(SLJIT_TEMPORARY_REG2
)));
1836 return push_inst(compiler
, (op
== SLJIT_UMUL
? UMULL
: SMULL
)
1837 | (reg_map
[SLJIT_TEMPORARY_REG2
] << 16)
1838 | (reg_map
[SLJIT_TEMPORARY_REG1
] << 12)
1839 | (reg_map
[SLJIT_TEMPORARY_REG1
] << 8)
1840 | reg_map
[TMP_REG1
]);
1844 if (compiler
->temporaries
>= 3)
1845 EMIT_INSTRUCTION(0xe52d2008 /* str r2, [sp, #-8]! */);
1846 #if defined(__GNUC__)
1847 FAIL_IF(sljit_emit_ijump(compiler
, SLJIT_FAST_CALL
, SLJIT_IMM
,
1848 (op
== SLJIT_UDIV
? SLJIT_FUNC_OFFSET(__aeabi_uidivmod
) : SLJIT_FUNC_OFFSET(__aeabi_idivmod
))));
1850 #error "Software divmod functions are needed"
1852 if (compiler
->temporaries
>= 3)
1853 return push_inst(compiler
, 0xe49d2008 /* ldr r2, [sp], #8 */);
1854 return SLJIT_SUCCESS
;
1857 return SLJIT_SUCCESS
;
1860 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_op1(struct sljit_compiler
*compiler
, int op
,
1861 int dst
, sljit_w dstw
,
1862 int src
, sljit_w srcw
)
1865 check_sljit_emit_op1(compiler
, op
, dst
, dstw
, src
, srcw
);
1866 ADJUST_LOCAL_OFFSET(dst
, dstw
);
1867 ADJUST_LOCAL_OFFSET(src
, srcw
);
1869 switch (GET_OPCODE(op
)) {
1874 return emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1877 return emit_op(compiler
, SLJIT_MOV_UB
, ALLOW_ANY_IMM
| BYTE_DATA
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_ub
)srcw
: srcw
);
1880 return emit_op(compiler
, SLJIT_MOV_SB
, ALLOW_ANY_IMM
| SIGNED_DATA
| BYTE_DATA
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_b
)srcw
: srcw
);
1883 return emit_op(compiler
, SLJIT_MOV_UH
, ALLOW_ANY_IMM
| HALF_DATA
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_uh
)srcw
: srcw
);
1886 return emit_op(compiler
, SLJIT_MOV_SH
, ALLOW_ANY_IMM
| SIGNED_DATA
| HALF_DATA
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_h
)srcw
: srcw
);
1892 return emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
| WRITE_BACK
, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1895 return emit_op(compiler
, SLJIT_MOV_UB
, ALLOW_ANY_IMM
| BYTE_DATA
| WRITE_BACK
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_ub
)srcw
: srcw
);
1898 return emit_op(compiler
, SLJIT_MOV_SB
, ALLOW_ANY_IMM
| SIGNED_DATA
| BYTE_DATA
| WRITE_BACK
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_b
)srcw
: srcw
);
1901 return emit_op(compiler
, SLJIT_MOV_UH
, ALLOW_ANY_IMM
| HALF_DATA
| WRITE_BACK
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_uh
)srcw
: srcw
);
1904 return emit_op(compiler
, SLJIT_MOV_SH
, ALLOW_ANY_IMM
| SIGNED_DATA
| HALF_DATA
| WRITE_BACK
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_h
)srcw
: srcw
);
1907 return emit_op(compiler
, op
, ALLOW_ANY_IMM
, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1910 #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG)
1911 compiler
->skip_checks
= 1;
1913 return sljit_emit_op2(compiler
, SLJIT_SUB
| GET_ALL_FLAGS(op
), dst
, dstw
, SLJIT_IMM
, 0, src
, srcw
);
1916 return emit_op(compiler
, op
, 0, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1919 return SLJIT_SUCCESS
;
1922 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_op2(struct sljit_compiler
*compiler
, int op
,
1923 int dst
, sljit_w dstw
,
1924 int src1
, sljit_w src1w
,
1925 int src2
, sljit_w src2w
)
1928 check_sljit_emit_op2(compiler
, op
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1929 ADJUST_LOCAL_OFFSET(dst
, dstw
);
1930 ADJUST_LOCAL_OFFSET(src1
, src1w
);
1931 ADJUST_LOCAL_OFFSET(src2
, src2w
);
1933 switch (GET_OPCODE(op
)) {
1940 return emit_op(compiler
, op
, ALLOW_IMM
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1943 return emit_op(compiler
, op
, 0, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1946 return emit_op(compiler
, op
, ALLOW_ANY_IMM
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1951 if (src2
& SLJIT_IMM
) {
1952 compiler
->shift_imm
= src2w
& 0x1f;
1953 return emit_op(compiler
, op
, 0, dst
, dstw
, TMP_REG1
, 0, src1
, src1w
);
1956 compiler
->shift_imm
= 0x20;
1957 return emit_op(compiler
, op
, 0, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1961 return SLJIT_SUCCESS
;
1964 SLJIT_API_FUNC_ATTRIBUTE
int sljit_get_register_index(int reg
)
1966 check_sljit_get_register_index(reg
);
1967 return reg_map
[reg
];
1970 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_op_custom(struct sljit_compiler
*compiler
,
1971 void *instruction
, int size
)
1974 check_sljit_emit_op_custom(compiler
, instruction
, size
);
1975 SLJIT_ASSERT(size
== 4);
1977 return push_inst(compiler
, *(sljit_uw
*)instruction
);
1980 /* --------------------------------------------------------------------- */
1981 /* Floating point operators */
1982 /* --------------------------------------------------------------------- */
1984 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
1988 static int arm_fpu_type
= -1;
1990 static void init_compiler(void)
1992 if (arm_fpu_type
!= -1)
1995 /* TODO: Only the OS can help to determine the correct fpu type. */
1999 SLJIT_API_FUNC_ATTRIBUTE
int sljit_is_fpu_available(void)
2001 if (arm_fpu_type
== -1)
2003 return arm_fpu_type
;
2008 #define arm_fpu_type 1
2010 SLJIT_API_FUNC_ATTRIBUTE
int sljit_is_fpu_available(void)
2012 /* Always available. */
2018 #define EMIT_FPU_DATA_TRANSFER(add, load, base, freg, offs) \
2019 (VSTR | ((add) << 23) | ((load) << 20) | (reg_map[base] << 16) | (freg << 12) | (offs))
2020 #define EMIT_FPU_OPERATION(opcode, dst, src1, src2) \
2021 ((opcode) | ((dst) << 12) | (src1) | ((src2) << 16))
2023 static int emit_fpu_data_transfer(struct sljit_compiler
*compiler
, int fpu_reg
, int load
, int arg
, sljit_w argw
)
2025 SLJIT_ASSERT(arg
& SLJIT_MEM
);
2027 /* Fast loads and stores. */
2028 if ((arg
& 0xf) && !(arg
& 0xf0) && (argw
& 0x3) == 0) {
2029 if (argw
>= 0 && argw
<= 0x3ff) {
2030 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load
, arg
& 0xf, fpu_reg
, argw
>> 2));
2031 return SLJIT_SUCCESS
;
2033 if (argw
< 0 && argw
>= -0x3ff) {
2034 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load
, arg
& 0xf, fpu_reg
, (-argw
) >> 2));
2035 return SLJIT_SUCCESS
;
2037 if (argw
>= 0 && argw
<= 0x3ffff) {
2038 SLJIT_ASSERT(get_immediate(argw
& 0x3fc00));
2039 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG1
, arg
& 0xf, get_immediate(argw
& 0x3fc00)));
2041 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load
, TMP_REG1
, fpu_reg
, argw
>> 2));
2042 return SLJIT_SUCCESS
;
2044 if (argw
< 0 && argw
>= -0x3ffff) {
2046 SLJIT_ASSERT(get_immediate(argw
& 0x3fc00));
2047 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP
, 0, TMP_REG1
, arg
& 0xf, get_immediate(argw
& 0x3fc00)));
2049 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load
, TMP_REG1
, fpu_reg
, argw
>> 2));
2050 return SLJIT_SUCCESS
;
2055 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG1
, arg
& 0xf, RM((arg
>> 4) & 0xf) | ((argw
& 0x3) << 7)));
2056 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load
, TMP_REG1
, fpu_reg
, 0));
2057 return SLJIT_SUCCESS
;
2060 if (compiler
->cache_arg
== arg
&& ((argw
- compiler
->cache_argw
) & 0x3) == 0) {
2061 if (((sljit_uw
)argw
- (sljit_uw
)compiler
->cache_argw
) <= 0x3ff) {
2062 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load
, TMP_REG3
, fpu_reg
, (argw
- compiler
->cache_argw
) >> 2));
2063 return SLJIT_SUCCESS
;
2065 if (((sljit_uw
)compiler
->cache_argw
- (sljit_uw
)argw
) <= 0x3ff) {
2066 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load
, TMP_REG3
, fpu_reg
, (compiler
->cache_argw
- argw
) >> 2));
2067 return SLJIT_SUCCESS
;
2071 compiler
->cache_arg
= arg
;
2072 compiler
->cache_argw
= argw
;
2074 FAIL_IF(load_immediate(compiler
, TMP_REG1
, argw
));
2075 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG3
, arg
& 0xf, reg_map
[TMP_REG1
]));
2078 FAIL_IF(load_immediate(compiler
, TMP_REG3
, argw
));
2080 EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load
, TMP_REG3
, fpu_reg
, 0));
2081 return SLJIT_SUCCESS
;
2084 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_fop1(struct sljit_compiler
*compiler
, int op
,
2085 int dst
, sljit_w dstw
,
2086 int src
, sljit_w srcw
)
2091 check_sljit_emit_fop1(compiler
, op
, dst
, dstw
, src
, srcw
);
2093 compiler
->cache_arg
= 0;
2094 compiler
->cache_argw
= 0;
2096 if (GET_OPCODE(op
) == SLJIT_FCMP
) {
2097 if (dst
> SLJIT_FLOAT_REG4
) {
2098 FAIL_IF(emit_fpu_data_transfer(compiler
, TMP_FREG1
, 1, dst
, dstw
));
2101 if (src
> SLJIT_FLOAT_REG4
) {
2102 FAIL_IF(emit_fpu_data_transfer(compiler
, TMP_FREG2
, 1, src
, srcw
));
2105 EMIT_INSTRUCTION(VCMP_F64
| (dst
<< 12) | src
);
2106 EMIT_INSTRUCTION(VMRS
);
2107 return SLJIT_SUCCESS
;
2110 dst_fr
= (dst
> SLJIT_FLOAT_REG4
) ? TMP_FREG1
: dst
;
2112 if (src
> SLJIT_FLOAT_REG4
) {
2113 FAIL_IF(emit_fpu_data_transfer(compiler
, dst_fr
, 1, src
, srcw
));
2119 if (src
!= dst_fr
&& dst_fr
!= TMP_FREG1
)
2120 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMOV_F64
, dst_fr
, src
, 0));
2123 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VNEG_F64
, dst_fr
, src
, 0));
2126 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VABS_F64
, dst_fr
, src
, 0));
2130 if (dst_fr
== TMP_FREG1
) {
2131 if (op
== SLJIT_FMOV
)
2133 FAIL_IF(emit_fpu_data_transfer(compiler
, dst_fr
, 0, dst
, dstw
));
2136 return SLJIT_SUCCESS
;
2139 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_fop2(struct sljit_compiler
*compiler
, int op
,
2140 int dst
, sljit_w dstw
,
2141 int src1
, sljit_w src1w
,
2142 int src2
, sljit_w src2w
)
2147 check_sljit_emit_fop2(compiler
, op
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
2149 compiler
->cache_arg
= 0;
2150 compiler
->cache_argw
= 0;
2152 dst_fr
= (dst
> SLJIT_FLOAT_REG4
) ? TMP_FREG1
: dst
;
2154 if (src2
> SLJIT_FLOAT_REG4
) {
2155 FAIL_IF(emit_fpu_data_transfer(compiler
, TMP_FREG2
, 1, src2
, src2w
));
2159 if (src1
> SLJIT_FLOAT_REG4
) {
2160 FAIL_IF(emit_fpu_data_transfer(compiler
, TMP_FREG1
, 1, src1
, src1w
));
2166 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VADD_F64
, dst_fr
, src2
, src1
));
2170 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VSUB_F64
, dst_fr
, src2
, src1
));
2174 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMUL_F64
, dst_fr
, src2
, src1
));
2178 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VDIV_F64
, dst_fr
, src2
, src1
));
2182 if (dst_fr
== TMP_FREG1
)
2183 FAIL_IF(emit_fpu_data_transfer(compiler
, TMP_FREG1
, 0, dst
, dstw
));
2185 return SLJIT_SUCCESS
;
2188 /* --------------------------------------------------------------------- */
2189 /* Other instructions */
2190 /* --------------------------------------------------------------------- */
2192 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_fast_enter(struct sljit_compiler
*compiler
, int dst
, sljit_w dstw
)
2195 check_sljit_emit_fast_enter(compiler
, dst
, dstw
);
2196 ADJUST_LOCAL_OFFSET(dst
, dstw
);
2198 if (dst
>= SLJIT_TEMPORARY_REG1
&& dst
<= SLJIT_NO_REGISTERS
)
2199 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst
, SLJIT_UNUSED
, RM(TMP_REG3
)));
2200 else if (dst
& SLJIT_MEM
) {
2201 if (getput_arg_fast(compiler
, WORD_DATA
, TMP_REG3
, dst
, dstw
))
2202 return compiler
->error
;
2203 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG2
, SLJIT_UNUSED
, RM(TMP_REG3
)));
2204 compiler
->cache_arg
= 0;
2205 compiler
->cache_argw
= 0;
2206 return getput_arg(compiler
, WORD_DATA
, TMP_REG2
, dst
, dstw
, 0, 0);
2209 return SLJIT_SUCCESS
;
2212 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_fast_return(struct sljit_compiler
*compiler
, int src
, sljit_w srcw
)
2215 check_sljit_emit_fast_return(compiler
, src
, srcw
);
2216 ADJUST_LOCAL_OFFSET(src
, srcw
);
2218 if (src
>= SLJIT_TEMPORARY_REG1
&& src
<= SLJIT_NO_REGISTERS
)
2219 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG3
, SLJIT_UNUSED
, RM(src
)));
2220 else if (src
& SLJIT_MEM
) {
2221 if (getput_arg_fast(compiler
, WORD_DATA
| LOAD_DATA
, TMP_REG3
, src
, srcw
))
2222 FAIL_IF(compiler
->error
);
2224 compiler
->cache_arg
= 0;
2225 compiler
->cache_argw
= 0;
2226 FAIL_IF(getput_arg(compiler
, WORD_DATA
| LOAD_DATA
, TMP_REG2
, src
, srcw
, 0, 0));
2227 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG3
, SLJIT_UNUSED
, RM(TMP_REG2
)));
2230 else if (src
& SLJIT_IMM
)
2231 FAIL_IF(load_immediate(compiler
, TMP_REG3
, srcw
));
2232 return push_inst(compiler
, BLX
| RM(TMP_REG3
));
2235 /* --------------------------------------------------------------------- */
2236 /* Conditional instructions */
2237 /* --------------------------------------------------------------------- */
2239 static sljit_uw
get_cc(int type
)
2243 case SLJIT_C_MUL_NOT_OVERFLOW
:
2244 case SLJIT_C_FLOAT_EQUAL
:
2247 case SLJIT_C_NOT_EQUAL
:
2248 case SLJIT_C_MUL_OVERFLOW
:
2249 case SLJIT_C_FLOAT_NOT_EQUAL
:
2253 case SLJIT_C_FLOAT_LESS
:
2256 case SLJIT_C_GREATER_EQUAL
:
2257 case SLJIT_C_FLOAT_GREATER_EQUAL
:
2260 case SLJIT_C_GREATER
:
2261 case SLJIT_C_FLOAT_GREATER
:
2264 case SLJIT_C_LESS_EQUAL
:
2265 case SLJIT_C_FLOAT_LESS_EQUAL
:
2268 case SLJIT_C_SIG_LESS
:
2271 case SLJIT_C_SIG_GREATER_EQUAL
:
2274 case SLJIT_C_SIG_GREATER
:
2277 case SLJIT_C_SIG_LESS_EQUAL
:
2280 case SLJIT_C_OVERFLOW
:
2281 case SLJIT_C_FLOAT_UNORDERED
:
2284 case SLJIT_C_NOT_OVERFLOW
:
2285 case SLJIT_C_FLOAT_ORDERED
:
2288 default: /* SLJIT_JUMP */
2293 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_label
* sljit_emit_label(struct sljit_compiler
*compiler
)
2295 struct sljit_label
*label
;
2298 check_sljit_emit_label(compiler
);
2300 if (compiler
->last_label
&& compiler
->last_label
->size
== compiler
->size
)
2301 return compiler
->last_label
;
2303 label
= (struct sljit_label
*)ensure_abuf(compiler
, sizeof(struct sljit_label
));
2304 PTR_FAIL_IF(!label
);
2305 set_label(label
, compiler
);
2309 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_jump(struct sljit_compiler
*compiler
, int type
)
2311 struct sljit_jump
*jump
;
2314 check_sljit_emit_jump(compiler
, type
);
2316 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
2318 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
2321 /* In ARM, we don't need to touch the arguments. */
2322 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2323 if (type
>= SLJIT_FAST_CALL
)
2324 PTR_FAIL_IF(prepare_blx(compiler
));
2325 PTR_FAIL_IF(push_inst_with_unique_literal(compiler
, ((EMIT_DATA_TRANSFER(WORD_DATA
| LOAD_DATA
, 1, 0,
2326 type
<= SLJIT_JUMP
? TMP_PC
: TMP_REG1
, TMP_PC
, 0)) & ~COND_MASK
) | get_cc(type
), 0));
2328 if (jump
->flags
& SLJIT_REWRITABLE_JUMP
) {
2329 jump
->addr
= compiler
->size
;
2330 compiler
->patches
++;
2333 if (type
>= SLJIT_FAST_CALL
) {
2334 jump
->flags
|= IS_BL
;
2335 PTR_FAIL_IF(emit_blx(compiler
));
2338 if (!(jump
->flags
& SLJIT_REWRITABLE_JUMP
))
2339 jump
->addr
= compiler
->size
;
2341 if (type
>= SLJIT_FAST_CALL
)
2342 jump
->flags
|= IS_BL
;
2343 PTR_FAIL_IF(emit_imm(compiler
, TMP_REG1
, 0));
2344 PTR_FAIL_IF(push_inst(compiler
, (((type
<= SLJIT_JUMP
? BX
: BLX
) | RM(TMP_REG1
)) & ~COND_MASK
) | get_cc(type
)));
2345 jump
->addr
= compiler
->size
;
2350 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_ijump(struct sljit_compiler
*compiler
, int type
, int src
, sljit_w srcw
)
2352 struct sljit_jump
*jump
;
2355 check_sljit_emit_ijump(compiler
, type
, src
, srcw
);
2356 ADJUST_LOCAL_OFFSET(src
, srcw
);
2358 /* In ARM, we don't need to touch the arguments. */
2359 if (src
& SLJIT_IMM
) {
2360 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
2362 set_jump(jump
, compiler
, JUMP_ADDR
| ((type
>= SLJIT_FAST_CALL
) ? IS_BL
: 0));
2363 jump
->u
.target
= srcw
;
2365 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2366 if (type
>= SLJIT_FAST_CALL
)
2367 FAIL_IF(prepare_blx(compiler
));
2368 FAIL_IF(push_inst_with_unique_literal(compiler
, EMIT_DATA_TRANSFER(WORD_DATA
| LOAD_DATA
, 1, 0, type
<= SLJIT_JUMP
? TMP_PC
: TMP_REG1
, TMP_PC
, 0), 0));
2369 if (type
>= SLJIT_FAST_CALL
)
2370 FAIL_IF(emit_blx(compiler
));
2372 FAIL_IF(emit_imm(compiler
, TMP_REG1
, 0));
2373 FAIL_IF(push_inst(compiler
, (type
<= SLJIT_JUMP
? BX
: BLX
) | RM(TMP_REG1
)));
2375 jump
->addr
= compiler
->size
;
2378 if (src
>= SLJIT_TEMPORARY_REG1
&& src
<= SLJIT_NO_REGISTERS
)
2379 return push_inst(compiler
, (type
<= SLJIT_JUMP
? BX
: BLX
) | RM(src
));
2381 SLJIT_ASSERT(src
& SLJIT_MEM
);
2382 FAIL_IF(emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
, TMP_REG2
, 0, TMP_REG1
, 0, src
, srcw
));
2383 return push_inst(compiler
, (type
<= SLJIT_JUMP
? BX
: BLX
) | RM(TMP_REG2
));
2386 return SLJIT_SUCCESS
;
2389 SLJIT_API_FUNC_ATTRIBUTE
int sljit_emit_cond_value(struct sljit_compiler
*compiler
, int op
, int dst
, sljit_w dstw
, int type
)
2395 check_sljit_emit_cond_value(compiler
, op
, dst
, dstw
, type
);
2396 ADJUST_LOCAL_OFFSET(dst
, dstw
);
2398 if (dst
== SLJIT_UNUSED
)
2399 return SLJIT_SUCCESS
;
2402 if (GET_OPCODE(op
) == SLJIT_OR
) {
2403 if (dst
>= SLJIT_TEMPORARY_REG1
&& dst
<= SLJIT_NO_REGISTERS
) {
2404 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ORR_DP
, 0, dst
, dst
, SRC2_IMM
| 1) & ~COND_MASK
) | cc
);
2405 if (op
& SLJIT_SET_E
)
2406 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, SET_FLAGS
, TMP_REG1
, SLJIT_UNUSED
, RM(dst
)));
2407 return SLJIT_SUCCESS
;
2410 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG1
, SLJIT_UNUSED
, SRC2_IMM
| 0));
2411 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG1
, SLJIT_UNUSED
, SRC2_IMM
| 1) & ~COND_MASK
) | cc
);
2412 #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG)
2413 compiler
->skip_checks
= 1;
2415 return emit_op(compiler
, op
, ALLOW_IMM
, dst
, dstw
, TMP_REG1
, 0, dst
, dstw
);
2418 reg
= (dst
>= SLJIT_TEMPORARY_REG1
&& dst
<= SLJIT_NO_REGISTERS
) ? dst
: TMP_REG2
;
2420 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, reg
, SLJIT_UNUSED
, SRC2_IMM
| 0));
2421 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP
, 0, reg
, SLJIT_UNUSED
, SRC2_IMM
| 1) & ~COND_MASK
) | cc
);
2423 if (reg
== TMP_REG2
)
2424 return emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
, dst
, dstw
, TMP_REG1
, 0, TMP_REG2
, 0);
2425 return SLJIT_SUCCESS
;
2428 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_const
* sljit_emit_const(struct sljit_compiler
*compiler
, int dst
, sljit_w dstw
, sljit_w init_value
)
2430 struct sljit_const
*const_
;
2434 check_sljit_emit_const(compiler
, dst
, dstw
, init_value
);
2435 ADJUST_LOCAL_OFFSET(dst
, dstw
);
2437 const_
= (struct sljit_const
*)ensure_abuf(compiler
, sizeof(struct sljit_const
));
2438 PTR_FAIL_IF(!const_
);
2440 reg
= (dst
>= SLJIT_TEMPORARY_REG1
&& dst
<= SLJIT_NO_REGISTERS
) ? dst
: TMP_REG2
;
2442 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2443 PTR_FAIL_IF(push_inst_with_unique_literal(compiler
, EMIT_DATA_TRANSFER(WORD_DATA
| LOAD_DATA
, 1, 0, reg
, TMP_PC
, 0), init_value
));
2444 compiler
->patches
++;
2446 PTR_FAIL_IF(emit_imm(compiler
, reg
, init_value
));
2448 set_const(const_
, compiler
);
2450 if (reg
== TMP_REG2
&& dst
!= SLJIT_UNUSED
)
2451 if (emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
, dst
, dstw
, TMP_REG1
, 0, TMP_REG2
, 0))
2456 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_addr
)
2458 inline_set_jump_addr(addr
, new_addr
, 1);
2461 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_w new_constant
)
2463 inline_set_const(addr
, new_constant
, 1);