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
= (sljit_u32
)type
;
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 PTR_FAIL_IF(call_with_args(compiler
, arg_types
, &ins
, &extra_space
));
211 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
213 PTR_FAIL_IF(emit_const(compiler
, PIC_ADDR_REG
, 0));
215 if (!(type
& SLJIT_CALL_RETURN
) || extra_space
> 0) {
216 jump
->flags
|= IS_JAL
| IS_CALL
;
217 PTR_FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
219 PTR_FAIL_IF(push_inst(compiler
, JR
| S(PIC_ADDR_REG
), UNMOVABLE_INS
));
221 jump
->addr
= compiler
->size
;
222 PTR_FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
224 if (extra_space
== 0)
227 if (type
& SLJIT_CALL_RETURN
)
228 PTR_FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, RETURN_ADDR_REG
,
229 SLJIT_MEM1(SLJIT_SP
), (sljit_sw
)(extra_space
- sizeof(sljit_sw
))));
231 if (type
& SLJIT_CALL_RETURN
)
232 PTR_FAIL_IF(push_inst(compiler
, JR
| SA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
234 PTR_FAIL_IF(push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(extra_space
),
235 (type
& SLJIT_CALL_RETURN
) ? UNMOVABLE_INS
: DR(SLJIT_SP
)));
239 SLJIT_API_FUNC_ATTRIBUTE sljit_s32
sljit_emit_icall(struct sljit_compiler
*compiler
, sljit_s32 type
,
241 sljit_s32 src
, sljit_sw srcw
)
243 sljit_u32 extra_space
= (sljit_u32
)type
;
247 CHECK(check_sljit_emit_icall(compiler
, type
, arg_types
, src
, srcw
));
249 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
252 FAIL_IF(load_immediate(compiler
, DR(PIC_ADDR_REG
), srcw
));
253 else if (FAST_IS_REG(src
))
254 FAIL_IF(push_inst(compiler
, ADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
255 else if (src
& SLJIT_MEM
) {
256 ADJUST_LOCAL_OFFSET(src
, srcw
);
257 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, DR(PIC_ADDR_REG
), src
, srcw
));
260 FAIL_IF(call_with_args(compiler
, arg_types
, &ins
, &extra_space
));
262 /* Register input. */
263 if (!(type
& SLJIT_CALL_RETURN
) || extra_space
> 0)
264 FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
266 FAIL_IF(push_inst(compiler
, JR
| S(PIC_ADDR_REG
), UNMOVABLE_INS
));
267 FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
269 if (extra_space
== 0)
270 return SLJIT_SUCCESS
;
272 if (type
& SLJIT_CALL_RETURN
)
273 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, RETURN_ADDR_REG
,
274 SLJIT_MEM1(SLJIT_SP
), (sljit_sw
)(extra_space
- sizeof(sljit_sw
))));
276 if (type
& SLJIT_CALL_RETURN
)
277 FAIL_IF(push_inst(compiler
, JR
| SA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
279 return push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(extra_space
),
280 (type
& SLJIT_CALL_RETURN
) ? UNMOVABLE_INS
: DR(SLJIT_SP
));