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
);
48 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
50 return push_inst(compiler
, OR
| D(dst
) | S1(0) | S2(src2
), DR(dst
));
55 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
56 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
57 if (op
== SLJIT_MOV_U8
)
58 return push_inst(compiler
, AND
| D(dst
) | S1(src2
) | IMM(0xff), DR(dst
));
59 FAIL_IF(push_inst(compiler
, SLL
| D(dst
) | S1(src2
) | IMM(24), DR(dst
)));
60 return push_inst(compiler
, SRA
| D(dst
) | S1(dst
) | IMM(24), DR(dst
));
68 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
69 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
70 FAIL_IF(push_inst(compiler
, SLL
| D(dst
) | S1(src2
) | IMM(16), DR(dst
)));
71 return push_inst(compiler
, (op
== SLJIT_MOV_S16
? SRA
: SRL
) | D(dst
) | S1(dst
) | IMM(16), DR(dst
));
78 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
79 return push_inst(compiler
, XNOR
| (flags
& SET_FLAGS
) | D(dst
) | S1(0) | S2(src2
), DR(dst
) | (flags
& SET_FLAGS
));
82 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
83 FAIL_IF(push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(src2
) | S2(0), SET_FLAGS
));
84 FAIL_IF(push_inst(compiler
, OR
| D(TMP_REG1
) | S1(0) | S2(src2
), DR(TMP_REG1
)));
85 FAIL_IF(push_inst(compiler
, BICC
| DA(0x1) | (7 & DISP_MASK
), UNMOVABLE_INS
));
86 FAIL_IF(push_inst(compiler
, OR
| D(dst
) | S1(0) | IMM(32), UNMOVABLE_INS
));
87 FAIL_IF(push_inst(compiler
, OR
| D(dst
) | S1(0) | IMM(-1), DR(dst
)));
90 FAIL_IF(push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(TMP_REG1
) | S2(0), SET_FLAGS
));
91 FAIL_IF(push_inst(compiler
, SLL
| D(TMP_REG1
) | S1(TMP_REG1
) | IMM(1), DR(TMP_REG1
)));
92 FAIL_IF(push_inst(compiler
, BICC
| DA(0xe) | (-2 & DISP_MASK
), UNMOVABLE_INS
));
93 return push_inst(compiler
, ADD
| D(dst
) | S1(dst
) | IMM(1), UNMOVABLE_INS
);
96 compiler
->status_flags_state
= SLJIT_CURRENT_FLAGS_ADD_SUB
;
97 return push_inst(compiler
, ADD
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
100 return push_inst(compiler
, ADDC
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
103 compiler
->status_flags_state
= SLJIT_CURRENT_FLAGS_ADD_SUB
;
104 return push_inst(compiler
, SUB
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
107 return push_inst(compiler
, SUBC
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
110 compiler
->status_flags_state
= 0;
111 FAIL_IF(push_inst(compiler
, SMUL
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
112 if (!(flags
& SET_FLAGS
))
113 return SLJIT_SUCCESS
;
114 FAIL_IF(push_inst(compiler
, SRA
| D(TMP_REG1
) | S1(dst
) | IMM(31), DR(TMP_REG1
)));
115 FAIL_IF(push_inst(compiler
, RDY
| D(TMP_LINK
), DR(TMP_LINK
)));
116 return push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(TMP_REG1
) | S2(TMP_LINK
), MOVABLE_INS
| SET_FLAGS
);
119 return push_inst(compiler
, AND
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
122 return push_inst(compiler
, OR
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
125 return push_inst(compiler
, XOR
| (flags
& SET_FLAGS
) | D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
) | (flags
& SET_FLAGS
));
128 FAIL_IF(push_inst(compiler
, SLL
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
129 return !(flags
& SET_FLAGS
) ? SLJIT_SUCCESS
: push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(dst
) | S2(0), SET_FLAGS
);
132 FAIL_IF(push_inst(compiler
, SRL
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
133 return !(flags
& SET_FLAGS
) ? SLJIT_SUCCESS
: push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(dst
) | S2(0), SET_FLAGS
);
136 FAIL_IF(push_inst(compiler
, SRA
| D(dst
) | S1(src1
) | ARG2(flags
, src2
), DR(dst
)));
137 return !(flags
& SET_FLAGS
) ? SLJIT_SUCCESS
: push_inst(compiler
, SUB
| SET_FLAGS
| D(0) | S1(dst
) | S2(0), SET_FLAGS
);
141 return SLJIT_SUCCESS
;
144 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_s32
*src
)
146 sljit_s32 reg_index
= 8;
147 sljit_s32 word_reg_index
= 8;
148 sljit_s32 float_arg_index
= 1;
149 sljit_s32 double_arg_count
= 0;
150 sljit_s32 float_offset
= (16 + 6) * sizeof(sljit_sw
);
153 sljit_s32 move_to_tmp2
= 0;
156 reg
= reg_map
[*src
& REG_MASK
];
158 arg_types
>>= SLJIT_DEF_SHIFT
;
161 types
= (types
<< SLJIT_DEF_SHIFT
) | (arg_types
& SLJIT_DEF_MASK
);
163 switch (arg_types
& SLJIT_DEF_MASK
) {
164 case SLJIT_ARG_TYPE_F32
:
166 if (reg_index
== reg
)
170 case SLJIT_ARG_TYPE_F64
:
173 if (reg_index
== reg
|| reg_index
+ 1 == reg
)
178 if (reg_index
!= word_reg_index
&& reg_index
< 14 && reg_index
== reg
)
188 FAIL_IF(push_inst(compiler
, OR
| D(TMP_REG1
) | S1(0) | S2A(reg
), DR(TMP_REG1
)));
192 arg_types
>>= SLJIT_DEF_SHIFT
;
198 switch (arg_types
& SLJIT_DEF_MASK
) {
199 case SLJIT_ARG_TYPE_F32
:
201 FAIL_IF(push_inst(compiler
, STF
| FD(float_arg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), MOVABLE_INS
));
202 float_offset
-= sizeof(sljit_f64
);
204 case SLJIT_ARG_TYPE_F64
:
206 if (float_arg_index
== 4 && double_arg_count
== 4) {
207 FAIL_IF(push_inst(compiler
, STF
| FD(float_arg_index
) | S1(SLJIT_SP
) | IMM((16 + 7) * sizeof(sljit_sw
)), MOVABLE_INS
));
208 FAIL_IF(push_inst(compiler
, STF
| FD(float_arg_index
) | (1 << 25) | S1(SLJIT_SP
) | IMM((16 + 8) * sizeof(sljit_sw
)), MOVABLE_INS
));
211 FAIL_IF(push_inst(compiler
, STDF
| FD(float_arg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), MOVABLE_INS
));
212 float_offset
-= sizeof(sljit_f64
);
218 arg_types
>>= SLJIT_DEF_SHIFT
;
221 float_offset
= (16 + 6) * sizeof(sljit_sw
);
224 switch (types
& SLJIT_DEF_MASK
) {
225 case SLJIT_ARG_TYPE_F32
:
228 FAIL_IF(push_inst(compiler
, LDUW
| DA(reg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), reg_index
));
229 float_offset
-= sizeof(sljit_f64
);
231 case SLJIT_ARG_TYPE_F64
:
233 if (reg_index
< 14) {
234 if ((reg_index
& 0x1) != 0) {
235 FAIL_IF(push_inst(compiler
, LDUW
| DA(reg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), reg_index
));
237 FAIL_IF(push_inst(compiler
, LDUW
| DA(reg_index
+ 1) | S1(SLJIT_SP
) | IMM(float_offset
+ sizeof(sljit_sw
)), reg_index
+ 1));
240 FAIL_IF(push_inst(compiler
, LDD
| DA(reg_index
) | S1(SLJIT_SP
) | IMM(float_offset
), reg_index
));
242 float_offset
-= sizeof(sljit_f64
);
248 if (reg_index
!= word_reg_index
) {
250 FAIL_IF(push_inst(compiler
, OR
| DA(reg_index
) | S1(0) | S2A(word_reg_index
), reg_index
));
252 FAIL_IF(push_inst(compiler
, STW
| DA(word_reg_index
) | S1(SLJIT_SP
) | IMM(92), word_reg_index
));
257 types
>>= SLJIT_DEF_SHIFT
;
260 return SLJIT_SUCCESS
;
263 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
265 FAIL_IF(push_inst(compiler
, SETHI
| D(dst
) | ((init_value
>> 10) & 0x3fffff), DR(dst
)));
266 return push_inst(compiler
, OR
| D(dst
) | S1(dst
) | IMM_ARG
| (init_value
& 0x3ff), DR(dst
));
269 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
271 sljit_ins
*inst
= (sljit_ins
*)addr
;
272 SLJIT_UNUSED_ARG(executable_offset
);
274 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 0);
275 SLJIT_ASSERT(((inst
[0] & 0xc1c00000) == 0x01000000) && ((inst
[1] & 0xc1f82000) == 0x80102000));
276 inst
[0] = (inst
[0] & 0xffc00000) | ((new_target
>> 10) & 0x3fffff);
277 inst
[1] = (inst
[1] & 0xfffffc00) | (new_target
& 0x3ff);
278 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 1);
279 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
280 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
283 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
285 sljit_set_jump_addr(addr
, new_constant
, executable_offset
);