2 * Stack-less Just-In-Time compiler
4 * Copyright 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 /* mips 32-bit arch dependent functions. */
29 static sljit_s32
load_immediate(struct sljit_compiler
*compiler
, sljit_s32 dst_ar
, sljit_sw imm
)
32 return push_inst(compiler
, ORI
| SA(0) | TA(dst_ar
) | IMM(imm
), dst_ar
);
34 if (imm
< 0 && imm
>= SIMM_MIN
)
35 return push_inst(compiler
, ADDIU
| SA(0) | TA(dst_ar
) | IMM(imm
), dst_ar
);
37 FAIL_IF(push_inst(compiler
, LUI
| TA(dst_ar
) | IMM(imm
>> 16), dst_ar
));
38 return (imm
& 0xffff) ? push_inst(compiler
, ORI
| SA(dst_ar
) | TA(dst_ar
) | IMM(imm
), dst_ar
) : SLJIT_SUCCESS
;
41 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
43 FAIL_IF(push_inst(compiler
, LUI
| T(dst
) | IMM(init_value
>> 16), DR(dst
)));
44 return push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
), DR(dst
));
47 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
49 sljit_ins
*inst
= (sljit_ins
*)addr
;
50 SLJIT_UNUSED_ARG(executable_offset
);
52 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 0);
53 SLJIT_ASSERT((inst
[0] & 0xffe00000) == LUI
&& (inst
[1] & 0xfc000000) == ORI
);
54 inst
[0] = (inst
[0] & 0xffff0000) | ((new_target
>> 16) & 0xffff);
55 inst
[1] = (inst
[1] & 0xffff0000) | (new_target
& 0xffff);
56 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 1);
57 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
58 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
61 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
63 sljit_set_jump_addr(addr
, (sljit_uw
)new_constant
, executable_offset
);
66 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_ins
*ins_ptr
, sljit_u32
*extra_space
)
68 sljit_u32 is_tail_call
= *extra_space
& SLJIT_CALL_RETURN
;
70 sljit_s32 float_arg_count
= 0;
71 sljit_s32 word_arg_count
= 0;
73 sljit_ins prev_ins
= NOP
;
76 sljit_u8
*offsets_ptr
= offsets
;
78 SLJIT_ASSERT(reg_map
[TMP_REG1
] == 4 && freg_map
[TMP_FREG1
] == 12);
80 arg_types
>>= SLJIT_ARG_SHIFT
;
82 /* See ABI description in sljit_emit_enter. */
85 types
= (types
<< SLJIT_ARG_SHIFT
) | (arg_types
& SLJIT_ARG_MASK
);
86 *offsets_ptr
= (sljit_u8
)offset
;
88 switch (arg_types
& SLJIT_ARG_MASK
) {
89 case SLJIT_ARG_TYPE_F64
:
91 offset
+= sizeof(sljit_sw
);
92 *offsets_ptr
= (sljit_u8
)offset
;
95 if (word_arg_count
== 0 && float_arg_count
<= 1)
96 *offsets_ptr
= (sljit_u8
)(254 + float_arg_count
);
98 offset
+= sizeof(sljit_f64
);
101 case SLJIT_ARG_TYPE_F32
:
102 if (word_arg_count
== 0 && float_arg_count
<= 1)
103 *offsets_ptr
= (sljit_u8
)(254 + float_arg_count
);
105 offset
+= sizeof(sljit_f32
);
109 offset
+= sizeof(sljit_sw
);
114 arg_types
>>= SLJIT_ARG_SHIFT
;
118 /* Stack is aligned to 16 bytes. */
119 SLJIT_ASSERT(offset
<= 8 * sizeof(sljit_sw
));
121 if (offset
> 4 * sizeof(sljit_sw
) && (!is_tail_call
|| offset
> compiler
->args_size
)) {
123 offset
= (offset
+ sizeof(sljit_sw
) + 15) & ~(sljit_uw
)0xf;
124 FAIL_IF(emit_stack_frame_release(compiler
, (sljit_s32
)offset
, &prev_ins
));
125 *extra_space
= offset
;
127 FAIL_IF(push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(-16), DR(SLJIT_SP
)));
132 FAIL_IF(emit_stack_frame_release(compiler
, 0, &prev_ins
));
139 switch (types
& SLJIT_ARG_MASK
) {
140 case SLJIT_ARG_TYPE_F64
:
141 if (*offsets_ptr
< 4 * sizeof (sljit_sw
)) {
143 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
145 /* Must be preceded by at least one other argument,
146 * and its starting offset must be 8 because of alignment. */
147 SLJIT_ASSERT((*offsets_ptr
>> 2) == 2);
149 prev_ins
= MFC1
| TA(6) | FS(float_arg_count
) | (1 << 11);
150 ins
= MFC1
| TA(7) | FS(float_arg_count
);
151 } else if (*offsets_ptr
< 254)
152 ins
= SDC1
| S(SLJIT_SP
) | FT(float_arg_count
) | IMM(*offsets_ptr
);
153 else if (*offsets_ptr
== 254)
154 ins
= MOV_S
| FMT_D
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
158 case SLJIT_ARG_TYPE_F32
:
159 if (*offsets_ptr
< 4 * sizeof (sljit_sw
))
160 ins
= MFC1
| TA(4 + (*offsets_ptr
>> 2)) | FS(float_arg_count
);
161 else if (*offsets_ptr
< 254)
162 ins
= SWC1
| S(SLJIT_SP
) | FT(float_arg_count
) | IMM(*offsets_ptr
);
163 else if (*offsets_ptr
== 254)
164 ins
= MOV_S
| FMT_S
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
169 if (*offsets_ptr
>= 4 * sizeof (sljit_sw
))
170 ins
= SW
| S(SLJIT_SP
) | T(word_arg_count
) | IMM(*offsets_ptr
);
171 else if ((*offsets_ptr
>> 2) != word_arg_count
- 1)
172 ins
= ADDU
| S(word_arg_count
) | TA(0) | DA(4 + (*offsets_ptr
>> 2));
173 else if (*offsets_ptr
== 0)
174 ins
= ADDU
| S(SLJIT_R0
) | TA(0) | DA(4);
182 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
187 types
>>= SLJIT_ARG_SHIFT
;
192 return SLJIT_SUCCESS
;
195 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_call(struct sljit_compiler
*compiler
, sljit_s32 type
,
198 struct sljit_jump
*jump
;
199 sljit_u32 extra_space
= 0;
203 CHECK_PTR(check_sljit_emit_call(compiler
, type
, arg_types
));
205 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
207 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
209 if ((type
& 0xff) != SLJIT_CALL_REG_ARG
) {
210 extra_space
= (sljit_u32
)type
;
211 PTR_FAIL_IF(call_with_args(compiler
, arg_types
, &ins
, &extra_space
));
212 } else if (type
& SLJIT_CALL_RETURN
)
213 PTR_FAIL_IF(emit_stack_frame_release(compiler
, 0, &ins
));
215 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
217 if (ins
== NOP
&& compiler
->delay_slot
!= UNMOVABLE_INS
)
218 jump
->flags
|= IS_MOVABLE
;
220 if (!(type
& SLJIT_CALL_RETURN
) || extra_space
> 0) {
221 jump
->flags
|= IS_JAL
;
223 if ((type
& 0xff) != SLJIT_CALL_REG_ARG
)
224 jump
->flags
|= IS_CALL
;
226 PTR_FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
228 PTR_FAIL_IF(push_inst(compiler
, JR
| S(PIC_ADDR_REG
), UNMOVABLE_INS
));
230 jump
->addr
= compiler
->size
;
231 PTR_FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
233 /* Maximum number of instructions required for generating a constant. */
236 if (extra_space
== 0)
239 if (type
& SLJIT_CALL_RETURN
)
240 PTR_FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, RETURN_ADDR_REG
,
241 SLJIT_MEM1(SLJIT_SP
), (sljit_sw
)(extra_space
- sizeof(sljit_sw
))));
243 if (type
& SLJIT_CALL_RETURN
)
244 PTR_FAIL_IF(push_inst(compiler
, JR
| SA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
246 PTR_FAIL_IF(push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(extra_space
),
247 (type
& SLJIT_CALL_RETURN
) ? UNMOVABLE_INS
: DR(SLJIT_SP
)));
251 SLJIT_API_FUNC_ATTRIBUTE sljit_s32
sljit_emit_icall(struct sljit_compiler
*compiler
, sljit_s32 type
,
253 sljit_s32 src
, sljit_sw srcw
)
255 sljit_u32 extra_space
= (sljit_u32
)type
;
259 CHECK(check_sljit_emit_icall(compiler
, type
, arg_types
, src
, srcw
));
261 if (src
& SLJIT_MEM
) {
262 ADJUST_LOCAL_OFFSET(src
, srcw
);
263 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, DR(PIC_ADDR_REG
), src
, srcw
));
268 if ((type
& 0xff) == SLJIT_CALL_REG_ARG
) {
269 if (type
& SLJIT_CALL_RETURN
) {
270 if (src
>= SLJIT_FIRST_SAVED_REG
&& src
<= SLJIT_S0
) {
271 FAIL_IF(push_inst(compiler
, ADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
276 FAIL_IF(emit_stack_frame_release(compiler
, 0, &ins
));
279 FAIL_IF(push_inst(compiler
, ins
, MOVABLE_INS
));
282 SLJIT_SKIP_CHECKS(compiler
);
283 return sljit_emit_ijump(compiler
, type
, src
, srcw
);
286 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
289 FAIL_IF(load_immediate(compiler
, DR(PIC_ADDR_REG
), srcw
));
290 else if (src
!= PIC_ADDR_REG
)
291 FAIL_IF(push_inst(compiler
, ADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
293 FAIL_IF(call_with_args(compiler
, arg_types
, &ins
, &extra_space
));
295 /* Register input. */
296 if (!(type
& SLJIT_CALL_RETURN
) || extra_space
> 0)
297 FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
299 FAIL_IF(push_inst(compiler
, JR
| S(PIC_ADDR_REG
), UNMOVABLE_INS
));
300 FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
302 if (extra_space
== 0)
303 return SLJIT_SUCCESS
;
305 if (type
& SLJIT_CALL_RETURN
)
306 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, RETURN_ADDR_REG
,
307 SLJIT_MEM1(SLJIT_SP
), (sljit_sw
)(extra_space
- sizeof(sljit_sw
))));
309 if (type
& SLJIT_CALL_RETURN
)
310 FAIL_IF(push_inst(compiler
, JR
| SA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
312 return push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(extra_space
),
313 (type
& SLJIT_CALL_RETURN
) ? UNMOVABLE_INS
: DR(SLJIT_SP
));