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)
45 #define TMP_FREG2 (SLJIT_FLOAT_REG6 + 1)
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) / (sljit_si)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_F32 0xeeb00ac0
103 #define VADD_F32 0xee300a00
104 #define VCMP_F32 0xeeb40a40
105 #define VDIV_F32 0xee800a00
106 #define VMOV_F32 0xeeb00a40
107 #define VMRS 0xeef1fa10
108 #define VMUL_F32 0xee200a00
109 #define VNEG_F32 0xeeb10a40
110 #define VSTR_F32 0xed000a00
111 #define VSUB_F32 0xee300a40
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 sljit_si
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 sljit_si
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 sljit_si
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 sljit_si
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 sljit_si
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 sljit_si
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 ((sljit_si
)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 sljit_si
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
= (sljit_si
)cpool_start_address
[cpool_current_index
];
323 curr_patch
= *first_patch
;
327 value
= (sljit_si
)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 sljit_si
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 sljit_si
emit_imm(struct sljit_compiler
*compiler
, sljit_si reg
, sljit_sw 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 sljit_si
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_sw
)jump
->u
.target
- (sljit_sw
)(code_ptr
+ 2));
400 SLJIT_ASSERT(jump
->flags
& JUMP_LABEL
);
401 diff
= ((sljit_sw
)(code
+ jump
->u
.label
->size
) - (sljit_sw
)(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_sw
)jump
->u
.target
- (sljit_sw
)code_ptr
);
426 SLJIT_ASSERT(jump
->flags
& JUMP_LABEL
);
427 diff
= ((sljit_sw
)(code
+ jump
->u
.label
->size
) - (sljit_sw
)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
, sljit_si 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 sljit_si bl
= (mov_pc
& 0x0000f000) != RD(TMP_PC
);
452 sljit_sw diff
= (sljit_sw
)(((sljit_sw
)new_addr
- (sljit_sw
)(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_imm(sljit_uw imm
);
503 static SLJIT_INLINE
void inline_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_si 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_imm(new_constant
);
513 *inst
= 0xe3a00000 | (ldr_literal
& 0xf000) | src2
;
515 SLJIT_CACHE_FLUSH(inst
, inst
+ 1);
520 src2
= get_imm(~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_sw
)jump
->u
.label
->addr
- (sljit_sw
)(buf_ptr
+ 2)) <= 0x01ffffff && ((sljit_sw
)jump
->u
.label
->addr
- (sljit_sw
)(buf_ptr
+ 2)) >= -0x02000000);
734 *buf_ptr
|= (((sljit_sw
)jump
->u
.label
->addr
- (sljit_sw
)(buf_ptr
+ 2)) >> 2) & 0x00ffffff;
737 SLJIT_ASSERT(((sljit_sw
)jump
->u
.target
- (sljit_sw
)(buf_ptr
+ 2)) <= 0x01ffffff && ((sljit_sw
)jump
->u
.target
- (sljit_sw
)(buf_ptr
+ 2)) >= -0x02000000);
738 *buf_ptr
|= (((sljit_sw
)jump
->u
.target
- (sljit_sw
)(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
<= (sljit_si
)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 sljit_si
emit_op(struct sljit_compiler
*compiler
, sljit_si op
, sljit_si inp_flags
,
823 sljit_si dst
, sljit_sw dstw
,
824 sljit_si src1
, sljit_sw src1w
,
825 sljit_si src2
, sljit_sw src2w
);
827 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_enter(struct sljit_compiler
*compiler
, sljit_si args
, sljit_si scratches
, sljit_si saveds
, sljit_si local_size
)
833 check_sljit_emit_enter(compiler
, args
, scratches
, saveds
, local_size
);
835 compiler
->scratches
= scratches
;
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);
858 EMIT_INSTRUCTION(push
);
860 /* Stack must be aligned to 8 bytes: */
861 size
= (1 + saveds
) * sizeof(sljit_uw
);
863 size
+= (scratches
- 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_SCRATCH_REG1
)));
874 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, SLJIT_SAVED_REG2
, SLJIT_UNUSED
, RM(SLJIT_SCRATCH_REG2
)));
876 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, SLJIT_SAVED_REG3
, SLJIT_UNUSED
, RM(SLJIT_SCRATCH_REG3
)));
878 return SLJIT_SUCCESS
;
881 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_context(struct sljit_compiler
*compiler
, sljit_si args
, sljit_si scratches
, sljit_si saveds
, sljit_si local_size
)
886 check_sljit_set_context(compiler
, args
, scratches
, saveds
, local_size
);
888 compiler
->scratches
= scratches
;
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
);
896 size
+= (scratches
- 3) * sizeof(sljit_uw
);
898 local_size
= (local_size
+ 7) & ~7;
900 compiler
->local_size
= local_size
;
903 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_return(struct sljit_compiler
*compiler
, sljit_si op
, sljit_si src
, sljit_sw 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
->scratches
>= 5)
920 if (compiler
->scratches
>= 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_sw 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 sljit_si
emit_single_op(struct sljit_compiler
*compiler
, sljit_si op
, sljit_si flags
,
1012 sljit_si dst
, sljit_si src1
, sljit_si 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_imm(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 sljit_si
generate_int(struct sljit_compiler
*compiler
, sljit_si reg
, sljit_uw imm
, sljit_si 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 sljit_si
load_immediate(struct sljit_compiler
*compiler
, sljit_si 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. */
1326 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, reg
, SLJIT_UNUSED
, tmp
));
1327 return SLJIT_SUCCESS
;
1330 tmp
= get_imm(~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 /* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */
1349 static sljit_si
emit_set_delta(struct sljit_compiler
*compiler
, sljit_si dst
, sljit_si reg
, sljit_sw value
)
1352 value
= get_imm(value
);
1354 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(ADD_DP
, 0, dst
, reg
, value
));
1357 value
= get_imm(-value
);
1359 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(SUB_DP
, 0, dst
, reg
, value
));
1361 return SLJIT_ERR_UNSUPPORTED
;
1364 /* Can perform an operation using at most 1 instruction. */
1365 static sljit_si
getput_arg_fast(struct sljit_compiler
*compiler
, sljit_si inp_flags
, sljit_si reg
, sljit_si arg
, sljit_sw argw
)
1369 if (arg
& SLJIT_IMM
) {
1370 imm
= get_imm(argw
);
1372 if (inp_flags
& ARG_TEST
)
1374 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, reg
, SLJIT_UNUSED
, imm
));
1377 imm
= get_imm(~argw
);
1379 if (inp_flags
& ARG_TEST
)
1381 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MVN_DP
, 0, reg
, SLJIT_UNUSED
, imm
));
1384 return (inp_flags
& ARG_TEST
) ? SLJIT_SUCCESS
: 0;
1387 SLJIT_ASSERT(arg
& SLJIT_MEM
);
1389 /* Fast loads/stores. */
1391 if (!(arg
& 0xf0)) {
1392 if (IS_TYPE1_TRANSFER(inp_flags
)) {
1393 if (argw
>= 0 && argw
<= 0xfff) {
1394 if (inp_flags
& ARG_TEST
)
1396 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, argw
));
1399 if (argw
< 0 && argw
>= -0xfff) {
1400 if (inp_flags
& ARG_TEST
)
1402 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 0, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, -argw
));
1407 if (argw
>= 0 && argw
<= 0xff) {
1408 if (inp_flags
& ARG_TEST
)
1410 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, TYPE2_TRANSFER_IMM(argw
)));
1413 if (argw
< 0 && argw
>= -0xff) {
1414 if (inp_flags
& ARG_TEST
)
1417 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 0, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, TYPE2_TRANSFER_IMM(argw
)));
1422 else if ((argw
& 0x3) == 0 || IS_TYPE1_TRANSFER(inp_flags
)) {
1423 if (inp_flags
& ARG_TEST
)
1425 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf,
1426 RM((arg
>> 4) & 0xf) | (IS_TYPE1_TRANSFER(inp_flags
) ? SRC2_IMM
: 0) | ((argw
& 0x3) << 7)));
1431 return (inp_flags
& ARG_TEST
) ? SLJIT_SUCCESS
: 0;
1434 /* See getput_arg below.
1435 Note: can_cache is called only for binary operators. Those
1436 operators always uses word arguments without write back. */
1437 static sljit_si
can_cache(sljit_si arg
, sljit_sw argw
, sljit_si next_arg
, sljit_sw next_argw
)
1439 /* Immediate caching is not supported as it would be an operation on constant arguments. */
1440 if (arg
& SLJIT_IMM
)
1443 /* Always a simple operation. */
1448 /* Immediate access. */
1449 if ((next_arg
& SLJIT_MEM
) && ((sljit_uw
)argw
- (sljit_uw
)next_argw
<= 0xfff || (sljit_uw
)next_argw
- (sljit_uw
)argw
<= 0xfff))
1454 if (argw
<= 0xfffff && argw
>= -0xfffff)
1457 if (argw
== next_argw
&& (next_arg
& SLJIT_MEM
))
1460 if (arg
== next_arg
&& ((sljit_uw
)argw
- (sljit_uw
)next_argw
<= 0xfff || (sljit_uw
)next_argw
- (sljit_uw
)argw
<= 0xfff))
1466 #define GETPUT_ARG_DATA_TRANSFER(add, wb, target, base, imm) \
1467 if (max_delta & 0xf00) \
1468 FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, imm))); \
1470 FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, TYPE2_TRANSFER_IMM(imm))));
1472 #define TEST_WRITE_BACK() \
1473 if (inp_flags & WRITE_BACK) { \
1474 tmp_r = arg & 0xf; \
1475 if (reg == tmp_r) { \
1476 /* This can only happen for stores */ \
1477 /* since ldr reg, [reg, ...]! has no meaning */ \
1478 SLJIT_ASSERT(!(inp_flags & LOAD_DATA)); \
1479 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(reg))); \
1484 /* Emit the necessary instructions. See can_cache above. */
1485 static sljit_si
getput_arg(struct sljit_compiler
*compiler
, sljit_si inp_flags
, sljit_si reg
, sljit_si arg
, sljit_sw argw
, sljit_si next_arg
, sljit_sw next_argw
)
1492 if (arg
& SLJIT_IMM
) {
1493 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1494 return load_immediate(compiler
, reg
, argw
);
1497 SLJIT_ASSERT(arg
& SLJIT_MEM
);
1499 tmp_r
= (inp_flags
& LOAD_DATA
) ? reg
: TMP_REG3
;
1500 max_delta
= IS_TYPE1_TRANSFER(inp_flags
) ? 0xfff : 0xff;
1502 if ((arg
& 0xf) == SLJIT_UNUSED
) {
1503 /* Write back is not used. */
1504 imm
= (sljit_uw
)(argw
- compiler
->cache_argw
);
1505 if ((compiler
->cache_arg
& SLJIT_IMM
) && (imm
<= (sljit_uw
)max_delta
|| imm
>= (sljit_uw
)-max_delta
)) {
1506 if (imm
<= (sljit_uw
)max_delta
) {
1508 argw
= argw
- compiler
->cache_argw
;
1512 argw
= compiler
->cache_argw
- argw
;
1515 GETPUT_ARG_DATA_TRANSFER(sign
, 0, reg
, TMP_REG3
, argw
);
1516 return SLJIT_SUCCESS
;
1519 /* With write back, we can create some sophisticated loads, but
1520 it is hard to decide whether we should convert downward (0s) or upward (1s). */
1521 imm
= (sljit_uw
)(argw
- next_argw
);
1522 if ((next_arg
& SLJIT_MEM
) && (imm
<= (sljit_uw
)max_delta
|| imm
>= (sljit_uw
)-max_delta
)) {
1523 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1525 compiler
->cache_arg
= SLJIT_IMM
;
1526 compiler
->cache_argw
= argw
;
1530 FAIL_IF(load_immediate(compiler
, tmp_r
, argw
));
1531 GETPUT_ARG_DATA_TRANSFER(1, 0, reg
, tmp_r
, 0);
1532 return SLJIT_SUCCESS
;
1536 SLJIT_ASSERT((argw
& 0x3) && !(max_delta
& 0xf00));
1537 if (inp_flags
& WRITE_BACK
)
1539 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, tmp_r
, arg
& 0xf, RM((arg
>> 4) & 0xf) | ((argw
& 0x3) << 7)));
1540 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, 0, reg
, tmp_r
, TYPE2_TRANSFER_IMM(0)));
1541 return SLJIT_SUCCESS
;
1544 imm
= (sljit_uw
)(argw
- compiler
->cache_argw
);
1545 if (compiler
->cache_arg
== arg
&& imm
<= (sljit_uw
)max_delta
) {
1546 SLJIT_ASSERT(!(inp_flags
& WRITE_BACK
));
1547 GETPUT_ARG_DATA_TRANSFER(1, 0, reg
, TMP_REG3
, imm
);
1548 return SLJIT_SUCCESS
;
1550 if (compiler
->cache_arg
== arg
&& imm
>= (sljit_uw
)-max_delta
) {
1551 SLJIT_ASSERT(!(inp_flags
& WRITE_BACK
));
1552 imm
= (sljit_uw
)-(sljit_sw
)imm
;
1553 GETPUT_ARG_DATA_TRANSFER(0, 0, reg
, TMP_REG3
, imm
);
1554 return SLJIT_SUCCESS
;
1557 imm
= get_imm(argw
& ~max_delta
);
1560 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, tmp_r
, arg
& 0xf, imm
));
1561 GETPUT_ARG_DATA_TRANSFER(1, inp_flags
& WRITE_BACK
, reg
, tmp_r
, argw
& max_delta
);
1562 return SLJIT_SUCCESS
;
1565 imm
= get_imm(-argw
& ~max_delta
);
1569 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP
, 0, tmp_r
, arg
& 0xf, imm
));
1570 GETPUT_ARG_DATA_TRANSFER(0, inp_flags
& WRITE_BACK
, reg
, tmp_r
, argw
& max_delta
);
1571 return SLJIT_SUCCESS
;
1574 if ((compiler
->cache_arg
& SLJIT_IMM
) && compiler
->cache_argw
== argw
) {
1576 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, RM(TMP_REG3
) | (max_delta
& 0xf00 ? SRC2_IMM
: 0)));
1577 return SLJIT_SUCCESS
;
1580 if (argw
== next_argw
&& (next_arg
& SLJIT_MEM
)) {
1581 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1582 FAIL_IF(load_immediate(compiler
, TMP_REG3
, argw
));
1584 compiler
->cache_arg
= SLJIT_IMM
;
1585 compiler
->cache_argw
= argw
;
1588 EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags
, 1, inp_flags
& WRITE_BACK
, reg
, arg
& 0xf, RM(TMP_REG3
) | (max_delta
& 0xf00 ? SRC2_IMM
: 0)));
1589 return SLJIT_SUCCESS
;
1592 imm
= (sljit_uw
)(argw
- next_argw
);
1593 if (arg
== next_arg
&& !(inp_flags
& WRITE_BACK
) && (imm
<= (sljit_uw
)max_delta
|| imm
>= (sljit_uw
)-max_delta
)) {
1594 SLJIT_ASSERT(inp_flags
& LOAD_DATA
);
1595 FAIL_IF(load_immediate(compiler
, TMP_REG3
, argw
));
1596 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG3
, TMP_REG3
, reg_map
[arg
& 0xf]));
1598 compiler
->cache_arg
= arg
;
1599 compiler
->cache_argw
= argw
;
1601 GETPUT_ARG_DATA_TRANSFER(1, 0, reg
, TMP_REG3
, 0);
1602 return SLJIT_SUCCESS
;
1605 if ((arg
& 0xf) == tmp_r
) {
1606 compiler
->cache_arg
= SLJIT_IMM
;
1607 compiler
->cache_argw
= argw
;
1611 FAIL_IF(load_immediate(compiler
, tmp_r
, argw
));
1612 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)));
1613 return SLJIT_SUCCESS
;
1616 static SLJIT_INLINE sljit_si
emit_op_mem(struct sljit_compiler
*compiler
, sljit_si flags
, sljit_si reg
, sljit_si arg
, sljit_sw argw
)
1618 if (getput_arg_fast(compiler
, flags
, reg
, arg
, argw
))
1619 return compiler
->error
;
1620 compiler
->cache_arg
= 0;
1621 compiler
->cache_argw
= 0;
1622 return getput_arg(compiler
, flags
, reg
, arg
, argw
, 0, 0);
1625 static SLJIT_INLINE sljit_si
emit_op_mem2(struct sljit_compiler
*compiler
, sljit_si flags
, sljit_si reg
, sljit_si arg1
, sljit_sw arg1w
, sljit_si arg2
, sljit_sw arg2w
)
1627 if (getput_arg_fast(compiler
, flags
, reg
, arg1
, arg1w
))
1628 return compiler
->error
;
1629 return getput_arg(compiler
, flags
, reg
, arg1
, arg1w
, arg2
, arg2w
);
1632 static sljit_si
emit_op(struct sljit_compiler
*compiler
, sljit_si op
, sljit_si inp_flags
,
1633 sljit_si dst
, sljit_sw dstw
,
1634 sljit_si src1
, sljit_sw src1w
,
1635 sljit_si src2
, sljit_sw src2w
)
1637 /* arg1 goes to TMP_REG1 or src reg
1638 arg2 goes to TMP_REG2, imm or src reg
1639 TMP_REG3 can be used for caching
1640 result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
1642 /* We prefers register and simple consts. */
1645 sljit_si src2_r
= 0;
1646 sljit_si sugg_src2_r
= TMP_REG2
;
1647 sljit_si flags
= GET_FLAGS(op
) ? SET_FLAGS
: 0;
1649 compiler
->cache_arg
= 0;
1650 compiler
->cache_argw
= 0;
1652 /* Destination check. */
1653 if (SLJIT_UNLIKELY(dst
== SLJIT_UNUSED
)) {
1654 if (op
>= SLJIT_MOV
&& op
<= SLJIT_MOVU_SI
&& !(src2
& SLJIT_MEM
))
1655 return SLJIT_SUCCESS
;
1658 else if (dst
<= TMP_REG3
) {
1661 if (op
>= SLJIT_MOV
&& op
<= SLJIT_MOVU_SI
)
1662 sugg_src2_r
= dst_r
;
1665 SLJIT_ASSERT(dst
& SLJIT_MEM
);
1666 if (getput_arg_fast(compiler
, inp_flags
| ARG_TEST
, TMP_REG2
, dst
, dstw
)) {
1677 if (src1
<= TMP_REG3
)
1679 else if (src2
<= TMP_REG3
) {
1680 flags
|= ARGS_SWAPPED
;
1685 else do { /* do { } while(0) is used because of breaks. */
1687 if ((inp_flags
& ALLOW_ANY_IMM
) && (src1
& SLJIT_IMM
)) {
1688 /* The second check will generate a hit. */
1689 src2_r
= get_imm(src1w
);
1691 flags
|= ARGS_SWAPPED
;
1696 if (inp_flags
& ALLOW_INV_IMM
) {
1697 src2_r
= get_imm(~src1w
);
1699 flags
|= ARGS_SWAPPED
| INV_IMM
;
1705 if (GET_OPCODE(op
) == SLJIT_ADD
) {
1706 src2_r
= get_imm(-src1w
);
1708 /* Note: ARGS_SWAPPED is intentionally not applied! */
1711 op
= SLJIT_SUB
| GET_ALL_FLAGS(op
);
1717 if (getput_arg_fast(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
)) {
1718 FAIL_IF(compiler
->error
);
1725 if (src2
<= TMP_REG3
) {
1727 flags
|= REG_SOURCE
;
1728 if (!(flags
& REG_DEST
) && op
>= SLJIT_MOV
&& op
<= SLJIT_MOVU_SI
)
1731 else do { /* do { } while(0) is used because of breaks. */
1732 if ((inp_flags
& ALLOW_ANY_IMM
) && (src2
& SLJIT_IMM
)) {
1733 src2_r
= get_imm(src2w
);
1736 if (inp_flags
& ALLOW_INV_IMM
) {
1737 src2_r
= get_imm(~src2w
);
1743 if (GET_OPCODE(op
) == SLJIT_ADD
) {
1744 src2_r
= get_imm(-src2w
);
1746 op
= SLJIT_SUB
| GET_ALL_FLAGS(op
);
1747 flags
&= ~ARGS_SWAPPED
;
1751 if (GET_OPCODE(op
) == SLJIT_SUB
&& !(flags
& ARGS_SWAPPED
)) {
1752 src2_r
= get_imm(-src2w
);
1754 op
= SLJIT_ADD
| GET_ALL_FLAGS(op
);
1755 flags
&= ~ARGS_SWAPPED
;
1762 if (getput_arg_fast(compiler
, inp_flags
| LOAD_DATA
, sugg_src2_r
, src2
, src2w
)) {
1763 FAIL_IF(compiler
->error
);
1764 src2_r
= sugg_src2_r
;
1769 /* src1_r, src2_r and dst_r can be zero (=unprocessed) or non-zero.
1770 If they are zero, they must not be registers. */
1771 if (src1_r
== 0 && src2_r
== 0 && dst_r
== 0) {
1772 if (!can_cache(src1
, src1w
, src2
, src2w
) && can_cache(src1
, src1w
, dst
, dstw
)) {
1773 SLJIT_ASSERT(!(flags
& ARGS_SWAPPED
));
1774 flags
|= ARGS_SWAPPED
;
1775 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src2
, src2w
, src1
, src1w
));
1776 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG2
, src1
, src1w
, dst
, dstw
));
1779 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, src2
, src2w
));
1780 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG2
, src2
, src2w
, dst
, dstw
));
1785 else if (src1_r
== 0 && src2_r
== 0) {
1786 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, src2
, src2w
));
1789 else if (src1_r
== 0 && dst_r
== 0) {
1790 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, dst
, dstw
));
1793 else if (src2_r
== 0 && dst_r
== 0) {
1794 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, sugg_src2_r
, src2
, src2w
, dst
, dstw
));
1795 src2_r
= sugg_src2_r
;
1802 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, TMP_REG1
, src1
, src1w
, 0, 0));
1807 FAIL_IF(getput_arg(compiler
, inp_flags
| LOAD_DATA
, sugg_src2_r
, src2
, src2w
, 0, 0));
1808 src2_r
= sugg_src2_r
;
1811 FAIL_IF(emit_single_op(compiler
, op
, flags
, dst_r
, src1_r
, src2_r
));
1813 if (flags
& (FAST_DEST
| SLOW_DEST
)) {
1814 if (flags
& FAST_DEST
)
1815 FAIL_IF(getput_arg_fast(compiler
, inp_flags
, dst_r
, dst
, dstw
));
1817 FAIL_IF(getput_arg(compiler
, inp_flags
, dst_r
, dst
, dstw
, 0, 0));
1819 return SLJIT_SUCCESS
;
1826 #if defined(__GNUC__)
1827 extern unsigned int __aeabi_uidivmod(unsigned int numerator
, unsigned int denominator
);
1828 extern int __aeabi_idivmod(int numerator
, int denominator
);
1830 #error "Software divmod functions are needed"
1837 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_op0(struct sljit_compiler
*compiler
, sljit_si op
)
1840 check_sljit_emit_op0(compiler
, op
);
1842 op
= GET_OPCODE(op
);
1844 case SLJIT_BREAKPOINT
:
1845 EMIT_INSTRUCTION(BKPT
);
1848 EMIT_INSTRUCTION(NOP
);
1852 #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
1853 return push_inst(compiler
, (op
== SLJIT_UMUL
? UMULL
: SMULL
)
1854 | (reg_map
[SLJIT_SCRATCH_REG2
] << 16)
1855 | (reg_map
[SLJIT_SCRATCH_REG1
] << 12)
1856 | (reg_map
[SLJIT_SCRATCH_REG1
] << 8)
1857 | reg_map
[SLJIT_SCRATCH_REG2
]);
1859 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG1
, SLJIT_UNUSED
, RM(SLJIT_SCRATCH_REG2
)));
1860 return push_inst(compiler
, (op
== SLJIT_UMUL
? UMULL
: SMULL
)
1861 | (reg_map
[SLJIT_SCRATCH_REG2
] << 16)
1862 | (reg_map
[SLJIT_SCRATCH_REG1
] << 12)
1863 | (reg_map
[SLJIT_SCRATCH_REG1
] << 8)
1864 | reg_map
[TMP_REG1
]);
1868 if (compiler
->scratches
>= 3)
1869 EMIT_INSTRUCTION(0xe52d2008 /* str r2, [sp, #-8]! */);
1870 #if defined(__GNUC__)
1871 FAIL_IF(sljit_emit_ijump(compiler
, SLJIT_FAST_CALL
, SLJIT_IMM
,
1872 (op
== SLJIT_UDIV
? SLJIT_FUNC_OFFSET(__aeabi_uidivmod
) : SLJIT_FUNC_OFFSET(__aeabi_idivmod
))));
1874 #error "Software divmod functions are needed"
1876 if (compiler
->scratches
>= 3)
1877 return push_inst(compiler
, 0xe49d2008 /* ldr r2, [sp], #8 */);
1878 return SLJIT_SUCCESS
;
1881 return SLJIT_SUCCESS
;
1884 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_op1(struct sljit_compiler
*compiler
, sljit_si op
,
1885 sljit_si dst
, sljit_sw dstw
,
1886 sljit_si src
, sljit_sw srcw
)
1889 check_sljit_emit_op1(compiler
, op
, dst
, dstw
, src
, srcw
);
1890 ADJUST_LOCAL_OFFSET(dst
, dstw
);
1891 ADJUST_LOCAL_OFFSET(src
, srcw
);
1893 switch (GET_OPCODE(op
)) {
1898 return emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1901 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
);
1904 return emit_op(compiler
, SLJIT_MOV_SB
, ALLOW_ANY_IMM
| SIGNED_DATA
| BYTE_DATA
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_sb
)srcw
: srcw
);
1907 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
);
1910 return emit_op(compiler
, SLJIT_MOV_SH
, ALLOW_ANY_IMM
| SIGNED_DATA
| HALF_DATA
, dst
, dstw
, TMP_REG1
, 0, src
, (src
& SLJIT_IMM
) ? (sljit_sh
)srcw
: srcw
);
1916 return emit_op(compiler
, SLJIT_MOV
, ALLOW_ANY_IMM
| WRITE_BACK
, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1919 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
);
1922 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_sb
)srcw
: srcw
);
1925 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
);
1928 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_sh
)srcw
: srcw
);
1931 return emit_op(compiler
, op
, ALLOW_ANY_IMM
, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1934 #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG)
1935 compiler
->skip_checks
= 1;
1937 return sljit_emit_op2(compiler
, SLJIT_SUB
| GET_ALL_FLAGS(op
), dst
, dstw
, SLJIT_IMM
, 0, src
, srcw
);
1940 return emit_op(compiler
, op
, 0, dst
, dstw
, TMP_REG1
, 0, src
, srcw
);
1943 return SLJIT_SUCCESS
;
1946 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_op2(struct sljit_compiler
*compiler
, sljit_si op
,
1947 sljit_si dst
, sljit_sw dstw
,
1948 sljit_si src1
, sljit_sw src1w
,
1949 sljit_si src2
, sljit_sw src2w
)
1952 check_sljit_emit_op2(compiler
, op
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1953 ADJUST_LOCAL_OFFSET(dst
, dstw
);
1954 ADJUST_LOCAL_OFFSET(src1
, src1w
);
1955 ADJUST_LOCAL_OFFSET(src2
, src2w
);
1957 switch (GET_OPCODE(op
)) {
1964 return emit_op(compiler
, op
, ALLOW_IMM
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1967 return emit_op(compiler
, op
, 0, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1970 return emit_op(compiler
, op
, ALLOW_ANY_IMM
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1975 if (src2
& SLJIT_IMM
) {
1976 compiler
->shift_imm
= src2w
& 0x1f;
1977 return emit_op(compiler
, op
, 0, dst
, dstw
, TMP_REG1
, 0, src1
, src1w
);
1980 compiler
->shift_imm
= 0x20;
1981 return emit_op(compiler
, op
, 0, dst
, dstw
, src1
, src1w
, src2
, src2w
);
1985 return SLJIT_SUCCESS
;
1988 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_get_register_index(sljit_si reg
)
1990 check_sljit_get_register_index(reg
);
1991 return reg_map
[reg
];
1994 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_op_custom(struct sljit_compiler
*compiler
,
1995 void *instruction
, sljit_si size
)
1998 check_sljit_emit_op_custom(compiler
, instruction
, size
);
1999 SLJIT_ASSERT(size
== 4);
2001 return push_inst(compiler
, *(sljit_uw
*)instruction
);
2004 /* --------------------------------------------------------------------- */
2005 /* Floating point operators */
2006 /* --------------------------------------------------------------------- */
2008 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2012 static sljit_si arm_fpu_type
= -1;
2014 static void init_compiler(void)
2016 if (arm_fpu_type
!= -1)
2019 /* TODO: Only the OS can help to determine the correct fpu type. */
2023 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_is_fpu_available(void)
2025 if (arm_fpu_type
== -1)
2027 return arm_fpu_type
;
2032 #define arm_fpu_type 1
2034 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_is_fpu_available(void)
2036 /* Always available. */
2042 #define FPU_LOAD (1 << 20)
2043 #define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \
2044 ((inst) | ((add) << 23) | (reg_map[base] << 16) | (freg << 12) | (offs))
2045 #define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \
2046 ((opcode) | (mode) | ((dst) << 12) | (src1) | ((src2) << 16))
2048 static sljit_si
emit_fop_mem(struct sljit_compiler
*compiler
, sljit_si flags
, sljit_si reg
, sljit_si arg
, sljit_sw argw
)
2052 sljit_sw inst
= VSTR_F32
| (flags
& (SLJIT_SINGLE_OP
| FPU_LOAD
));
2053 SLJIT_ASSERT(arg
& SLJIT_MEM
);
2055 if (SLJIT_UNLIKELY(arg
& 0xf0)) {
2056 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG1
, arg
& 0xf, RM((arg
>> 4) & 0xf) | ((argw
& 0x3) << 7)));
2057 arg
= SLJIT_MEM
| TMP_REG1
;
2061 /* Fast loads and stores. */
2063 if (!(argw
& ~0x3fc))
2064 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 1, arg
& 0xf, reg
, argw
>> 2));
2065 if (!(-argw
& ~0x3fc))
2066 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 0, arg
& 0xf, reg
, (-argw
) >> 2));
2069 if (compiler
->cache_arg
== arg
) {
2070 tmp
= argw
- compiler
->cache_argw
;
2071 if (!(tmp
& ~0x3fc))
2072 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 1, TMP_REG3
, reg
, tmp
>> 2));
2073 if (!(-tmp
& ~0x3fc))
2074 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 0, TMP_REG3
, reg
, -tmp
>> 2));
2075 if (emit_set_delta(compiler
, TMP_REG3
, TMP_REG3
, tmp
) != SLJIT_ERR_UNSUPPORTED
) {
2076 FAIL_IF(compiler
->error
);
2077 compiler
->cache_argw
= argw
;
2078 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 1, TMP_REG3
, reg
, 0));
2083 if (emit_set_delta(compiler
, TMP_REG1
, arg
& 0xf, argw
) != SLJIT_ERR_UNSUPPORTED
) {
2084 FAIL_IF(compiler
->error
);
2085 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 1, TMP_REG1
, reg
, 0));
2087 imm
= get_imm(argw
& ~0x3fc);
2089 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG1
, arg
& 0xf, imm
));
2090 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 1, TMP_REG1
, reg
, (argw
& 0x3fc) >> 2));
2092 imm
= get_imm(-argw
& ~0x3fc);
2095 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP
, 0, TMP_REG1
, arg
& 0xf, imm
));
2096 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 0, TMP_REG1
, reg
, (argw
& 0x3fc) >> 2));
2100 compiler
->cache_arg
= arg
;
2101 compiler
->cache_argw
= argw
;
2103 FAIL_IF(load_immediate(compiler
, TMP_REG1
, argw
));
2104 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP
, 0, TMP_REG3
, arg
& 0xf, reg_map
[TMP_REG1
]));
2107 FAIL_IF(load_immediate(compiler
, TMP_REG3
, argw
));
2109 return push_inst(compiler
, EMIT_FPU_DATA_TRANSFER(inst
, 1, TMP_REG3
, reg
, 0));
2112 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_fop1(struct sljit_compiler
*compiler
, sljit_si op
,
2113 sljit_si dst
, sljit_sw dstw
,
2114 sljit_si src
, sljit_sw srcw
)
2119 check_sljit_emit_fop1(compiler
, op
, dst
, dstw
, src
, srcw
);
2120 SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP
== 0x100), float_transfer_bit_error
);
2122 compiler
->cache_arg
= 0;
2123 compiler
->cache_argw
= 0;
2124 op
^= SLJIT_SINGLE_OP
;
2126 if (GET_OPCODE(op
) == SLJIT_CMPD
) {
2127 if (dst
> SLJIT_FLOAT_REG6
) {
2128 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
) | FPU_LOAD
, TMP_FREG1
, dst
, dstw
));
2131 if (src
> SLJIT_FLOAT_REG6
) {
2132 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
) | FPU_LOAD
, TMP_FREG2
, src
, srcw
));
2135 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VCMP_F32
, op
& SLJIT_SINGLE_OP
, dst
, src
, 0));
2136 EMIT_INSTRUCTION(VMRS
);
2137 return SLJIT_SUCCESS
;
2140 dst_fr
= (dst
> SLJIT_FLOAT_REG6
) ? TMP_FREG1
: dst
;
2142 if (src
> SLJIT_FLOAT_REG6
) {
2143 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
) | FPU_LOAD
, dst_fr
, src
, srcw
));
2147 switch (GET_OPCODE(op
)) {
2149 if (src
!= dst_fr
&& dst_fr
!= TMP_FREG1
)
2150 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMOV_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src
, 0));
2153 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VNEG_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src
, 0));
2156 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VABS_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src
, 0));
2160 if (dst_fr
== TMP_FREG1
) {
2161 if (GET_OPCODE(op
) == SLJIT_MOVD
)
2163 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
), dst_fr
, dst
, dstw
));
2166 return SLJIT_SUCCESS
;
2169 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_fop2(struct sljit_compiler
*compiler
, sljit_si op
,
2170 sljit_si dst
, sljit_sw dstw
,
2171 sljit_si src1
, sljit_sw src1w
,
2172 sljit_si src2
, sljit_sw src2w
)
2177 check_sljit_emit_fop2(compiler
, op
, dst
, dstw
, src1
, src1w
, src2
, src2w
);
2179 compiler
->cache_arg
= 0;
2180 compiler
->cache_argw
= 0;
2181 op
^= SLJIT_SINGLE_OP
;
2183 dst_fr
= (dst
> SLJIT_FLOAT_REG6
) ? TMP_FREG1
: dst
;
2185 if (src2
> SLJIT_FLOAT_REG6
) {
2186 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
) | FPU_LOAD
, TMP_FREG2
, src2
, src2w
));
2190 if (src1
> SLJIT_FLOAT_REG6
) {
2191 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
) | FPU_LOAD
, TMP_FREG1
, src1
, src1w
));
2195 switch (GET_OPCODE(op
)) {
2197 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VADD_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src2
, src1
));
2201 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VSUB_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src2
, src1
));
2205 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMUL_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src2
, src1
));
2209 EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VDIV_F32
, op
& SLJIT_SINGLE_OP
, dst_fr
, src2
, src1
));
2213 if (dst_fr
== TMP_FREG1
)
2214 FAIL_IF(emit_fop_mem(compiler
, (op
& SLJIT_SINGLE_OP
), TMP_FREG1
, dst
, dstw
));
2216 return SLJIT_SUCCESS
;
2220 #undef EMIT_FPU_DATA_TRANSFER
2221 #undef EMIT_FPU_OPERATION
2223 /* --------------------------------------------------------------------- */
2224 /* Other instructions */
2225 /* --------------------------------------------------------------------- */
2227 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_fast_enter(struct sljit_compiler
*compiler
, sljit_si dst
, sljit_sw dstw
)
2230 check_sljit_emit_fast_enter(compiler
, dst
, dstw
);
2231 ADJUST_LOCAL_OFFSET(dst
, dstw
);
2233 /* For UNUSED dst. Uncommon, but possible. */
2234 if (dst
== SLJIT_UNUSED
)
2235 return SLJIT_SUCCESS
;
2237 if (dst
<= TMP_REG3
)
2238 return push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst
, SLJIT_UNUSED
, RM(TMP_REG3
)));
2241 if (getput_arg_fast(compiler
, WORD_DATA
, TMP_REG3
, dst
, dstw
))
2242 return compiler
->error
;
2243 /* TMP_REG3 is used for caching. */
2244 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG2
, SLJIT_UNUSED
, RM(TMP_REG3
)));
2245 compiler
->cache_arg
= 0;
2246 compiler
->cache_argw
= 0;
2247 return getput_arg(compiler
, WORD_DATA
, TMP_REG2
, dst
, dstw
, 0, 0);
2250 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_fast_return(struct sljit_compiler
*compiler
, sljit_si src
, sljit_sw srcw
)
2253 check_sljit_emit_fast_return(compiler
, src
, srcw
);
2254 ADJUST_LOCAL_OFFSET(src
, srcw
);
2256 if (src
<= TMP_REG3
)
2257 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG3
, SLJIT_UNUSED
, RM(src
)));
2258 else if (src
& SLJIT_MEM
) {
2259 if (getput_arg_fast(compiler
, WORD_DATA
| LOAD_DATA
, TMP_REG3
, src
, srcw
))
2260 FAIL_IF(compiler
->error
);
2262 compiler
->cache_arg
= 0;
2263 compiler
->cache_argw
= 0;
2264 FAIL_IF(getput_arg(compiler
, WORD_DATA
| LOAD_DATA
, TMP_REG2
, src
, srcw
, 0, 0));
2265 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, TMP_REG3
, SLJIT_UNUSED
, RM(TMP_REG2
)));
2268 else if (src
& SLJIT_IMM
)
2269 FAIL_IF(load_immediate(compiler
, TMP_REG3
, srcw
));
2270 return push_inst(compiler
, BLX
| RM(TMP_REG3
));
2273 /* --------------------------------------------------------------------- */
2274 /* Conditional instructions */
2275 /* --------------------------------------------------------------------- */
2277 static sljit_uw
get_cc(sljit_si type
)
2281 case SLJIT_C_MUL_NOT_OVERFLOW
:
2282 case SLJIT_C_FLOAT_EQUAL
:
2285 case SLJIT_C_NOT_EQUAL
:
2286 case SLJIT_C_MUL_OVERFLOW
:
2287 case SLJIT_C_FLOAT_NOT_EQUAL
:
2291 case SLJIT_C_FLOAT_LESS
:
2294 case SLJIT_C_GREATER_EQUAL
:
2295 case SLJIT_C_FLOAT_GREATER_EQUAL
:
2298 case SLJIT_C_GREATER
:
2299 case SLJIT_C_FLOAT_GREATER
:
2302 case SLJIT_C_LESS_EQUAL
:
2303 case SLJIT_C_FLOAT_LESS_EQUAL
:
2306 case SLJIT_C_SIG_LESS
:
2309 case SLJIT_C_SIG_GREATER_EQUAL
:
2312 case SLJIT_C_SIG_GREATER
:
2315 case SLJIT_C_SIG_LESS_EQUAL
:
2318 case SLJIT_C_OVERFLOW
:
2319 case SLJIT_C_FLOAT_UNORDERED
:
2322 case SLJIT_C_NOT_OVERFLOW
:
2323 case SLJIT_C_FLOAT_ORDERED
:
2326 default: /* SLJIT_JUMP */
2331 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_label
* sljit_emit_label(struct sljit_compiler
*compiler
)
2333 struct sljit_label
*label
;
2336 check_sljit_emit_label(compiler
);
2338 if (compiler
->last_label
&& compiler
->last_label
->size
== compiler
->size
)
2339 return compiler
->last_label
;
2341 label
= (struct sljit_label
*)ensure_abuf(compiler
, sizeof(struct sljit_label
));
2342 PTR_FAIL_IF(!label
);
2343 set_label(label
, compiler
);
2347 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_jump(struct sljit_compiler
*compiler
, sljit_si type
)
2349 struct sljit_jump
*jump
;
2352 check_sljit_emit_jump(compiler
, type
);
2354 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
2356 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
2359 /* In ARM, we don't need to touch the arguments. */
2360 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2361 if (type
>= SLJIT_FAST_CALL
)
2362 PTR_FAIL_IF(prepare_blx(compiler
));
2363 PTR_FAIL_IF(push_inst_with_unique_literal(compiler
, ((EMIT_DATA_TRANSFER(WORD_DATA
| LOAD_DATA
, 1, 0,
2364 type
<= SLJIT_JUMP
? TMP_PC
: TMP_REG1
, TMP_PC
, 0)) & ~COND_MASK
) | get_cc(type
), 0));
2366 if (jump
->flags
& SLJIT_REWRITABLE_JUMP
) {
2367 jump
->addr
= compiler
->size
;
2368 compiler
->patches
++;
2371 if (type
>= SLJIT_FAST_CALL
) {
2372 jump
->flags
|= IS_BL
;
2373 PTR_FAIL_IF(emit_blx(compiler
));
2376 if (!(jump
->flags
& SLJIT_REWRITABLE_JUMP
))
2377 jump
->addr
= compiler
->size
;
2379 if (type
>= SLJIT_FAST_CALL
)
2380 jump
->flags
|= IS_BL
;
2381 PTR_FAIL_IF(emit_imm(compiler
, TMP_REG1
, 0));
2382 PTR_FAIL_IF(push_inst(compiler
, (((type
<= SLJIT_JUMP
? BX
: BLX
) | RM(TMP_REG1
)) & ~COND_MASK
) | get_cc(type
)));
2383 jump
->addr
= compiler
->size
;
2388 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_ijump(struct sljit_compiler
*compiler
, sljit_si type
, sljit_si src
, sljit_sw srcw
)
2390 struct sljit_jump
*jump
;
2393 check_sljit_emit_ijump(compiler
, type
, src
, srcw
);
2394 ADJUST_LOCAL_OFFSET(src
, srcw
);
2396 /* In ARM, we don't need to touch the arguments. */
2397 if (src
& SLJIT_IMM
) {
2398 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
2400 set_jump(jump
, compiler
, JUMP_ADDR
| ((type
>= SLJIT_FAST_CALL
) ? IS_BL
: 0));
2401 jump
->u
.target
= srcw
;
2403 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2404 if (type
>= SLJIT_FAST_CALL
)
2405 FAIL_IF(prepare_blx(compiler
));
2406 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));
2407 if (type
>= SLJIT_FAST_CALL
)
2408 FAIL_IF(emit_blx(compiler
));
2410 FAIL_IF(emit_imm(compiler
, TMP_REG1
, 0));
2411 FAIL_IF(push_inst(compiler
, (type
<= SLJIT_JUMP
? BX
: BLX
) | RM(TMP_REG1
)));
2413 jump
->addr
= compiler
->size
;
2416 if (src
<= TMP_REG3
)
2417 return push_inst(compiler
, (type
<= SLJIT_JUMP
? BX
: BLX
) | RM(src
));
2419 SLJIT_ASSERT(src
& SLJIT_MEM
);
2420 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, TMP_REG2
, src
, srcw
));
2421 return push_inst(compiler
, (type
<= SLJIT_JUMP
? BX
: BLX
) | RM(TMP_REG2
));
2424 return SLJIT_SUCCESS
;
2427 SLJIT_API_FUNC_ATTRIBUTE sljit_si
sljit_emit_op_flags(struct sljit_compiler
*compiler
, sljit_si op
,
2428 sljit_si dst
, sljit_sw dstw
,
2429 sljit_si src
, sljit_sw srcw
,
2432 sljit_si dst_r
, flags
= GET_ALL_FLAGS(op
);
2436 check_sljit_emit_op_flags(compiler
, op
, dst
, dstw
, src
, srcw
, type
);
2437 ADJUST_LOCAL_OFFSET(dst
, dstw
);
2438 ADJUST_LOCAL_OFFSET(src
, srcw
);
2440 if (dst
== SLJIT_UNUSED
)
2441 return SLJIT_SUCCESS
;
2443 op
= GET_OPCODE(op
);
2445 dst_r
= (dst
<= TMP_REG3
) ? dst
: TMP_REG2
;
2447 if (op
< SLJIT_ADD
) {
2448 EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst_r
, SLJIT_UNUSED
, SRC2_IMM
| 0));
2449 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP
, 0, dst_r
, SLJIT_UNUSED
, SRC2_IMM
| 1) & ~COND_MASK
) | cc
);
2450 return (dst_r
== TMP_REG2
) ? emit_op_mem(compiler
, WORD_DATA
, TMP_REG2
, dst
, dstw
) : SLJIT_SUCCESS
;
2453 ins
= (op
== SLJIT_AND
? AND_DP
: (op
== SLJIT_OR
? ORR_DP
: EOR_DP
));
2454 if ((op
== SLJIT_OR
|| op
== SLJIT_XOR
) && dst
<= TMP_REG3
&& dst
== src
) {
2455 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ins
, 0, dst
, dst
, SRC2_IMM
| 1) & ~COND_MASK
) | cc
);
2456 /* The condition must always be set, even if the ORR/EOR is not executed above. */
2457 return (flags
& SLJIT_SET_E
) ? push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, SET_FLAGS
, TMP_REG1
, SLJIT_UNUSED
, RM(dst
))) : SLJIT_SUCCESS
;
2460 compiler
->cache_arg
= 0;
2461 compiler
->cache_argw
= 0;
2462 if (src
& SLJIT_MEM
) {
2463 FAIL_IF(emit_op_mem2(compiler
, WORD_DATA
| LOAD_DATA
, TMP_REG1
, src
, srcw
, dst
, dstw
));
2466 } else if (src
& SLJIT_IMM
) {
2467 FAIL_IF(load_immediate(compiler
, TMP_REG1
, srcw
));
2472 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ins
, 0, dst_r
, src
, SRC2_IMM
| 1) & ~COND_MASK
) | cc
);
2473 EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ins
, 0, dst_r
, src
, SRC2_IMM
| 0) & ~COND_MASK
) | (cc
^ 0x10000000));
2474 if (dst_r
== TMP_REG2
)
2475 FAIL_IF(emit_op_mem2(compiler
, WORD_DATA
, TMP_REG2
, dst
, dstw
, 0, 0));
2477 return (flags
& SLJIT_SET_E
) ? push_inst(compiler
, EMIT_DATA_PROCESS_INS(MOV_DP
, SET_FLAGS
, TMP_REG1
, SLJIT_UNUSED
, RM(dst_r
))) : SLJIT_SUCCESS
;
2480 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_const
* sljit_emit_const(struct sljit_compiler
*compiler
, sljit_si dst
, sljit_sw dstw
, sljit_sw init_value
)
2482 struct sljit_const
*const_
;
2486 check_sljit_emit_const(compiler
, dst
, dstw
, init_value
);
2487 ADJUST_LOCAL_OFFSET(dst
, dstw
);
2489 const_
= (struct sljit_const
*)ensure_abuf(compiler
, sizeof(struct sljit_const
));
2490 PTR_FAIL_IF(!const_
);
2492 reg
= (dst
<= TMP_REG3
) ? dst
: TMP_REG2
;
2494 #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
2495 PTR_FAIL_IF(push_inst_with_unique_literal(compiler
, EMIT_DATA_TRANSFER(WORD_DATA
| LOAD_DATA
, 1, 0, reg
, TMP_PC
, 0), init_value
));
2496 compiler
->patches
++;
2498 PTR_FAIL_IF(emit_imm(compiler
, reg
, init_value
));
2500 set_const(const_
, compiler
);
2502 if (reg
== TMP_REG2
&& dst
!= SLJIT_UNUSED
)
2503 PTR_FAIL_IF(emit_op_mem(compiler
, WORD_DATA
, TMP_REG2
, dst
, dstw
));
2507 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_addr
)
2509 inline_set_jump_addr(addr
, new_addr
, 1);
2512 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
)
2514 inline_set_const(addr
, new_constant
, 1);