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
)) {
79 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
81 return push_inst(compiler
, ADDU
| S(src2
) | TA(0) | D(dst
), DR(dst
));
86 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
87 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
88 if (op
== SLJIT_MOV_S8
) {
89 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
90 return push_inst(compiler
, SEB
| T(src2
) | D(dst
), DR(dst
));
91 #else /* SLJIT_MIPS_REV < 1 */
92 FAIL_IF(push_inst(compiler
, SLL
| T(src2
) | D(dst
) | SH_IMM(24), DR(dst
)));
93 return push_inst(compiler
, SRA
| T(dst
) | D(dst
) | SH_IMM(24), DR(dst
));
94 #endif /* SLJIT_MIPS_REV >= 1 */
96 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xff), DR(dst
));
99 SLJIT_ASSERT(dst
== src2
);
101 return SLJIT_SUCCESS
;
105 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
106 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
107 if (op
== SLJIT_MOV_S16
) {
108 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
109 return push_inst(compiler
, SEH
| T(src2
) | D(dst
), DR(dst
));
110 #else /* SLJIT_MIPS_REV < 1 */
111 FAIL_IF(push_inst(compiler
, SLL
| T(src2
) | D(dst
) | SH_IMM(16), DR(dst
)));
112 return push_inst(compiler
, SRA
| T(dst
) | D(dst
) | SH_IMM(16), DR(dst
));
113 #endif /* SLJIT_MIPS_REV >= 1 */
115 return push_inst(compiler
, ANDI
| S(src2
) | T(dst
) | IMM(0xffff), DR(dst
));
118 SLJIT_ASSERT(dst
== src2
);
120 return SLJIT_SUCCESS
;
123 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
124 if (op
& SLJIT_SET_Z
)
125 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
126 if (!(flags
& UNUSED_DEST
))
127 FAIL_IF(push_inst(compiler
, NOR
| S(src2
) | T(src2
) | D(dst
), DR(dst
)));
128 return SLJIT_SUCCESS
;
131 SLJIT_ASSERT(src1
== TMP_REG1
&& !(flags
& SRC2_IMM
));
132 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
133 if (op
& SLJIT_SET_Z
)
134 FAIL_IF(push_inst(compiler
, CLZ
| S(src2
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
135 if (!(flags
& UNUSED_DEST
))
136 FAIL_IF(push_inst(compiler
, CLZ
| S(src2
) | T(dst
) | D(dst
), DR(dst
)));
137 #else /* SLJIT_MIPS_REV < 1 */
138 if (SLJIT_UNLIKELY(flags
& UNUSED_DEST
)) {
139 FAIL_IF(push_inst(compiler
, SRL
| T(src2
) | DA(EQUAL_FLAG
) | SH_IMM(31), EQUAL_FLAG
));
140 return push_inst(compiler
, XORI
| SA(EQUAL_FLAG
) | TA(EQUAL_FLAG
) | IMM(1), EQUAL_FLAG
);
142 /* Nearly all instructions are unmovable in the following sequence. */
143 FAIL_IF(push_inst(compiler
, ADDU
| S(src2
) | TA(0) | D(TMP_REG1
), DR(TMP_REG1
)));
145 FAIL_IF(push_inst(compiler
, BEQ
| S(TMP_REG1
) | TA(0) | IMM(5), UNMOVABLE_INS
));
146 FAIL_IF(push_inst(compiler
, ORI
| SA(0) | T(dst
) | IMM(32), UNMOVABLE_INS
));
147 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(dst
) | IMM(-1), DR(dst
)));
148 /* Loop for searching the highest bit. */
149 FAIL_IF(push_inst(compiler
, ADDIU
| S(dst
) | T(dst
) | IMM(1), DR(dst
)));
150 FAIL_IF(push_inst(compiler
, BGEZ
| S(TMP_REG1
) | IMM(-2), UNMOVABLE_INS
));
151 FAIL_IF(push_inst(compiler
, SLL
| T(TMP_REG1
) | D(TMP_REG1
) | SH_IMM(1), UNMOVABLE_INS
));
152 #endif /* SLJIT_MIPS_REV >= 1 */
153 return SLJIT_SUCCESS
;
156 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
157 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
159 if (flags
& SRC2_IMM
) {
162 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
164 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
166 else if (op
& SLJIT_SET_Z
)
167 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
169 if (is_overflow
|| is_carry
) {
171 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
173 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
174 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
177 /* dst may be the same as src1 or src2. */
178 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
179 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
183 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
184 else if (op
& SLJIT_SET_Z
)
185 FAIL_IF(push_inst(compiler
, ADDU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
187 if (is_overflow
|| is_carry
)
188 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
189 /* dst may be the same as src1 or src2. */
190 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
191 FAIL_IF(push_inst(compiler
, ADDU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
194 /* a + b >= a | b (otherwise, the carry should be set to 1). */
195 if (is_overflow
|| is_carry
)
196 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
198 return SLJIT_SUCCESS
;
199 FAIL_IF(push_inst(compiler
, SLL
| TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
200 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
201 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
202 if (op
& SLJIT_SET_Z
)
203 FAIL_IF(push_inst(compiler
, ADDU
| S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
204 return push_inst(compiler
, SRL
| TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
207 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
209 if (flags
& SRC2_IMM
) {
212 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
214 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
215 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
218 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(src2
), DR(dst
)));
221 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
222 /* dst may be the same as src1 or src2. */
223 FAIL_IF(push_inst(compiler
, ADDU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
226 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
228 FAIL_IF(push_inst(compiler
, ADDU
| S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
230 return SLJIT_SUCCESS
;
232 /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
233 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
234 /* Set carry flag. */
235 return push_inst(compiler
, OR
| SA(OTHER_FLAG
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
238 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
239 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
246 if (flags
& SRC2_IMM
) {
247 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
248 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
251 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
252 FAIL_IF(push_inst(compiler
, SLTI
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
257 if (!is_handled
&& GET_FLAG_TYPE(op
) >= SLJIT_LESS
&& GET_FLAG_TYPE(op
) <= SLJIT_SIG_LESS_EQUAL
) {
260 if (flags
& SRC2_IMM
) {
261 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
266 if (GET_FLAG_TYPE(op
) == SLJIT_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_GREATER_EQUAL
) {
267 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
269 else if (GET_FLAG_TYPE(op
) == SLJIT_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_LESS_EQUAL
)
271 FAIL_IF(push_inst(compiler
, SLTU
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
273 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER_EQUAL
) {
274 FAIL_IF(push_inst(compiler
, SLT
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
276 else if (GET_FLAG_TYPE(op
) == SLJIT_SIG_GREATER
|| GET_FLAG_TYPE(op
) == SLJIT_SIG_LESS_EQUAL
)
278 FAIL_IF(push_inst(compiler
, SLT
| S(src2
) | T(src1
) | DA(OTHER_FLAG
), OTHER_FLAG
));
283 if (flags
& SRC2_IMM
) {
284 if (op
& SLJIT_SET_Z
)
285 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
286 if (!(flags
& UNUSED_DEST
))
287 return push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(-src2
), DR(dst
));
290 if (op
& SLJIT_SET_Z
)
291 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
292 if (!(flags
& UNUSED_DEST
))
293 return push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | D(dst
), DR(dst
));
295 return SLJIT_SUCCESS
;
298 is_overflow
= GET_FLAG_TYPE(op
) == SLJIT_OVERFLOW
;
299 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
301 if (flags
& SRC2_IMM
) {
304 FAIL_IF(push_inst(compiler
, OR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
306 FAIL_IF(push_inst(compiler
, NOR
| S(src1
) | T(src1
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
308 else if (op
& SLJIT_SET_Z
)
309 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(-src2
), EQUAL_FLAG
));
311 if (is_overflow
|| is_carry
)
312 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(OTHER_FLAG
) | IMM(src2
), OTHER_FLAG
));
313 /* dst may be the same as src1 or src2. */
314 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
315 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
319 FAIL_IF(push_inst(compiler
, XOR
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
320 else if (op
& SLJIT_SET_Z
)
321 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
323 if (is_overflow
|| is_carry
)
324 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(OTHER_FLAG
), OTHER_FLAG
));
325 /* dst may be the same as src1 or src2. */
326 if (!(flags
& UNUSED_DEST
) || (op
& VARIABLE_FLAG_MASK
))
327 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
331 return SLJIT_SUCCESS
;
332 FAIL_IF(push_inst(compiler
, SLL
| TA(OTHER_FLAG
) | D(TMP_REG1
) | SH_IMM(31), DR(TMP_REG1
)));
333 FAIL_IF(push_inst(compiler
, XOR
| S(TMP_REG1
) | TA(EQUAL_FLAG
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
334 FAIL_IF(push_inst(compiler
, XOR
| S(dst
) | TA(EQUAL_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
));
335 if (op
& SLJIT_SET_Z
)
336 FAIL_IF(push_inst(compiler
, ADDU
| S(dst
) | TA(0) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
337 return push_inst(compiler
, SRL
| TA(OTHER_FLAG
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
);
340 if ((flags
& SRC2_IMM
) && src2
== SIMM_MIN
) {
341 FAIL_IF(push_inst(compiler
, ADDIU
| SA(0) | T(TMP_REG2
) | IMM(src2
), DR(TMP_REG2
)));
346 is_carry
= GET_FLAG_TYPE(op
) == GET_FLAG_TYPE(SLJIT_SET_CARRY
);
348 if (flags
& SRC2_IMM
) {
350 FAIL_IF(push_inst(compiler
, SLTIU
| S(src1
) | TA(EQUAL_FLAG
) | IMM(src2
), EQUAL_FLAG
));
351 /* dst may be the same as src1 or src2. */
352 FAIL_IF(push_inst(compiler
, ADDIU
| S(src1
) | T(dst
) | IMM(-src2
), DR(dst
)));
356 FAIL_IF(push_inst(compiler
, SLTU
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
357 /* dst may be the same as src1 or src2. */
358 FAIL_IF(push_inst(compiler
, SUBU
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
362 FAIL_IF(push_inst(compiler
, SLTU
| S(dst
) | TA(OTHER_FLAG
) | D(TMP_REG1
), DR(TMP_REG1
)));
364 FAIL_IF(push_inst(compiler
, SUBU
| S(dst
) | TA(OTHER_FLAG
) | D(dst
), DR(dst
)));
365 return (is_carry
) ? push_inst(compiler
, OR
| SA(EQUAL_FLAG
) | T(TMP_REG1
) | DA(OTHER_FLAG
), OTHER_FLAG
) : SLJIT_SUCCESS
;
368 SLJIT_ASSERT(!(flags
& SRC2_IMM
));
370 if (GET_FLAG_TYPE(op
) != SLJIT_MUL_OVERFLOW
) {
371 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
372 return push_inst(compiler
, MUL
| S(src1
) | T(src2
) | D(dst
), DR(dst
));
373 #else /* SLJIT_MIPS_REV < 1 */
374 FAIL_IF(push_inst(compiler
, MULT
| S(src1
) | T(src2
), MOVABLE_INS
));
375 return push_inst(compiler
, MFLO
| D(dst
), DR(dst
));
376 #endif /* SLJIT_MIPS_REV >= 1 */
379 #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
380 FAIL_IF(push_inst(compiler
, MUL
| S(src1
) | T(src2
) | D(dst
), DR(dst
)));
381 FAIL_IF(push_inst(compiler
, MUH
| S(src1
) | T(src2
) | DA(EQUAL_FLAG
), EQUAL_FLAG
));
382 #else /* SLJIT_MIPS_REV < 6 */
383 FAIL_IF(push_inst(compiler
, MULT
| S(src1
) | T(src2
), MOVABLE_INS
));
384 FAIL_IF(push_inst(compiler
, MFHI
| DA(EQUAL_FLAG
), EQUAL_FLAG
));
385 FAIL_IF(push_inst(compiler
, MFLO
| D(dst
), DR(dst
)));
386 #endif /* SLJIT_MIPS_REV >= 6 */
387 FAIL_IF(push_inst(compiler
, SRA
| T(dst
) | DA(OTHER_FLAG
) | SH_IMM(31), OTHER_FLAG
));
388 return push_inst(compiler
, SUBU
| SA(EQUAL_FLAG
) | TA(OTHER_FLAG
) | DA(OTHER_FLAG
), OTHER_FLAG
);
391 EMIT_LOGICAL(ANDI
, AND
);
392 return SLJIT_SUCCESS
;
395 EMIT_LOGICAL(ORI
, OR
);
396 return SLJIT_SUCCESS
;
399 EMIT_LOGICAL(XORI
, XOR
);
400 return SLJIT_SUCCESS
;
403 EMIT_SHIFT(SLL
, SLLV
);
404 return SLJIT_SUCCESS
;
407 EMIT_SHIFT(SRL
, SRLV
);
408 return SLJIT_SUCCESS
;
411 EMIT_SHIFT(SRA
, SRAV
);
412 return SLJIT_SUCCESS
;
416 return SLJIT_SUCCESS
;
419 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 dst
, sljit_sw init_value
)
421 FAIL_IF(push_inst(compiler
, LUI
| T(dst
) | IMM(init_value
>> 16), DR(dst
)));
422 return push_inst(compiler
, ORI
| S(dst
) | T(dst
) | IMM(init_value
), DR(dst
));
425 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
427 sljit_ins
*inst
= (sljit_ins
*)addr
;
428 SLJIT_UNUSED_ARG(executable_offset
);
430 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 0);
431 SLJIT_ASSERT((inst
[0] & 0xffe00000) == LUI
&& (inst
[1] & 0xfc000000) == ORI
);
432 inst
[0] = (inst
[0] & 0xffff0000) | ((new_target
>> 16) & 0xffff);
433 inst
[1] = (inst
[1] & 0xffff0000) | (new_target
& 0xffff);
434 SLJIT_UPDATE_WX_FLAGS(inst
, inst
+ 2, 1);
435 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
436 SLJIT_CACHE_FLUSH(inst
, inst
+ 2);
439 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
441 sljit_set_jump_addr(addr
, new_constant
, executable_offset
);
444 static sljit_s32
call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
, sljit_ins
*ins_ptr
)
446 sljit_s32 stack_offset
= 0;
447 sljit_s32 arg_count
= 0;
448 sljit_s32 float_arg_count
= 0;
449 sljit_s32 word_arg_count
= 0;
451 sljit_s32 arg_count_save
, types_save
;
452 sljit_ins prev_ins
= NOP
;
456 SLJIT_ASSERT(reg_map
[TMP_REG1
] == 4 && freg_map
[TMP_FREG1
] == 12);
458 arg_types
>>= SLJIT_DEF_SHIFT
;
461 types
= (types
<< SLJIT_DEF_SHIFT
) | (arg_types
& SLJIT_DEF_MASK
);
463 switch (arg_types
& SLJIT_DEF_MASK
) {
464 case SLJIT_ARG_TYPE_F32
:
465 offsets
[arg_count
] = (sljit_u8
)stack_offset
;
467 if (word_arg_count
== 0 && arg_count
<= 1)
468 offsets
[arg_count
] = 254 + arg_count
;
470 stack_offset
+= sizeof(sljit_f32
);
474 case SLJIT_ARG_TYPE_F64
:
475 if (stack_offset
& 0x7)
476 stack_offset
+= sizeof(sljit_sw
);
477 offsets
[arg_count
] = (sljit_u8
)stack_offset
;
479 if (word_arg_count
== 0 && arg_count
<= 1)
480 offsets
[arg_count
] = 254 + arg_count
;
482 stack_offset
+= sizeof(sljit_f64
);
487 offsets
[arg_count
] = (sljit_u8
)stack_offset
;
488 stack_offset
+= sizeof(sljit_sw
);
494 arg_types
>>= SLJIT_DEF_SHIFT
;
497 /* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
498 if (stack_offset
> 16)
499 FAIL_IF(push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(-16), DR(SLJIT_SP
)));
502 arg_count_save
= arg_count
;
505 switch (types
& SLJIT_DEF_MASK
) {
506 case SLJIT_ARG_TYPE_F32
:
508 if (offsets
[arg_count
] < 254)
509 ins
= SWC1
| S(SLJIT_SP
) | FT(float_arg_count
) | IMM(offsets
[arg_count
]);
512 case SLJIT_ARG_TYPE_F64
:
514 if (offsets
[arg_count
] < 254)
515 ins
= SDC1
| S(SLJIT_SP
) | FT(float_arg_count
) | IMM(offsets
[arg_count
]);
519 if (offsets
[arg_count
- 1] >= 16)
520 ins
= SW
| S(SLJIT_SP
) | T(word_arg_count
) | IMM(offsets
[arg_count
- 1]);
521 else if (arg_count
!= word_arg_count
)
522 ins
= ADDU
| S(word_arg_count
) | TA(0) | DA(4 + (offsets
[arg_count
- 1] >> 2));
523 else if (arg_count
== 1)
524 ins
= ADDU
| S(SLJIT_R0
) | TA(0) | DA(4);
533 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
538 types
>>= SLJIT_DEF_SHIFT
;
542 arg_count
= arg_count_save
;
545 switch (types
& SLJIT_DEF_MASK
) {
546 case SLJIT_ARG_TYPE_F32
:
548 if (offsets
[arg_count
] == 254)
549 ins
= MOV_S
| FMT_S
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
550 else if (offsets
[arg_count
] < 16)
551 ins
= LW
| S(SLJIT_SP
) | TA(4 + (offsets
[arg_count
] >> 2)) | IMM(offsets
[arg_count
]);
553 case SLJIT_ARG_TYPE_F64
:
555 if (offsets
[arg_count
] == 254)
556 ins
= MOV_S
| FMT_D
| FS(SLJIT_FR0
) | FD(TMP_FREG1
);
557 else if (offsets
[arg_count
] < 16) {
559 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
560 prev_ins
= LW
| S(SLJIT_SP
) | TA(4 + (offsets
[arg_count
] >> 2)) | IMM(offsets
[arg_count
]);
561 ins
= LW
| S(SLJIT_SP
) | TA(5 + (offsets
[arg_count
] >> 2)) | IMM(offsets
[arg_count
] + sizeof(sljit_sw
));
571 FAIL_IF(push_inst(compiler
, prev_ins
, MOVABLE_INS
));
576 types
>>= SLJIT_DEF_SHIFT
;
581 return SLJIT_SUCCESS
;
584 static sljit_s32
post_call_with_args(struct sljit_compiler
*compiler
, sljit_s32 arg_types
)
586 sljit_s32 stack_offset
= 0;
588 arg_types
>>= SLJIT_DEF_SHIFT
;
591 switch (arg_types
& SLJIT_DEF_MASK
) {
592 case SLJIT_ARG_TYPE_F32
:
593 stack_offset
+= sizeof(sljit_f32
);
595 case SLJIT_ARG_TYPE_F64
:
596 if (stack_offset
& 0x7)
597 stack_offset
+= sizeof(sljit_sw
);
598 stack_offset
+= sizeof(sljit_f64
);
601 stack_offset
+= sizeof(sljit_sw
);
605 arg_types
>>= SLJIT_DEF_SHIFT
;
608 /* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
609 if (stack_offset
> 16)
610 return push_inst(compiler
, ADDIU
| S(SLJIT_SP
) | T(SLJIT_SP
) | IMM(16), DR(SLJIT_SP
));
612 return SLJIT_SUCCESS
;
615 SLJIT_API_FUNC_ATTRIBUTE
struct sljit_jump
* sljit_emit_call(struct sljit_compiler
*compiler
, sljit_s32 type
,
618 struct sljit_jump
*jump
;
622 CHECK_PTR(check_sljit_emit_call(compiler
, type
, arg_types
));
624 jump
= (struct sljit_jump
*)ensure_abuf(compiler
, sizeof(struct sljit_jump
));
626 set_jump(jump
, compiler
, type
& SLJIT_REWRITABLE_JUMP
);
629 PTR_FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
631 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
633 PTR_FAIL_IF(emit_const(compiler
, PIC_ADDR_REG
, 0));
635 jump
->flags
|= IS_JAL
| IS_CALL
;
636 PTR_FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
637 jump
->addr
= compiler
->size
;
638 PTR_FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
640 PTR_FAIL_IF(post_call_with_args(compiler
, arg_types
));
645 SLJIT_API_FUNC_ATTRIBUTE sljit_s32
sljit_emit_icall(struct sljit_compiler
*compiler
, sljit_s32 type
,
647 sljit_s32 src
, sljit_sw srcw
)
652 CHECK(check_sljit_emit_icall(compiler
, type
, arg_types
, src
, srcw
));
654 SLJIT_ASSERT(DR(PIC_ADDR_REG
) == 25 && PIC_ADDR_REG
== TMP_REG2
);
657 FAIL_IF(load_immediate(compiler
, DR(PIC_ADDR_REG
), srcw
));
658 else if (FAST_IS_REG(src
))
659 FAIL_IF(push_inst(compiler
, ADDU
| S(src
) | TA(0) | D(PIC_ADDR_REG
), DR(PIC_ADDR_REG
)));
660 else if (src
& SLJIT_MEM
) {
661 ADJUST_LOCAL_OFFSET(src
, srcw
);
662 FAIL_IF(emit_op_mem(compiler
, WORD_DATA
| LOAD_DATA
, DR(PIC_ADDR_REG
), src
, srcw
));
665 FAIL_IF(call_with_args(compiler
, arg_types
, &ins
));
667 /* Register input. */
668 FAIL_IF(push_inst(compiler
, JALR
| S(PIC_ADDR_REG
) | DA(RETURN_ADDR_REG
), UNMOVABLE_INS
));
669 FAIL_IF(push_inst(compiler
, ins
, UNMOVABLE_INS
));
670 return post_call_with_args(compiler
, arg_types
);