1 /*        $NetBSD: sljitNativeMIPS_32.c,v 1.4 2019/01/20 23:14:16 alnsn Exp $   */
2 
3 /*
4  *    Stack-less Just-In-Time compiler
5  *
6  *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without modification, are
9  * permitted provided that the following conditions are met:
10  *
11  *   1. Redistributions of source code must retain the above copyright notice, this list of
12  *      conditions and the following disclaimer.
13  *
14  *   2. Redistributions in binary form must reproduce the above copyright notice, this list
15  *      of conditions and the following disclaimer in the documentation and/or other materials
16  *      provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
21  * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* mips 32-bit arch dependent functions. */
30 
load_immediate(struct sljit_compiler * compiler,sljit_s32 dst_ar,sljit_sw imm)31 static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
32 {
33           if (!(imm & ~0xffff))
34                     return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
35 
36           if (imm < 0 && imm >= SIMM_MIN)
37                     return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
38 
39           FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
40           return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
41 }
42 
43 #define EMIT_LOGICAL(op_imm, op_norm) \
44           if (flags & SRC2_IMM) { \
45                     if (op & SLJIT_SET_Z) \
46                               FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
47                     if (!(flags & UNUSED_DEST)) \
48                               FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
49           } \
50           else { \
51                     if (op & SLJIT_SET_Z) \
52                               FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
53                     if (!(flags & UNUSED_DEST)) \
54                               FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
55           }
56 
57 #define EMIT_SHIFT(op_imm, op_v) \
58           if (flags & SRC2_IMM) { \
59                     if (op & SLJIT_SET_Z) \
60                               FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
61                     if (!(flags & UNUSED_DEST)) \
62                               FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
63           } \
64           else { \
65                     if (op & SLJIT_SET_Z) \
66                               FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
67                     if (!(flags & UNUSED_DEST)) \
68                               FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
69           }
70 
emit_single_op(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 flags,sljit_s32 dst,sljit_s32 src1,sljit_sw src2)71 static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
72           sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
73 {
74           sljit_s32 is_overflow, is_carry, is_handled;
75 
76           switch (GET_OPCODE(op)) {
77           case SLJIT_MOV:
78           case SLJIT_MOV_U32:
79           case SLJIT_MOV_S32:
80           case SLJIT_MOV_P:
81                     SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
82                     if (dst != src2)
83                               return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
84                     return SLJIT_SUCCESS;
85 
86           case SLJIT_MOV_U8:
87           case SLJIT_MOV_S8:
88                     SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
89                     if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
90                               if (op == SLJIT_MOV_S8) {
91 #if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
92                                         return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
93 #else
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
97                               }
98                               return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
99                     }
100                     else {
101                               SLJIT_ASSERT(dst == src2);
102                     }
103                     return SLJIT_SUCCESS;
104 
105           case SLJIT_MOV_U16:
106           case SLJIT_MOV_S16:
107                     SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
108                     if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
109                               if (op == SLJIT_MOV_S16) {
110 #if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
111                                         return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
112 #else
113                                         FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
114                                         return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
115 #endif
116                               }
117                               return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
118                     }
119                     else {
120                               SLJIT_ASSERT(dst == src2);
121                     }
122                     return SLJIT_SUCCESS;
123 
124           case SLJIT_NOT:
125                     SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
126                     if (op & SLJIT_SET_Z)
127                               FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
128                     if (!(flags & UNUSED_DEST))
129                               FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
130                     return SLJIT_SUCCESS;
131 
132           case SLJIT_CLZ:
133                     SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
134 #if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
135                     if (op & SLJIT_SET_Z)
136                               FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
137                     if (!(flags & UNUSED_DEST))
138                               FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
139 #else
140                     if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
141                               FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
142                               return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
143                     }
144                     /* Nearly all instructions are unmovable in the following sequence. */
145                     FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
146                     /* Check zero. */
147                     FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
148                     FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
149                     FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
150                     /* Loop for searching the highest bit. */
151                     FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
152                     FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
153                     FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
154                     if (op & SLJIT_SET_Z)
155                               return push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
156 #endif
157                     return SLJIT_SUCCESS;
158 
159           case SLJIT_ADD:
160                     is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
161                     is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
162 
163                     if (flags & SRC2_IMM) {
164                               if (is_overflow) {
165                                         if (src2 >= 0)
166                                                   FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
167                                         else
168                                                   FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
169                               }
170                               else if (op & SLJIT_SET_Z)
171                                         FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
172 
173                               if (is_overflow || is_carry) {
174                                         if (src2 >= 0)
175                                                   FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
176                                         else {
177                                                   FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
178                                                   FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
179                                         }
180                               }
181                               /* dst may be the same as src1 or src2. */
182                               if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
183                                         FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
184                     }
185                     else {
186                               if (is_overflow)
187                                         FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
188                               else if (op & SLJIT_SET_Z)
189                                         FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
190 
191                               if (is_overflow || is_carry)
192                                         FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
193                               /* dst may be the same as src1 or src2. */
194                               if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
195                                         FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
196                     }
197 
198                     /* a + b >= a | b (otherwise, the carry should be set to 1). */
199                     if (is_overflow || is_carry)
200                               FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
201                     if (!is_overflow)
202                               return SLJIT_SUCCESS;
203                     FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
204                     FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
205                     FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
206                     if (op & SLJIT_SET_Z)
207                               FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
208                     return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
209 
210           case SLJIT_ADDC:
211                     is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
212 
213                     if (flags & SRC2_IMM) {
214                               if (is_carry) {
215                                         if (src2 >= 0)
216                                                   FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
217                                         else {
218                                                   FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
219                                                   FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
220                                         }
221                               }
222                               FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
223                     } else {
224                               if (is_carry)
225                                         FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
226                               /* dst may be the same as src1 or src2. */
227                               FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
228                     }
229                     if (is_carry)
230                               FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
231 
232                     FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
233                     if (!is_carry)
234                               return SLJIT_SUCCESS;
235 
236                     /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
237                     FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
238                     /* Set carry flag. */
239                     return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
240 
241           case SLJIT_SUB:
242                     if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
243                               FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
244                               src2 = TMP_REG2;
245                               flags &= ~SRC2_IMM;
246                     }
247 
248                     is_handled = 0;
249 
250                     if (flags & SRC2_IMM) {
251                               if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
252                                         FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
253                                         is_handled = 1;
254                               }
255                               else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
256                                         FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
257                                         is_handled = 1;
258                               }
259                     }
260 
261                     if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
262                               is_handled = 1;
263 
264                               if (flags & SRC2_IMM) {
265                                         FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
266                                         src2 = TMP_REG2;
267                                         flags &= ~SRC2_IMM;
268                               }
269 
270                               if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
271                                         FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
272                               }
273                               else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
274                               {
275                                         FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
276                               }
277                               else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
278                                         FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
279                               }
280                               else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
281                               {
282                                         FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
283                               }
284                     }
285 
286                     if (is_handled) {
287                               if (flags & SRC2_IMM) {
288                                         if (op & SLJIT_SET_Z)
289                                                   FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
290                                         if (!(flags & UNUSED_DEST))
291                                                   return push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst));
292                               }
293                               else {
294                                         if (op & SLJIT_SET_Z)
295                                                   FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
296                                         if (!(flags & UNUSED_DEST))
297                                                   return push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst));
298                               }
299                               return SLJIT_SUCCESS;
300                     }
301 
302                     is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
303                     is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
304 
305                     if (flags & SRC2_IMM) {
306                               if (is_overflow) {
307                                         if (src2 >= 0)
308                                                   FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
309                                         else
310                                                   FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
311                               }
312                               else if (op & SLJIT_SET_Z)
313                                         FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
314 
315                               if (is_overflow || is_carry)
316                                         FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
317                               /* dst may be the same as src1 or src2. */
318                               if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
319                                         FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
320                     }
321                     else {
322                               if (is_overflow)
323                                         FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
324                               else if (op & SLJIT_SET_Z)
325                                         FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
326 
327                               if (is_overflow || is_carry)
328                                         FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
329                               /* dst may be the same as src1 or src2. */
330                               if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
331                                         FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
332                     }
333 
334                     if (!is_overflow)
335                               return SLJIT_SUCCESS;
336                     FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
337                     FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
338                     FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
339                     if (op & SLJIT_SET_Z)
340                               FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
341                     return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
342 
343           case SLJIT_SUBC:
344                     if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
345                               FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
346                               src2 = TMP_REG2;
347                               flags &= ~SRC2_IMM;
348                     }
349 
350                     is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
351 
352                     if (flags & SRC2_IMM) {
353                               if (is_carry)
354                                         FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
355                               /* dst may be the same as src1 or src2. */
356                               FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
357                     }
358                     else {
359                               if (is_carry)
360                                         FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
361                               /* dst may be the same as src1 or src2. */
362                               FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
363                     }
364 
365                     if (is_carry)
366                               FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
367 
368                     FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
369                     return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
370 
371           case SLJIT_MUL:
372                     SLJIT_ASSERT(!(flags & SRC2_IMM));
373 
374                     if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW && GET_FLAG_TYPE(op) != SLJIT_MUL_NOT_OVERFLOW) {
375 #if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
376                               return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
377 #else
378                               FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
379                               return push_inst(compiler, MFLO | D(dst), DR(dst));
380 #endif
381                     }
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                     FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
386                     return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
387 
388           case SLJIT_AND:
389                     EMIT_LOGICAL(ANDI, AND);
390                     return SLJIT_SUCCESS;
391 
392           case SLJIT_OR:
393                     EMIT_LOGICAL(ORI, OR);
394                     return SLJIT_SUCCESS;
395 
396           case SLJIT_XOR:
397                     EMIT_LOGICAL(XORI, XOR);
398                     return SLJIT_SUCCESS;
399 
400           case SLJIT_SHL:
401                     EMIT_SHIFT(SLL, SLLV);
402                     return SLJIT_SUCCESS;
403 
404           case SLJIT_LSHR:
405                     EMIT_SHIFT(SRL, SRLV);
406                     return SLJIT_SUCCESS;
407 
408           case SLJIT_ASHR:
409                     EMIT_SHIFT(SRA, SRAV);
410                     return SLJIT_SUCCESS;
411           }
412 
413           SLJIT_UNREACHABLE();
414           return SLJIT_SUCCESS;
415 }
416 
emit_const(struct sljit_compiler * compiler,sljit_s32 dst,sljit_sw init_value)417 static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
418 {
419           FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
420           return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
421 }
422 
sljit_set_jump_addr(sljit_uw addr,sljit_uw new_target,sljit_sw executable_offset)423 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
424 {
425           sljit_ins *inst = (sljit_ins *)addr;
426 
427           inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
428           inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
429           inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
430           SLJIT_CACHE_FLUSH(inst, inst + 2);
431 }
432 
sljit_set_const(sljit_uw addr,sljit_sw new_constant,sljit_sw executable_offset)433 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
434 {
435           sljit_ins *inst = (sljit_ins *)addr;
436 
437           inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
438           inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
439           inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
440           SLJIT_CACHE_FLUSH(inst, inst + 2);
441 }
442