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 64-bit arch dependent functions. */
29 static sljit_s32
load_immediate(struct sljit_compiler
*compiler
, sljit_s32 dst_ar
, sljit_sw imm
)
38 return push_inst(compiler
, ORI
| SA(0) | TA(dst_ar
) | IMM(imm
), dst_ar
);
40 if (imm
< 0 && imm
>= SIMM_MIN
)
41 return push_inst(compiler
, ADDIU
| SA(0) | TA(dst_ar
) | IMM(imm
), dst_ar
);
43 if (imm
<= 0x7fffffffl
&& imm
>= -0x80000000l
) {
44 FAIL_IF(push_inst(compiler
, LUI
| TA(dst_ar
) | IMM(imm
>> 16), dst_ar
));
45 return (imm
& 0xffff) ? push_inst(compiler
, ORI
| SA(dst_ar
) | TA(dst_ar
) | IMM(imm
), dst_ar
) : SLJIT_SUCCESS
;
48 /* Zero extended number. */
55 while (!(uimm
& 0xff00000000000000l
)) {
60 if (!(uimm
& 0xf000000000000000l
)) {
65 if (!(uimm
& 0xc000000000000000l
)) {
70 if ((sljit_sw
)uimm
< 0) {
74 SLJIT_ASSERT(((uimm
& 0xc000000000000000l
) == 0x4000000000000000l
) && (shift
> 0) && (shift
<= 32));
79 FAIL_IF(push_inst(compiler
, LUI
| TA(dst_ar
) | IMM(uimm
>> 48), dst_ar
));
80 if (uimm
& 0x0000ffff00000000l
)
81 FAIL_IF(push_inst(compiler
, ORI
| SA(dst_ar
) | TA(dst_ar
) | IMM(uimm
>> 32), dst_ar
));
83 imm
&= (1l << shift
) - 1;
84 if (!(imm
& ~0xffff)) {
85 ins
= (shift
== 32) ? DSLL32
: DSLL
;
88 FAIL_IF(push_inst(compiler
, ins
| TA(dst_ar
) | DA(dst_ar
), dst_ar
));
89 return !(imm
& 0xffff) ? SLJIT_SUCCESS
: push_inst(compiler
, ORI
| SA(dst_ar
) | TA(dst_ar
) | IMM(imm
), dst_ar
);
92 /* Double shifts needs to be performed. */
96 while (!(uimm
& 0xf000000000000000l
)) {
101 if (!(uimm
& 0xc000000000000000l
)) {
106 if (!(uimm
& 0x8000000000000000l
)) {
111 SLJIT_ASSERT((uimm
& 0x8000000000000000l
) && (shift2
> 0) && (shift2
<= 16));
113 FAIL_IF(push_inst(compiler
, DSLL
| TA(dst_ar
) | DA(dst_ar
) | SH_IMM(shift
- shift2
), dst_ar
));
114 FAIL_IF(push_inst(compiler
, ORI
| SA(dst_ar
) | TA(dst_ar
) | IMM(uimm
>> 48), dst_ar
));
115 FAIL_IF(push_inst(compiler
, DSLL
| TA(dst_ar
) | DA(dst_ar
) | SH_IMM(shift2
), dst_ar
));
117 imm
&= (1l << shift2
) - 1;
118 return !(imm
& 0xffff) ? SLJIT_SUCCESS
: push_inst(compiler
, ORI
| SA(dst_ar
) | TA(dst_ar
) | IMM(imm
), dst_ar
);
121 #define SELECT_OP(a, b) \
122 (!(op & SLJIT_32) ? a : b)
124 #define EMIT_LOGICAL(op_imm, op_norm) \
125 if (flags & SRC2_IMM) { \
126 if (op & SLJIT_SET_Z) \
127 FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
128 if (!(flags & UNUSED_DEST)) \
129 FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
132 if (op & SLJIT_SET_Z) \
133 FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
134 if (!(flags & UNUSED_DEST)) \
135 FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
138 #define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
139 if (flags & SRC2_IMM) { \
141 SLJIT_ASSERT(!(op & SLJIT_32)); \
146 ins = (op & SLJIT_32) ? op_imm : op_dimm; \
147 if (op & SLJIT_SET_Z) \
148 FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
149 if (!(flags & UNUSED_DEST)) \
150 FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
153 ins = (op & SLJIT_32) ? op_v : op_dv; \
154 if (op & SLJIT_SET_Z) \
155 FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
156 if (!(flags & UNUSED_DEST)) \
157 FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
160 static SLJIT_INLINE sljit_s32
emit_single_op(struct sljit_compiler
*compiler
, sljit_s32 op
, sljit_s32 flags
,
161 sljit_s32 dst
, sljit_s32 src1
, sljit_sw src2
)
164 sljit_s32 is_overflow
, is_carry
, is_handled
;
166 switch (GET_OPCODE(op
)) {
169 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
171 return push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src2
) | TA(0) | D(dst
), DR(dst
));
172 return SLJIT_SUCCESS
;
176 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
177 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
178 if (op
== SLJIT_MOV_S8
) {
179 FAIL_IF(push_inst(compiler
, DSLL32
| T(src2
) | D(dst
) | SH_IMM(24), DR(dst
)));
180 return push_inst(compiler
, DSRA32
| T(dst
) | D(dst
) | SH_IMM(24), DR(dst
));
182 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xff), DR(dst
));
185 SLJIT_ASSERT(dst
== src2
);
187 return SLJIT_SUCCESS
;
191 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
192 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
193 if (op
== SLJIT_MOV_S16
) {
194 FAIL_IF(push_inst(compiler
, DSLL32
| T(src2
) | D(dst
) | SH_IMM(16), DR(dst
)));
195 return push_inst(compiler
, DSRA32
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
));
197 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xffff), DR(dst
));
200 SLJIT_ASSERT(dst
== src2
);
202 return SLJIT_SUCCESS
;
205 SLJIT_ASSERT(!(op
& SLJIT_32
));
206 FAIL_IF(push_inst(compiler
, DSLL32
| T(src2
) | D(dst
) | SH_IMM(0), DR(dst
)));
207 return push_inst(compiler
, DSRL32
| T(dst
) | D(dst
) | SH_IMM(0), DR(dst
));
210 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
211 return push_inst(compiler
, SLL
| T(src2
) | D(dst
) | SH_IMM(0), DR(dst
));
214 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
215 if (op
& SLJIT_SET_Z
)
216 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
217 if (!(flags
& UNUSED_DEST
))
218 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | D(dst
), DR(dst
)));
219 return SLJIT_SUCCESS
;
222 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
223 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
224 if (op
& SLJIT_SET_Z
)
225 FAIL_IF(push_inst(compiler
, SELECT_OP(DCLZ
, CLZ
) | S(src2
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
226 if (!(flags
& UNUSED_DEST
))
227 FAIL_IF(push_inst(compiler
, SELECT_OP(DCLZ
, CLZ
) | S(src2
) | T(dst
) | D(dst
), DR(dst
)));
228 #else /* SLJIT_MIPS_REV < 1 */
229 if (SLJIT_UNLIKELY(flags
& UNUSED_DEST
)) {
230 FAIL_IF(push_inst(compiler
, SELECT_OP(DSRL32
, SRL
) | T(src2
) | DA(EQUAL_FLAG
) | SH_IMM(31), EQUAL_FLAG
));
231 return push_inst(compiler
, XORI
| SA(EQUAL_FLAG
) | TA(EQUAL_FLAG
) | IMM(1), EQUAL_FLAG
);
233 /* Nearly all instructions are unmovable in the following sequence. */
234 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src2
) | TA(0) | D(TMP_REG1
), DR(TMP_REG1
)));
236 FAIL_IF(push_inst(compiler
, BEQ
| S(TMP_REG1
) | TA(0) | IMM(5), UNMOVABLE_INS
));
237 FAIL_IF(push_inst(compiler
, ORI
| SA(0) | T(dst
) | IMM((op
& SLJIT_32
) ? 32 : 64), UNMOVABLE_INS
));
238 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | SA(0) | T(dst
) | IMM(-1), DR(dst
)));
239 /* Loop for searching the highest bit. */
240 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(dst
) | T(dst
) | IMM(1), DR(dst
)));
241 FAIL_IF(push_inst(compiler
, BGEZ
| S(TMP_REG1
) | IMM(-2), UNMOVABLE_INS
));
242 FAIL_IF(push_inst(compiler
, SELECT_OP(DSLL
, SLL
) | T(TMP_REG1
) | D(TMP_REG1
) | SH_IMM(1), UNMOVABLE_INS
));
243 #endif /* SLJIT_MIPS_REV >= 1 */
244 return SLJIT_SUCCESS
;
247 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
248 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
250 if (flags
& SRC2_IMM
) {
253 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
255 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
257 else if (op
& SLJIT_SET_Z
)
258 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
260 if (is_overflow
|| is_carry
) {
262 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
264 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | SA(0) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
265 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
268 /* dst may be the same as src1 or src2. */
269 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
270 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
274 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
275 else if (op
& SLJIT_SET_Z
)
276 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
278 if (is_overflow
|| is_carry
)
279 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
280 /* dst may be the same as src1 or src2. */
281 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
282 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
285 /* a + b >= a | b (otherwise, the carry should be set to 1). */
286 if (is_overflow
|| is_carry
)
287 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
289 return SLJIT_SUCCESS
;
290 FAIL_IF(push_inst(compiler
, SELECT_OP(DSLL32
, SLL
) | TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
291 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
292 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
293 if (op
& SLJIT_SET_Z
)
294 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
295 return push_inst(compiler
, SELECT_OP(DSRL32
, SRL
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
298 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
300 if (flags
& SRC2_IMM
) {
303 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
305 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | SA(0) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
306 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
309 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
312 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
313 /* dst may be the same as src1 or src2. */
314 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
317 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
319 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
321 return SLJIT_SUCCESS
;
323 /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
324 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
325 /* Set carry flag. */
326 return push_inst(compiler
, OR
| SA(OTHER_FLAG
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
329 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
330 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
337 if (flags
& SRC2_IMM
) {
338 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
339 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
342 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
343 FAIL_IF(push_inst(compiler
, SLTI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
348 if (!is_handled
&& GET_FLAG_TYPE(op
) >= SLJIT_LESS
&& GET_FLAG_TYPE(op
) <= SLJIT_SIG_LESS_EQUAL
) {
351 if (flags
& SRC2_IMM
) {
352 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
357 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
358 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
360 else if (GET_FLAG_TYPE(op
) == SLJIT_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_LESS_EQUAL
)
362 FAIL_IF(push_inst(compiler
, SLTU
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
364 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
365 FAIL_IF(push_inst(compiler
, SLT
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
367 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS_EQUAL
)
369 FAIL_IF(push_inst(compiler
, SLT
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
374 if (flags
& SRC2_IMM
) {
375 if (op
& SLJIT_SET_Z
)
376 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
377 if (!(flags
& UNUSED_DEST
))
378 return push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(-src2
), DR(dst
));
381 if (op
& SLJIT_SET_Z
)
382 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
383 if (!(flags
& UNUSED_DEST
))
384 return push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
));
386 return SLJIT_SUCCESS
;
389 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
390 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
392 if (flags
& SRC2_IMM
) {
395 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
397 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
399 else if (op
& SLJIT_SET_Z
)
400 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
402 if (is_overflow
|| is_carry
)
403 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
404 /* dst may be the same as src1 or src2. */
405 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
406 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
410 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
411 else if (op
& SLJIT_SET_Z
)
412 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
414 if (is_overflow
|| is_carry
)
415 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
416 /* dst may be the same as src1 or src2. */
417 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
418 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
422 return SLJIT_SUCCESS
;
423 FAIL_IF(push_inst(compiler
, SELECT_OP(DSLL32
, SLL
) | TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
424 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
425 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
426 if (op
& SLJIT_SET_Z
)
427 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
428 return push_inst(compiler
, SELECT_OP(DSRL32
, SRL
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
431 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
432 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
437 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
439 if (flags
& SRC2_IMM
) {
441 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
442 /* dst may be the same as src1 or src2. */
443 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
447 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
448 /* dst may be the same as src1 or src2. */
449 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
453 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | D(TMP_REG1
), DR(TMP_REG1
)));
455 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
456 return (is_carry
) ? push_inst(compiler
, OR
| SA(EQUAL_FLAG
) | T(TMP_REG1
) | DA(OTHER_FLAG
), OTHER_FLAG
) : SLJIT_SUCCESS
;
459 SLJIT_ASSERT(!(flags
& SRC2_IMM
));
461 if (GET_FLAG_TYPE(op
) != SLJIT_OVERFLOW
) {
462 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
463 return push_inst(compiler
, SELECT_OP(DMUL
, MUL
) | S(src1
) | T(src2
) | D(dst
), DR(dst
));
464 #elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
466 return push_inst(compiler
, MUL
| S(src1
) | T(src2
) | D(dst
), DR(dst
));
467 FAIL_IF(push_inst(compiler
, DMULT
| S(src1
) | T(src2
), MOVABLE_INS
));
468 return push_inst(compiler
, MFLO
| D(dst
), DR(dst
));
469 #else /* SLJIT_MIPS_REV < 1 */
470 FAIL_IF(push_inst(compiler
, SELECT_OP(DMULT
, MULT
) | S(src1
) | T(src2
), MOVABLE_INS
));
471 return push_inst(compiler
, MFLO
| D(dst
), DR(dst
));
472 #endif /* SLJIT_MIPS_REV >= 6 */
475 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
476 FAIL_IF(push_inst(compiler
, SELECT_OP(DMUL
, MUL
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
477 FAIL_IF(push_inst(compiler
, SELECT_OP(DMUH
, MUH
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
478 #else /* SLJIT_MIPS_REV < 6 */
479 FAIL_IF(push_inst(compiler
, SELECT_OP(DMULT
, MULT
) | S(src1
) | T(src2
), MOVABLE_INS
));
480 FAIL_IF(push_inst(compiler
, MFHI
| DA(EQUAL_FLAG
), EQUAL_FLAG
));
481 FAIL_IF(push_inst(compiler
, MFLO
| D(dst
), DR(dst
)));
482 #endif /* SLJIT_MIPS_REV >= 6 */
483 FAIL_IF(push_inst(compiler
, SELECT_OP(DSRA32
, SRA
) | T(dst
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
));
484 return push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | SA(EQUAL_FLAG
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
487 EMIT_LOGICAL(ANDI
, AND
);
488 return SLJIT_SUCCESS
;
491 EMIT_LOGICAL(ORI
, OR
);
492 return SLJIT_SUCCESS
;
495 EMIT_LOGICAL(XORI
, XOR
);
496 return SLJIT_SUCCESS
;
499 EMIT_SHIFT(DSLL
, DSLL32
, SLL
, DSLLV
, SLLV
);
500 return SLJIT_SUCCESS
;
503 EMIT_SHIFT(DSRL
, DSRL32
, SRL
, DSRLV
, SRLV
);
504 return SLJIT_SUCCESS
;
507 EMIT_SHIFT(DSRA
, DSRA32
, SRA
, DSRAV
, SRAV
);
508 return SLJIT_SUCCESS
;
512 return SLJIT_SUCCESS
;
515 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
517 FAIL_IF(push_inst(compiler
, LUI
| T(dst
) | IMM(init_value
>> 48), DR(dst
)));
518 FAIL_IF(push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
>> 32), DR(dst
)));
519 FAIL_IF(push_inst(compiler
, DSLL
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
)));
520 FAIL_IF(push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
>> 16), DR(dst
)));
521 FAIL_IF(push_inst(compiler
, DSLL
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
)));
522 return push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
), DR(dst
));
525 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
527 sljit_ins
*inst
= (sljit_ins
*)addr
;
528 SLJIT_UNUSED_ARG(executable_offset
);
530 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 6, 0);
531 inst
[0] = (inst
[0] & 0xffff0000) | ((new_target
>> 48) & 0xffff);
532 inst
[1] = (inst
[1] & 0xffff0000) | ((new_target
>> 32) & 0xffff);
533 inst
[3] = (inst
[3] & 0xffff0000) | ((new_target
>> 16) & 0xffff);
534 inst
[5] = (inst
[5] & 0xffff0000) | (new_target
& 0xffff);
535 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 6, 1);
536 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
537 SLJIT_CACHE_FLUSH(inst
, inst
+ 6);
540 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
542 sljit_set_jump_addr(addr
, new_constant
, executable_offset
);
545 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_ins
*ins_ptr
)
547 sljit_s32 arg_count
= 0;
548 sljit_s32 word_arg_count
= 0;
549 sljit_s32 float_arg_count
= 0;
551 sljit_ins prev_ins
= NOP
;
554 SLJIT_ASSERT(reg_map
[TMP_REG1
] == 4 && freg_map
[TMP_FREG1
] == 12);
556 arg_types
>>= SLJIT_DEF_SHIFT
;
559 types
= (types
<< SLJIT_DEF_SHIFT
) | (arg_types
& SLJIT_DEF_MASK
);
561 switch (arg_types
& SLJIT_DEF_MASK
) {
562 case SLJIT_ARG_TYPE_F32
:
563 case SLJIT_ARG_TYPE_F64
:
573 arg_types
>>= SLJIT_DEF_SHIFT
;
577 switch (types
& SLJIT_DEF_MASK
) {
578 case SLJIT_ARG_TYPE_F32
:
579 if (arg_count
!= float_arg_count
)
580 ins
= MOV_S
| FMT_S
| FS(float_arg_count
) | FD(arg_count
);
581 else if (arg_count
== 1)
582 ins
= MOV_S
| FMT_S
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
586 case SLJIT_ARG_TYPE_F64
:
587 if (arg_count
!= float_arg_count
)
588 ins
= MOV_S
| FMT_D
| FS(float_arg_count
) | FD(arg_count
);
589 else if (arg_count
== 1)
590 ins
= MOV_S
| FMT_D
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
595 if (arg_count
!= word_arg_count
)
596 ins
= DADDU
| S(word_arg_count
) | TA(0) | D(arg_count
);
597 else if (arg_count
== 1)
598 ins
= DADDU
| S(SLJIT_R0
) | TA(0) | DA(4);
606 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
611 types
>>= SLJIT_DEF_SHIFT
;
616 return SLJIT_SUCCESS
;
619 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_call(struct sljit_compiler
*compiler
, sljit_s32 type
,
622 struct sljit_jump
*jump
;
626 CHECK_PTR(check_sljit_emit_call(compiler
, type
, arg_types
));
628 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
630 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
633 PTR_FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
635 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
637 PTR_FAIL_IF(emit_const(compiler
, PIC_ADDR_REG
, 0));
639 jump
->flags
|= IS_JAL
| IS_CALL
;
640 PTR_FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
641 jump
->addr
= compiler
->size
;
642 PTR_FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
647 SLJIT_API_FUNC_ATTRIBUTE sljit_s32
sljit_emit_icall(struct sljit_compiler
*compiler
, sljit_s32 type
,
649 sljit_s32 src
, sljit_sw srcw
)
654 CHECK(check_sljit_emit_icall(compiler
, type
, arg_types
, src
, srcw
));
656 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
659 FAIL_IF(load_immediate(compiler
, DR(PIC_ADDR_REG
), srcw
));
660 else if (FAST_IS_REG(src
))
661 FAIL_IF(push_inst(compiler
, DADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
662 else if (src
& SLJIT_MEM
) {
663 ADJUST_LOCAL_OFFSET(src
, srcw
);
664 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, DR(PIC_ADDR_REG
), src
, srcw
));
667 FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
669 /* Register input. */
670 FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
671 return push_inst(compiler
, ins
, UNMOVABLE_INS
);