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 static sljit_s32
load_immediate(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw imm
)
29 if (imm
<= SIMM_MAX
&& imm
>= SIMM_MIN
)
30 return push_inst(compiler
, OR
| D(dst
) | S1(0) | IMM(imm
), DR(dst
));
32 FAIL_IF(push_inst(compiler
, SETHI
| D(dst
) | ((imm
>> 10) & 0x3fffff), DR(dst
)));
33 return (imm
& 0x3ff) ? push_inst(compiler
, OR
| D(dst
) | S1(dst
) | IMM_ARG
| (imm
& 0x3ff), DR(dst
)) : SLJIT_SUCCESS
;
36 #define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
38 static SLJIT_INLINE sljit_s32
emit_single_op(struct sljit_compiler
*compiler
, sljit_s32 op
, sljit_s32 flags
,
39 sljit_s32 dst
, sljit_s32 src1
, sljit_sw src2
)
41 SLJIT_COMPILE_ASSERT(ICC_IS_SET
== SET_FLAGS
, icc_is_set_and_set_flags_must_be_the_same
);
45 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
47 return push_inst(compiler
, OR
| D(dst
) | S1(0) | S2(src2
), DR(dst
));
52 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
53 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
54 if (op
== SLJIT_MOV_U8
)
55 return push_inst(compiler
, AND
| D(dst
) | S1(src2
) | IMM(0xff), DR(dst
));
56 FAIL_IF(push_inst(compiler
, SLL
| D(dst
) | S1(src2
) | IMM(24), DR(dst
)));
57 return push_inst(compiler
, SRA
| D(dst
) | S1(dst
) | IMM(24), DR(dst
));
59 SLJIT_ASSERT(dst
== src2
);
64 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
65 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
66 FAIL_IF(push_inst(compiler
, SLL
| D(dst
) | S1(src2
) | IMM(16), DR(dst
)));
67 return push_inst(compiler
, (op
== SLJIT_MOV_S16
? SRA
: SRL
) | D(dst
) | S1(dst
) | IMM(16), DR(dst
));
69 SLJIT_ASSERT(dst
== src2
);
73 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
74 return push_inst(compiler
, XNOR
| (flags
& SET_FLAGS
) | D(dst
) | S1(0) | S2(src2
), DR(dst
) | (flags
& SET_FLAGS
));
77 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
78 FAIL_IF(push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(src2
) | S2(0), SET_FLAGS
));
79 FAIL_IF(push_inst(compiler
, OR
| D(TMP_REG1
) | S1(0) | S2(src2
), DR(TMP_REG1
)));
80 FAIL_IF(push_inst(compiler
, BICC
| DA(0x1) | (7 & DISP_MASK
), UNMOVABLE_INS
));
81 FAIL_IF(push_inst(compiler
, OR
| D(dst
) | S1(0) | IMM(32), UNMOVABLE_INS
));
82 FAIL_IF(push_inst(compiler
, OR
| D(dst
) | S1(0) | IMM(-1), DR(dst
)));
85 FAIL_IF(push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(TMP_REG1
) | S2(0), SET_FLAGS
));
86 FAIL_IF(push_inst(compiler
, SLL
| D(TMP_REG1
) | S1(TMP_REG1
) | IMM(1), DR(TMP_REG1
)));
87 FAIL_IF(push_inst(compiler
, BICC
| DA(0xe) | (-2 & DISP_MASK
), UNMOVABLE_INS
));
88 return push_inst(compiler
, ADD
| D(dst
) | S1(dst
) | IMM(1), UNMOVABLE_INS
);
91 compiler
->status_flags_state
= SLJIT_CURRENT_FLAGS_ADD_SUB
;
92 return push_inst(compiler
, ADD
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
95 return push_inst(compiler
, ADDC
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
98 compiler
->status_flags_state
= SLJIT_CURRENT_FLAGS_ADD_SUB
;
99 return push_inst(compiler
, SUB
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
102 return push_inst(compiler
, SUBC
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
105 compiler
->status_flags_state
= 0;
106 FAIL_IF(push_inst(compiler
, SMUL
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
107 if (!(flags
& SET_FLAGS
))
108 return SLJIT_SUCCESS
;
109 FAIL_IF(push_inst(compiler
, SRA
| D(TMP_REG1
) | S1(dst
) | IMM(31), DR(TMP_REG1
)));
110 FAIL_IF(push_inst(compiler
, RDY
| D(TMP_LINK
), DR(TMP_LINK
)));
111 return push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(TMP_REG1
) | S2(TMP_LINK
), MOVABLE_INS
| SET_FLAGS
);
114 return push_inst(compiler
, AND
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
117 return push_inst(compiler
, OR
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
120 return push_inst(compiler
, XOR
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
123 FAIL_IF(push_inst(compiler
, SLL
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
124 return !(flags
& SET_FLAGS
) ? SLJIT_SUCCESS
: push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(dst
) | S2(0), SET_FLAGS
);
127 FAIL_IF(push_inst(compiler
, SRL
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
128 return !(flags
& SET_FLAGS
) ? SLJIT_SUCCESS
: push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(dst
) | S2(0), SET_FLAGS
);
131 FAIL_IF(push_inst(compiler
, SRA
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
132 return !(flags
& SET_FLAGS
) ? SLJIT_SUCCESS
: push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(dst
) | S2(0), SET_FLAGS
);
136 return SLJIT_SUCCESS
;
139 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_s32
*src
)
141 sljit_s32 reg_index
= 8;
142 sljit_s32 word_reg_index
= 8;
143 sljit_s32 float_arg_index
= 1;
144 sljit_s32 double_arg_count
= 0;
145 sljit_s32 float_offset
= (16 + 6) * sizeof(sljit_sw
);
148 sljit_s32 move_to_tmp2
= 0;
151 reg
= reg_map
[*src
& REG_MASK
];
153 arg_types
>>= SLJIT_ARG_SHIFT
;
156 types
= (types
<< SLJIT_ARG_SHIFT
) | (arg_types
& SLJIT_ARG_MASK
);
158 switch (arg_types
& SLJIT_ARG_MASK
) {
159 case SLJIT_ARG_TYPE_F64
:
162 if (reg_index
== reg
|| reg_index
+ 1 == reg
)
166 case SLJIT_ARG_TYPE_F32
:
168 if (reg_index
== reg
)
173 if (reg_index
!= word_reg_index
&& reg_index
== reg
)
180 arg_types
>>= SLJIT_ARG_SHIFT
;
185 FAIL_IF(push_inst(compiler
, OR
| D(TMP_REG1
) | S1(0) | S2A(reg
), DR(TMP_REG1
)));
192 switch (arg_types
& SLJIT_ARG_MASK
) {
193 case SLJIT_ARG_TYPE_F64
:
195 if (float_arg_index
== 4 && double_arg_count
== 4) {
196 /* The address is not doubleword aligned, so two instructions are required to store the double. */
197 FAIL_IF(push_inst(compiler
, STF
| FD(float_arg_index
) | S1(SLJIT_SP
) | IMM((16 + 7) * sizeof(sljit_sw
)), MOVABLE_INS
));
198 FAIL_IF(push_inst(compiler
, STF
| FD(float_arg_index
) | (1 << 25) | S1(SLJIT_SP
) | IMM((16 + 8) * sizeof(sljit_sw
)), MOVABLE_INS
));
201 FAIL_IF(push_inst(compiler
, STDF
| FD(float_arg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), MOVABLE_INS
));
202 float_offset
-= sizeof(sljit_f64
);
204 case SLJIT_ARG_TYPE_F32
:
206 FAIL_IF(push_inst(compiler
, STF
| FD(float_arg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), MOVABLE_INS
));
207 float_offset
-= sizeof(sljit_f64
);
213 arg_types
>>= SLJIT_ARG_SHIFT
;
216 float_offset
= (16 + 6) * sizeof(sljit_sw
);
219 switch (types
& SLJIT_ARG_MASK
) {
220 case SLJIT_ARG_TYPE_F64
:
222 if (reg_index
< 14) {
223 if ((reg_index
& 0x1) != 0) {
224 FAIL_IF(push_inst(compiler
, LDUW
| DA(reg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), reg_index
));
225 if (reg_index
< 8 + 6 - 1)
226 FAIL_IF(push_inst(compiler
, LDUW
| DA(reg_index
+ 1) | S1(SLJIT_SP
) | IMM(float_offset
+ sizeof(sljit_sw
)), reg_index
+ 1));
229 FAIL_IF(push_inst(compiler
, LDD
| DA(reg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), reg_index
));
231 float_offset
-= sizeof(sljit_f64
);
233 case SLJIT_ARG_TYPE_F32
:
235 if (reg_index
< 8 + 6)
236 FAIL_IF(push_inst(compiler
, LDUW
| DA(reg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), reg_index
));
237 float_offset
-= sizeof(sljit_f64
);
243 if (reg_index
!= word_reg_index
) {
245 FAIL_IF(push_inst(compiler
, OR
| DA(reg_index
) | S1(0) | S2A(word_reg_index
), reg_index
));
247 FAIL_IF(push_inst(compiler
, STW
| DA(word_reg_index
) | S1(SLJIT_SP
) | IMM(92), word_reg_index
));
252 types
>>= SLJIT_ARG_SHIFT
;
255 return SLJIT_SUCCESS
;
258 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
260 FAIL_IF(push_inst(compiler
, SETHI
| D(dst
) | ((init_value
>> 10) & 0x3fffff), DR(dst
)));
261 return push_inst(compiler
, OR
| D(dst
) | S1(dst
) | IMM_ARG
| (init_value
& 0x3ff), DR(dst
));
264 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
266 sljit_ins
*inst
= (sljit_ins
*)addr
;
267 SLJIT_UNUSED_ARG(executable_offset
);
269 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 0);
270 SLJIT_ASSERT(((inst
[0] & 0xc1c00000) == 0x01000000) && ((inst
[1] & 0xc1f82000) == 0x80102000));
271 inst
[0] = (inst
[0] & 0xffc00000) | ((new_target
>> 10) & 0x3fffff);
272 inst
[1] = (inst
[1] & 0xfffffc00) | (new_target
& 0x3ff);
273 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 1);
274 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
275 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
278 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
280 sljit_set_jump_addr(addr
, new_constant
, executable_offset
);