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 #define EMIT_LOGICAL(op_imm, op_norm) \
42 if (flags & SRC2_IMM) { \
43 if (op & SLJIT_SET_Z) \
44 FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
45 if (!(flags & UNUSED_DEST)) \
46 FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
49 if (op & SLJIT_SET_Z) \
50 FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
51 if (!(flags & UNUSED_DEST)) \
52 FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
55 #define EMIT_SHIFT(op_imm, op_v) \
56 if (flags & SRC2_IMM) { \
57 if (op & SLJIT_SET_Z) \
58 FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
59 if (!(flags & UNUSED_DEST)) \
60 FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
63 if (op & SLJIT_SET_Z) \
64 FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
65 if (!(flags & UNUSED_DEST)) \
66 FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
69 static SLJIT_INLINE sljit_s32
emit_single_op(struct sljit_compiler
*compiler
, sljit_s32 op
, sljit_s32 flags
,
70 sljit_s32 dst
, sljit_s32 src1
, sljit_sw src2
)
72 sljit_s32 is_overflow
, is_carry
, is_handled
;
74 switch (GET_OPCODE(op
)) {
76 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
78 return push_inst(compiler
, ADDU
| S(src2
) | TA(0) | D(dst
), DR(dst
));
82 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
83 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
))
84 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xff), DR(dst
));
85 SLJIT_ASSERT(dst
== src2
);
89 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
90 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
91 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
92 return push_inst(compiler
, SEB
| T(src2
) | D(dst
), DR(dst
));
93 #else /* SLJIT_MIPS_REV < 1 */
94 FAIL_IF(push_inst(compiler
, SLL
| T(src2
) | D(dst
) | SH_IMM(24), DR(dst
)));
95 return push_inst(compiler
, SRA
| T(dst
) | D(dst
) | SH_IMM(24), DR(dst
));
96 #endif /* SLJIT_MIPS_REV >= 1 */
98 SLJIT_ASSERT(dst
== src2
);
102 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
103 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
))
104 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xffff), DR(dst
));
105 SLJIT_ASSERT(dst
== src2
);
106 return SLJIT_SUCCESS
;
109 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
110 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
111 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
112 return push_inst(compiler
, SEH
| T(src2
) | D(dst
), DR(dst
));
113 #else /* SLJIT_MIPS_REV < 1 */
114 FAIL_IF(push_inst(compiler
, SLL
| T(src2
) | D(dst
) | SH_IMM(16), DR(dst
)));
115 return push_inst(compiler
, SRA
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
));
116 #endif /* SLJIT_MIPS_REV >= 1 */
118 SLJIT_ASSERT(dst
== src2
);
119 return SLJIT_SUCCESS
;
122 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
123 if (op
& SLJIT_SET_Z
)
124 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
125 if (!(flags
& UNUSED_DEST
))
126 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | D(dst
), DR(dst
)));
127 return SLJIT_SUCCESS
;
130 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
131 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
132 if (op
& SLJIT_SET_Z
)
133 FAIL_IF(push_inst(compiler
, CLZ
| S(src2
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
134 if (!(flags
& UNUSED_DEST
))
135 FAIL_IF(push_inst(compiler
, CLZ
| S(src2
) | T(dst
) | D(dst
), DR(dst
)));
136 #else /* SLJIT_MIPS_REV < 1 */
137 if (SLJIT_UNLIKELY(flags
& UNUSED_DEST
)) {
138 FAIL_IF(push_inst(compiler
, SRL
| T(src2
) | DA(EQUAL_FLAG
) | SH_IMM(31), EQUAL_FLAG
));
139 return push_inst(compiler
, XORI
| SA(EQUAL_FLAG
) | TA(EQUAL_FLAG
) | IMM(1), EQUAL_FLAG
);
141 /* Nearly all instructions are unmovable in the following sequence. */
142 FAIL_IF(push_inst(compiler
, ADDU
| S(src2
) | TA(0) | D(TMP_REG1
), DR(TMP_REG1
)));
144 FAIL_IF(push_inst(compiler
, BEQ
| S(TMP_REG1
) | TA(0) | IMM(5), UNMOVABLE_INS
));
145 FAIL_IF(push_inst(compiler
, ORI
| SA(0) | T(dst
) | IMM(32), UNMOVABLE_INS
));
146 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(dst
) | IMM(-1), DR(dst
)));
147 /* Loop for searching the highest bit. */
148 FAIL_IF(push_inst(compiler
, ADDIU
| S(dst
) | T(dst
) | IMM(1), DR(dst
)));
149 FAIL_IF(push_inst(compiler
, BGEZ
| S(TMP_REG1
) | IMM(-2), UNMOVABLE_INS
));
150 FAIL_IF(push_inst(compiler
, SLL
| T(TMP_REG1
) | D(TMP_REG1
) | SH_IMM(1), UNMOVABLE_INS
));
151 #endif /* SLJIT_MIPS_REV >= 1 */
152 return SLJIT_SUCCESS
;
155 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
156 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
158 if (flags
& SRC2_IMM
) {
161 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
163 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
165 else if (op
& SLJIT_SET_Z
)
166 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
168 if (is_overflow
|| is_carry
) {
170 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
172 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
173 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
176 /* dst may be the same as src1 or src2. */
177 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
178 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
182 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
183 else if (op
& SLJIT_SET_Z
)
184 FAIL_IF(push_inst(compiler
, ADDU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
186 if (is_overflow
|| is_carry
)
187 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
188 /* dst may be the same as src1 or src2. */
189 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
190 FAIL_IF(push_inst(compiler
, ADDU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
193 /* a + b >= a | b (otherwise, the carry should be set to 1). */
194 if (is_overflow
|| is_carry
)
195 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
197 return SLJIT_SUCCESS
;
198 FAIL_IF(push_inst(compiler
, SLL
| TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
199 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
200 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
201 if (op
& SLJIT_SET_Z
)
202 FAIL_IF(push_inst(compiler
, ADDU
| S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
203 return push_inst(compiler
, SRL
| TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
206 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
208 if (flags
& SRC2_IMM
) {
211 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
213 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
214 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
217 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
220 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
221 /* dst may be the same as src1 or src2. */
222 FAIL_IF(push_inst(compiler
, ADDU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
225 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
227 FAIL_IF(push_inst(compiler
, ADDU
| S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
229 return SLJIT_SUCCESS
;
231 /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
232 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
233 /* Set carry flag. */
234 return push_inst(compiler
, OR
| SA(OTHER_FLAG
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
237 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
238 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
245 if (flags
& SRC2_IMM
) {
246 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
247 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
250 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
251 FAIL_IF(push_inst(compiler
, SLTI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
256 if (!is_handled
&& GET_FLAG_TYPE(op
) >= SLJIT_LESS
&& GET_FLAG_TYPE(op
) <= SLJIT_SIG_LESS_EQUAL
) {
259 if (flags
& SRC2_IMM
) {
260 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
265 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
266 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
268 else if (GET_FLAG_TYPE(op
) == SLJIT_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_LESS_EQUAL
)
270 FAIL_IF(push_inst(compiler
, SLTU
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
272 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
273 FAIL_IF(push_inst(compiler
, SLT
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
275 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS_EQUAL
)
277 FAIL_IF(push_inst(compiler
, SLT
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
282 if (flags
& SRC2_IMM
) {
283 if (op
& SLJIT_SET_Z
)
284 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
285 if (!(flags
& UNUSED_DEST
))
286 return push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(-src2
), DR(dst
));
289 if (op
& SLJIT_SET_Z
)
290 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
291 if (!(flags
& UNUSED_DEST
))
292 return push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | D(dst
), DR(dst
));
294 return SLJIT_SUCCESS
;
297 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
298 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
300 if (flags
& SRC2_IMM
) {
303 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
305 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
307 else if (op
& SLJIT_SET_Z
)
308 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
310 if (is_overflow
|| is_carry
)
311 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
312 /* dst may be the same as src1 or src2. */
313 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
314 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
318 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
319 else if (op
& SLJIT_SET_Z
)
320 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
322 if (is_overflow
|| is_carry
)
323 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
324 /* dst may be the same as src1 or src2. */
325 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
326 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
330 return SLJIT_SUCCESS
;
331 FAIL_IF(push_inst(compiler
, SLL
| TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
332 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
333 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
334 if (op
& SLJIT_SET_Z
)
335 FAIL_IF(push_inst(compiler
, ADDU
| S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
336 return push_inst(compiler
, SRL
| TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
339 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
340 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
345 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
347 if (flags
& SRC2_IMM
) {
349 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
350 /* dst may be the same as src1 or src2. */
351 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
355 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
356 /* dst may be the same as src1 or src2. */
357 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
361 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | D(TMP_REG1
), DR(TMP_REG1
)));
363 FAIL_IF(push_inst(compiler
, SUBU
| S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
364 return (is_carry
) ? push_inst(compiler
, OR
| SA(EQUAL_FLAG
) | T(TMP_REG1
) | DA(OTHER_FLAG
), OTHER_FLAG
) : SLJIT_SUCCESS
;
367 SLJIT_ASSERT(!(flags
& SRC2_IMM
));
369 if (GET_FLAG_TYPE(op
) != SLJIT_OVERFLOW
) {
370 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
371 return push_inst(compiler
, MUL
| S(src1
) | T(src2
) | D(dst
), DR(dst
));
372 #else /* SLJIT_MIPS_REV < 1 */
373 FAIL_IF(push_inst(compiler
, MULT
| S(src1
) | T(src2
), MOVABLE_INS
));
374 return push_inst(compiler
, MFLO
| D(dst
), DR(dst
));
375 #endif /* SLJIT_MIPS_REV >= 1 */
378 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
379 FAIL_IF(push_inst(compiler
, MUL
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
380 FAIL_IF(push_inst(compiler
, MUH
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
381 #else /* SLJIT_MIPS_REV < 6 */
382 FAIL_IF(push_inst(compiler
, MULT
| S(src1
) | T(src2
), MOVABLE_INS
));
383 FAIL_IF(push_inst(compiler
, MFHI
| DA(EQUAL_FLAG
), EQUAL_FLAG
));
384 FAIL_IF(push_inst(compiler
, MFLO
| D(dst
), DR(dst
)));
385 #endif /* SLJIT_MIPS_REV >= 6 */
386 FAIL_IF(push_inst(compiler
, SRA
| T(dst
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
));
387 return push_inst(compiler
, SUBU
| SA(EQUAL_FLAG
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
390 EMIT_LOGICAL(ANDI
, AND
);
391 return SLJIT_SUCCESS
;
394 EMIT_LOGICAL(ORI
, OR
);
395 return SLJIT_SUCCESS
;
398 EMIT_LOGICAL(XORI
, XOR
);
399 return SLJIT_SUCCESS
;
402 EMIT_SHIFT(SLL
, SLLV
);
403 return SLJIT_SUCCESS
;
406 EMIT_SHIFT(SRL
, SRLV
);
407 return SLJIT_SUCCESS
;
410 EMIT_SHIFT(SRA
, SRAV
);
411 return SLJIT_SUCCESS
;
415 return SLJIT_SUCCESS
;
418 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
420 FAIL_IF(push_inst(compiler
, LUI
| T(dst
) | IMM(init_value
>> 16), DR(dst
)));
421 return push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
), DR(dst
));
424 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
426 sljit_ins
*inst
= (sljit_ins
*)addr
;
427 SLJIT_UNUSED_ARG(executable_offset
);
429 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 0);
430 SLJIT_ASSERT((inst
[0] & 0xffe00000) == LUI
&& (inst
[1] & 0xfc000000) == ORI
);
431 inst
[0] = (inst
[0] & 0xffff0000) | ((new_target
>> 16) & 0xffff);
432 inst
[1] = (inst
[1] & 0xffff0000) | (new_target
& 0xffff);
433 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 1);
434 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
435 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
438 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
440 sljit_set_jump_addr(addr
, (sljit_uw
)new_constant
, executable_offset
);
443 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_ins
*ins_ptr
)
445 sljit_u32 offset
= 0;
446 sljit_s32 float_arg_count
= 0;
447 sljit_s32 word_arg_count
= 0;
449 sljit_ins prev_ins
= NOP
;
452 sljit_u8
*offsets_ptr
= offsets
;
454 SLJIT_ASSERT(reg_map
[TMP_REG1
] == 4 && freg_map
[TMP_FREG1
] == 12);
456 arg_types
>>= SLJIT_ARG_SHIFT
;
458 /* See ABI description in sljit_emit_enter. */
461 types
= (types
<< SLJIT_ARG_SHIFT
) | (arg_types
& SLJIT_ARG_MASK
);
462 *offsets_ptr
= (sljit_u8
)offset
;
464 switch (arg_types
& SLJIT_ARG_MASK
) {
465 case SLJIT_ARG_TYPE_F64
:
467 offset
+= sizeof(sljit_sw
);
468 *offsets_ptr
= (sljit_u8
)offset
;
471 if (word_arg_count
== 0 && float_arg_count
<= 1)
472 *offsets_ptr
= (sljit_u8
)(254 + float_arg_count
);
474 offset
+= sizeof(sljit_f64
);
477 case SLJIT_ARG_TYPE_F32
:
478 if (word_arg_count
== 0 && float_arg_count
<= 1)
479 *offsets_ptr
= (sljit_u8
)(254 + float_arg_count
);
481 offset
+= sizeof(sljit_f32
);
485 offset
+= sizeof(sljit_sw
);
490 arg_types
>>= SLJIT_ARG_SHIFT
;
494 /* Stack is aligned to 16 bytes. */
495 SLJIT_ASSERT(offset
<= 8 * sizeof(sljit_sw
));
497 if (offset
> 4 * sizeof(sljit_sw
))
498 FAIL_IF(push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(-16), DR(SLJIT_SP
)));
503 switch (types
& SLJIT_ARG_MASK
) {
504 case SLJIT_ARG_TYPE_F64
:
505 if (*offsets_ptr
< 4 * sizeof (sljit_sw
)) {
507 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
509 /* Must be preceded by at least one other argument,
510 * and its starting offset must be 8 because of aligment. */
511 SLJIT_ASSERT((*offsets_ptr
>> 2) == 2);
513 prev_ins
= MFC1
| TA(6) | FS(float_arg_count
) | (1 << 11);
514 ins
= MFC1
| TA(7) | FS(float_arg_count
);
515 } else if (*offsets_ptr
< 254)
516 ins
= SDC1
| S(SLJIT_SP
) | FT(float_arg_count
) | IMM(*offsets_ptr
);
517 else if (*offsets_ptr
== 254)
518 ins
= MOV_S
| FMT_D
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
522 case SLJIT_ARG_TYPE_F32
:
523 if (*offsets_ptr
< 4 * sizeof (sljit_sw
))
524 ins
= MFC1
| TA(4 + (*offsets_ptr
>> 2)) | FS(float_arg_count
);
525 else if (*offsets_ptr
< 254)
526 ins
= SWC1
| S(SLJIT_SP
) | FT(float_arg_count
) | IMM(*offsets_ptr
);
527 else if (*offsets_ptr
== 254)
528 ins
= MOV_S
| FMT_S
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
533 if (*offsets_ptr
>= 4 * sizeof (sljit_sw
))
534 ins
= SW
| S(SLJIT_SP
) | T(word_arg_count
) | IMM(*offsets_ptr
);
535 else if ((*offsets_ptr
>> 2) != word_arg_count
- 1)
536 ins
= ADDU
| S(word_arg_count
) | TA(0) | DA(4 + (*offsets_ptr
>> 2));
537 else if (*offsets_ptr
== 0)
538 ins
= ADDU
| S(SLJIT_R0
) | TA(0) | DA(4);
546 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
551 types
>>= SLJIT_ARG_SHIFT
;
556 return SLJIT_SUCCESS
;
559 static sljit_s32
post_call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
)
561 sljit_u32 offset
= 0;
563 arg_types
>>= SLJIT_ARG_SHIFT
;
566 switch (arg_types
& SLJIT_ARG_MASK
) {
567 case SLJIT_ARG_TYPE_F64
:
569 offset
+= sizeof(sljit_sw
);
570 offset
+= sizeof(sljit_f64
);
572 case SLJIT_ARG_TYPE_F32
:
573 offset
+= sizeof(sljit_f32
);
576 offset
+= sizeof(sljit_sw
);
580 arg_types
>>= SLJIT_ARG_SHIFT
;
583 /* Stack is aligned to 16 bytes. */
584 SLJIT_ASSERT(offset
<= 8 * sizeof(sljit_sw
));
586 if (offset
> 4 * sizeof(sljit_sw
))
587 return push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(16), DR(SLJIT_SP
));
589 return SLJIT_SUCCESS
;
592 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_call(struct sljit_compiler
*compiler
, sljit_s32 type
,
595 struct sljit_jump
*jump
;
599 CHECK_PTR(check_sljit_emit_call(compiler
, type
, arg_types
));
601 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
603 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
606 PTR_FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
608 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
610 PTR_FAIL_IF(emit_const(compiler
, PIC_ADDR_REG
, 0));
612 jump
->flags
|= IS_JAL
| IS_CALL
;
613 PTR_FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
614 jump
->addr
= compiler
->size
;
615 PTR_FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
617 PTR_FAIL_IF(post_call_with_args(compiler
, arg_types
));
622 SLJIT_API_FUNC_ATTRIBUTE sljit_s32
sljit_emit_icall(struct sljit_compiler
*compiler
, sljit_s32 type
,
624 sljit_s32 src
, sljit_sw srcw
)
629 CHECK(check_sljit_emit_icall(compiler
, type
, arg_types
, src
, srcw
));
631 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
634 FAIL_IF(load_immediate(compiler
, DR(PIC_ADDR_REG
), srcw
));
635 else if (FAST_IS_REG(src
))
636 FAIL_IF(push_inst(compiler
, ADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
637 else if (src
& SLJIT_MEM
) {
638 ADJUST_LOCAL_OFFSET(src
, srcw
);
639 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, DR(PIC_ADDR_REG
), src
, srcw
));
642 FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
644 /* Register input. */
645 FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
646 FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
647 return post_call_with_args(compiler
, arg_types
);