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. */
51 uimm
= ~(sljit_uw
)imm
;
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
)) {
168 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
170 return push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src2
) | TA(0) | D(dst
), DR(dst
));
171 return SLJIT_SUCCESS
;
174 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
175 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
))
176 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xff), DR(dst
));
177 SLJIT_ASSERT(dst
== src2
);
178 return SLJIT_SUCCESS
;
181 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
182 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
183 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
185 return push_inst(compiler
, SEB
| T(src2
) | D(dst
), DR(dst
));
186 #endif /* SLJIT_MIPS_REV >= 1 */
187 FAIL_IF(push_inst(compiler
, DSLL32
| T(src2
) | D(dst
) | SH_IMM(24), DR(dst
)));
188 return push_inst(compiler
, DSRA32
| T(dst
) | D(dst
) | SH_IMM(24), DR(dst
));
190 SLJIT_ASSERT(dst
== src2
);
191 return SLJIT_SUCCESS
;
194 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
195 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
))
196 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xffff), DR(dst
));
197 SLJIT_ASSERT(dst
== src2
);
198 return SLJIT_SUCCESS
;
201 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
202 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
203 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
205 return push_inst(compiler
, SEH
| T(src2
) | D(dst
), DR(dst
));
206 #endif /* SLJIT_MIPS_REV >= 1 */
207 FAIL_IF(push_inst(compiler
, DSLL32
| T(src2
) | D(dst
) | SH_IMM(16), DR(dst
)));
208 return push_inst(compiler
, DSRA32
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
));
210 SLJIT_ASSERT(dst
== src2
);
211 return SLJIT_SUCCESS
;
214 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
) && !(op
& SLJIT_32
));
215 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
216 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
218 return push_inst(compiler
, DINSU
| T(src2
) | SA(0) | (31 << 11) | (0 << 11), DR(dst
));
219 #endif /* SLJIT_MIPS_REV >= 2 */
220 FAIL_IF(push_inst(compiler
, DSLL32
| T(src2
) | D(dst
) | SH_IMM(0), DR(dst
)));
221 return push_inst(compiler
, DSRL32
| T(dst
) | D(dst
) | SH_IMM(0), DR(dst
));
223 SLJIT_ASSERT(dst
== src2
);
224 return SLJIT_SUCCESS
;
227 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
) && !(op
& SLJIT_32
));
228 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
229 return push_inst(compiler
, SLL
| T(src2
) | D(dst
) | SH_IMM(0), DR(dst
));
231 SLJIT_ASSERT(dst
== src2
);
232 return SLJIT_SUCCESS
;
235 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
236 if (op
& SLJIT_SET_Z
)
237 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
238 if (!(flags
& UNUSED_DEST
))
239 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | D(dst
), DR(dst
)));
240 return SLJIT_SUCCESS
;
243 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
244 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
245 if (op
& SLJIT_SET_Z
)
246 FAIL_IF(push_inst(compiler
, SELECT_OP(DCLZ
, CLZ
) | S(src2
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
247 if (!(flags
& UNUSED_DEST
))
248 FAIL_IF(push_inst(compiler
, SELECT_OP(DCLZ
, CLZ
) | S(src2
) | T(dst
) | D(dst
), DR(dst
)));
249 #else /* SLJIT_MIPS_REV < 1 */
250 if (SLJIT_UNLIKELY(flags
& UNUSED_DEST
)) {
251 FAIL_IF(push_inst(compiler
, SELECT_OP(DSRL32
, SRL
) | T(src2
) | DA(EQUAL_FLAG
) | SH_IMM(31), EQUAL_FLAG
));
252 return push_inst(compiler
, XORI
| SA(EQUAL_FLAG
) | TA(EQUAL_FLAG
) | IMM(1), EQUAL_FLAG
);
254 /* Nearly all instructions are unmovable in the following sequence. */
255 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src2
) | TA(0) | D(TMP_REG1
), DR(TMP_REG1
)));
257 FAIL_IF(push_inst(compiler
, BEQ
| S(TMP_REG1
) | TA(0) | IMM(5), UNMOVABLE_INS
));
258 FAIL_IF(push_inst(compiler
, ORI
| SA(0) | T(dst
) | IMM((op
& SLJIT_32
) ? 32 : 64), UNMOVABLE_INS
));
259 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | SA(0) | T(dst
) | IMM(-1), DR(dst
)));
260 /* Loop for searching the highest bit. */
261 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(dst
) | T(dst
) | IMM(1), DR(dst
)));
262 FAIL_IF(push_inst(compiler
, BGEZ
| S(TMP_REG1
) | IMM(-2), UNMOVABLE_INS
));
263 FAIL_IF(push_inst(compiler
, SELECT_OP(DSLL
, SLL
) | T(TMP_REG1
) | D(TMP_REG1
) | SH_IMM(1), UNMOVABLE_INS
));
264 #endif /* SLJIT_MIPS_REV >= 1 */
265 return SLJIT_SUCCESS
;
268 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
269 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
271 if (flags
& SRC2_IMM
) {
274 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
276 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
278 else if (op
& SLJIT_SET_Z
)
279 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
281 if (is_overflow
|| is_carry
) {
283 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
285 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | SA(0) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
286 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
289 /* dst may be the same as src1 or src2. */
290 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
291 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
295 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
296 else if (op
& SLJIT_SET_Z
)
297 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
299 if (is_overflow
|| is_carry
)
300 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
301 /* dst may be the same as src1 or src2. */
302 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
303 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
306 /* a + b >= a | b (otherwise, the carry should be set to 1). */
307 if (is_overflow
|| is_carry
)
308 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
310 return SLJIT_SUCCESS
;
311 FAIL_IF(push_inst(compiler
, SELECT_OP(DSLL32
, SLL
) | TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
312 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
313 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
314 if (op
& SLJIT_SET_Z
)
315 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
316 return push_inst(compiler
, SELECT_OP(DSRL32
, SRL
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
319 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
321 if (flags
& SRC2_IMM
) {
324 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
326 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | SA(0) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
327 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
330 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
333 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
334 /* dst may be the same as src1 or src2. */
335 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
338 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
340 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
342 return SLJIT_SUCCESS
;
344 /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
345 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
346 /* Set carry flag. */
347 return push_inst(compiler
, OR
| SA(OTHER_FLAG
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
350 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
351 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
358 if (flags
& SRC2_IMM
) {
359 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
360 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
363 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
364 FAIL_IF(push_inst(compiler
, SLTI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
369 if (!is_handled
&& GET_FLAG_TYPE(op
) >= SLJIT_LESS
&& GET_FLAG_TYPE(op
) <= SLJIT_SIG_LESS_EQUAL
) {
372 if (flags
& SRC2_IMM
) {
373 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
378 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
379 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
381 else if (GET_FLAG_TYPE(op
) == SLJIT_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_LESS_EQUAL
)
383 FAIL_IF(push_inst(compiler
, SLTU
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
385 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
386 FAIL_IF(push_inst(compiler
, SLT
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
388 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS_EQUAL
)
390 FAIL_IF(push_inst(compiler
, SLT
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
395 if (flags
& SRC2_IMM
) {
396 if (op
& SLJIT_SET_Z
)
397 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
398 if (!(flags
& UNUSED_DEST
))
399 return push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(-src2
), DR(dst
));
402 if (op
& SLJIT_SET_Z
)
403 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
404 if (!(flags
& UNUSED_DEST
))
405 return push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
));
407 return SLJIT_SUCCESS
;
410 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
411 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
413 if (flags
& SRC2_IMM
) {
416 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
418 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
420 else if (op
& SLJIT_SET_Z
)
421 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
423 if (is_overflow
|| is_carry
)
424 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
425 /* dst may be the same as src1 or src2. */
426 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
427 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
431 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
432 else if (op
& SLJIT_SET_Z
)
433 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
435 if (is_overflow
|| is_carry
)
436 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
437 /* dst may be the same as src1 or src2. */
438 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
439 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
443 return SLJIT_SUCCESS
;
444 FAIL_IF(push_inst(compiler
, SELECT_OP(DSLL32
, SLL
) | TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
445 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
446 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
447 if (op
& SLJIT_SET_Z
)
448 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDU
, ADDU
) | S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
449 return push_inst(compiler
, SELECT_OP(DSRL32
, SRL
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
452 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
453 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
458 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
460 if (flags
& SRC2_IMM
) {
462 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
463 /* dst may be the same as src1 or src2. */
464 FAIL_IF(push_inst(compiler
, SELECT_OP(DADDIU
, ADDIU
) | S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
468 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
469 /* dst may be the same as src1 or src2. */
470 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
474 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | D(TMP_REG1
), DR(TMP_REG1
)));
476 FAIL_IF(push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
477 return (is_carry
) ? push_inst(compiler
, OR
| SA(EQUAL_FLAG
) | T(TMP_REG1
) | DA(OTHER_FLAG
), OTHER_FLAG
) : SLJIT_SUCCESS
;
480 SLJIT_ASSERT(!(flags
& SRC2_IMM
));
482 if (GET_FLAG_TYPE(op
) != SLJIT_OVERFLOW
) {
483 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
484 return push_inst(compiler
, SELECT_OP(DMUL
, MUL
) | S(src1
) | T(src2
) | D(dst
), DR(dst
));
485 #elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
487 return push_inst(compiler
, MUL
| S(src1
) | T(src2
) | D(dst
), DR(dst
));
488 FAIL_IF(push_inst(compiler
, DMULT
| S(src1
) | T(src2
), MOVABLE_INS
));
489 return push_inst(compiler
, MFLO
| D(dst
), DR(dst
));
490 #else /* SLJIT_MIPS_REV < 1 */
491 FAIL_IF(push_inst(compiler
, SELECT_OP(DMULT
, MULT
) | S(src1
) | T(src2
), MOVABLE_INS
));
492 return push_inst(compiler
, MFLO
| D(dst
), DR(dst
));
493 #endif /* SLJIT_MIPS_REV >= 6 */
496 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
497 FAIL_IF(push_inst(compiler
, SELECT_OP(DMUL
, MUL
) | S(src1
) | T(src2
) | D(dst
), DR(dst
)));
498 FAIL_IF(push_inst(compiler
, SELECT_OP(DMUH
, MUH
) | S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
499 #else /* SLJIT_MIPS_REV < 6 */
500 FAIL_IF(push_inst(compiler
, SELECT_OP(DMULT
, MULT
) | S(src1
) | T(src2
), MOVABLE_INS
));
501 FAIL_IF(push_inst(compiler
, MFHI
| DA(EQUAL_FLAG
), EQUAL_FLAG
));
502 FAIL_IF(push_inst(compiler
, MFLO
| D(dst
), DR(dst
)));
503 #endif /* SLJIT_MIPS_REV >= 6 */
504 FAIL_IF(push_inst(compiler
, SELECT_OP(DSRA32
, SRA
) | T(dst
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
));
505 return push_inst(compiler
, SELECT_OP(DSUBU
, SUBU
) | SA(EQUAL_FLAG
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
508 EMIT_LOGICAL(ANDI
, AND
);
509 return SLJIT_SUCCESS
;
512 EMIT_LOGICAL(ORI
, OR
);
513 return SLJIT_SUCCESS
;
516 EMIT_LOGICAL(XORI
, XOR
);
517 return SLJIT_SUCCESS
;
520 EMIT_SHIFT(DSLL
, DSLL32
, SLL
, DSLLV
, SLLV
);
521 return SLJIT_SUCCESS
;
524 EMIT_SHIFT(DSRL
, DSRL32
, SRL
, DSRLV
, SRLV
);
525 return SLJIT_SUCCESS
;
528 EMIT_SHIFT(DSRA
, DSRA32
, SRA
, DSRAV
, SRAV
);
529 return SLJIT_SUCCESS
;
533 return SLJIT_SUCCESS
;
536 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
538 FAIL_IF(push_inst(compiler
, LUI
| T(dst
) | IMM(init_value
>> 48), DR(dst
)));
539 FAIL_IF(push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
>> 32), DR(dst
)));
540 FAIL_IF(push_inst(compiler
, DSLL
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
)));
541 FAIL_IF(push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
>> 16), DR(dst
)));
542 FAIL_IF(push_inst(compiler
, DSLL
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
)));
543 return push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
), DR(dst
));
546 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
548 sljit_ins
*inst
= (sljit_ins
*)addr
;
549 SLJIT_UNUSED_ARG(executable_offset
);
551 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 6, 0);
552 inst
[0] = (inst
[0] & 0xffff0000) | ((sljit_ins
)(new_target
>> 48) & 0xffff);
553 inst
[1] = (inst
[1] & 0xffff0000) | ((sljit_ins
)(new_target
>> 32) & 0xffff);
554 inst
[3] = (inst
[3] & 0xffff0000) | ((sljit_ins
)(new_target
>> 16) & 0xffff);
555 inst
[5] = (inst
[5] & 0xffff0000) | ((sljit_ins
)new_target
& 0xffff);
556 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 6, 1);
557 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
558 SLJIT_CACHE_FLUSH(inst
, inst
+ 6);
561 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
563 sljit_set_jump_addr(addr
, (sljit_uw
)new_constant
, executable_offset
);
566 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_ins
*ins_ptr
)
568 sljit_s32 arg_count
= 0;
569 sljit_s32 word_arg_count
= 0;
570 sljit_s32 float_arg_count
= 0;
572 sljit_ins prev_ins
= NOP
;
575 SLJIT_ASSERT(reg_map
[TMP_REG1
] == 4 && freg_map
[TMP_FREG1
] == 12);
577 arg_types
>>= SLJIT_ARG_SHIFT
;
580 types
= (types
<< SLJIT_ARG_SHIFT
) | (arg_types
& SLJIT_ARG_MASK
);
582 switch (arg_types
& SLJIT_ARG_MASK
) {
583 case SLJIT_ARG_TYPE_F64
:
584 case SLJIT_ARG_TYPE_F32
:
594 arg_types
>>= SLJIT_ARG_SHIFT
;
598 switch (types
& SLJIT_ARG_MASK
) {
599 case SLJIT_ARG_TYPE_F64
:
600 if (arg_count
!= float_arg_count
)
601 ins
= MOV_S
| FMT_D
| FS(float_arg_count
) | FD(arg_count
);
602 else if (arg_count
== 1)
603 ins
= MOV_S
| FMT_D
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
607 case SLJIT_ARG_TYPE_F32
:
608 if (arg_count
!= float_arg_count
)
609 ins
= MOV_S
| FMT_S
| FS(float_arg_count
) | FD(arg_count
);
610 else if (arg_count
== 1)
611 ins
= MOV_S
| FMT_S
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
616 if (arg_count
!= word_arg_count
)
617 ins
= DADDU
| S(word_arg_count
) | TA(0) | D(arg_count
);
618 else if (arg_count
== 1)
619 ins
= DADDU
| S(SLJIT_R0
) | TA(0) | DA(4);
627 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
632 types
>>= SLJIT_ARG_SHIFT
;
637 return SLJIT_SUCCESS
;
640 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_call(struct sljit_compiler
*compiler
, sljit_s32 type
,
643 struct sljit_jump
*jump
;
647 CHECK_PTR(check_sljit_emit_call(compiler
, type
, arg_types
));
649 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
651 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
654 PTR_FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
656 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
658 PTR_FAIL_IF(emit_const(compiler
, PIC_ADDR_REG
, 0));
660 jump
->flags
|= IS_JAL
| IS_CALL
;
661 PTR_FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
662 jump
->addr
= compiler
->size
;
663 PTR_FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
668 SLJIT_API_FUNC_ATTRIBUTE sljit_s32
sljit_emit_icall(struct sljit_compiler
*compiler
, sljit_s32 type
,
670 sljit_s32 src
, sljit_sw srcw
)
675 CHECK(check_sljit_emit_icall(compiler
, type
, arg_types
, src
, srcw
));
677 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
680 FAIL_IF(load_immediate(compiler
, DR(PIC_ADDR_REG
), srcw
));
681 else if (FAST_IS_REG(src
))
682 FAIL_IF(push_inst(compiler
, DADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
683 else if (src
& SLJIT_MEM
) {
684 ADJUST_LOCAL_OFFSET(src
, srcw
);
685 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, DR(PIC_ADDR_REG
), src
, srcw
));
688 FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
690 /* Register input. */
691 FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
692 return push_inst(compiler
, ins
, UNMOVABLE_INS
);