new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / external / pcre2-10.32 / src / sljit / sljitNativeMIPS_32.c
1 /*
2  *    Stack-less Just-In-Time compiler
3  *
4  *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification, are
7  * permitted provided that the following conditions are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright notice, this list of
10  *      conditions and the following disclaimer.
11  *
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.
15  *
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.
25  */
26
27 /* mips 32-bit arch dependent functions. */
28
29 static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
30 {
31         if (!(imm & ~0xffff))
32                 return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
33
34         if (imm < 0 && imm >= SIMM_MIN)
35                 return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
36
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;
39 }
40
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))); \
47         } \
48         else { \
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))); \
53         }
54
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))); \
61         } \
62         else { \
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))); \
67         }
68
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)
71 {
72         sljit_s32 is_overflow, is_carry, is_handled;
73
74         switch (GET_OPCODE(op)) {
75         case SLJIT_MOV:
76         case SLJIT_MOV_U32:
77         case SLJIT_MOV_S32:
78         case SLJIT_MOV_P:
79                 SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
80                 if (dst != src2)
81                         return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
82                 return SLJIT_SUCCESS;
83
84         case SLJIT_MOV_U8:
85         case SLJIT_MOV_S8:
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_R1 && SLJIT_MIPS_R1)
90                                 return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
91 #else
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
95                         }
96                         return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
97                 }
98                 else {
99                         SLJIT_ASSERT(dst == src2);
100                 }
101                 return SLJIT_SUCCESS;
102
103         case SLJIT_MOV_U16:
104         case SLJIT_MOV_S16:
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_R1 && SLJIT_MIPS_R1)
109                                 return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
110 #else
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
114                         }
115                         return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
116                 }
117                 else {
118                         SLJIT_ASSERT(dst == src2);
119                 }
120                 return SLJIT_SUCCESS;
121
122         case SLJIT_NOT:
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;
129
130         case SLJIT_CLZ:
131                 SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
132 #if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
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
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);
141                 }
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)));
144                 /* Check zero. */
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
153                 return SLJIT_SUCCESS;
154
155         case SLJIT_ADD:
156                 is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
157                 is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
158
159                 if (flags & SRC2_IMM) {
160                         if (is_overflow) {
161                                 if (src2 >= 0)
162                                         FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
163                                 else
164                                         FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
165                         }
166                         else if (op & SLJIT_SET_Z)
167                                 FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
168
169                         if (is_overflow || is_carry) {
170                                 if (src2 >= 0)
171                                         FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
172                                 else {
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));
175                                 }
176                         }
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)));
180                 }
181                 else {
182                         if (is_overflow)
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));
186
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)));
192                 }
193
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));
197                 if (!is_overflow)
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);
205
206         case SLJIT_ADDC:
207                 is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
208
209                 if (flags & SRC2_IMM) {
210                         if (is_carry) {
211                                 if (src2 >= 0)
212                                         FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
213                                 else {
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));
216                                 }
217                         }
218                         FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
219                 } else {
220                         if (is_carry)
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)));
224                 }
225                 if (is_carry)
226                         FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
227
228                 FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
229                 if (!is_carry)
230                         return SLJIT_SUCCESS;
231
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);
236
237         case SLJIT_SUB:
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)));
240                         src2 = TMP_REG2;
241                         flags &= ~SRC2_IMM;
242                 }
243
244                 is_handled = 0;
245
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));
249                                 is_handled = 1;
250                         }
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));
253                                 is_handled = 1;
254                         }
255                 }
256
257                 if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
258                         is_handled = 1;
259
260                         if (flags & SRC2_IMM) {
261                                 FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
262                                 src2 = TMP_REG2;
263                                 flags &= ~SRC2_IMM;
264                         }
265
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));
268                         }
269                         else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
270                         {
271                                 FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
272                         }
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));
275                         }
276                         else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
277                         {
278                                 FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
279                         }
280                 }
281
282                 if (is_handled) {
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));
288                         }
289                         else {
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));
294                         }
295                         return SLJIT_SUCCESS;
296                 }
297
298                 is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
299                 is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
300
301                 if (flags & SRC2_IMM) {
302                         if (is_overflow) {
303                                 if (src2 >= 0)
304                                         FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
305                                 else
306                                         FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
307                         }
308                         else if (op & SLJIT_SET_Z)
309                                 FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
310
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)));
316                 }
317                 else {
318                         if (is_overflow)
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));
322
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)));
328                 }
329
330                 if (!is_overflow)
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);
338
339         case SLJIT_SUBC:
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)));
342                         src2 = TMP_REG2;
343                         flags &= ~SRC2_IMM;
344                 }
345
346                 is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
347
348                 if (flags & SRC2_IMM) {
349                         if (is_carry)
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)));
353                 }
354                 else {
355                         if (is_carry)
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)));
359                 }
360
361                 if (is_carry)
362                         FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
363
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;
366
367         case SLJIT_MUL:
368                 SLJIT_ASSERT(!(flags & SRC2_IMM));
369
370                 if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
371 #if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
372                         return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
373 #else
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
377                 }
378                 FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
379                 FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
380                 FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
381                 FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
382                 return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
383
384         case SLJIT_AND:
385                 EMIT_LOGICAL(ANDI, AND);
386                 return SLJIT_SUCCESS;
387
388         case SLJIT_OR:
389                 EMIT_LOGICAL(ORI, OR);
390                 return SLJIT_SUCCESS;
391
392         case SLJIT_XOR:
393                 EMIT_LOGICAL(XORI, XOR);
394                 return SLJIT_SUCCESS;
395
396         case SLJIT_SHL:
397                 EMIT_SHIFT(SLL, SLLV);
398                 return SLJIT_SUCCESS;
399
400         case SLJIT_LSHR:
401                 EMIT_SHIFT(SRL, SRLV);
402                 return SLJIT_SUCCESS;
403
404         case SLJIT_ASHR:
405                 EMIT_SHIFT(SRA, SRAV);
406                 return SLJIT_SUCCESS;
407         }
408
409         SLJIT_UNREACHABLE();
410         return SLJIT_SUCCESS;
411 }
412
413 static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
414 {
415         FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
416         return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
417 }
418
419 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
420 {
421         sljit_ins *inst = (sljit_ins *)addr;
422
423         inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
424         inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
425         inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
426         SLJIT_CACHE_FLUSH(inst, inst + 2);
427 }
428
429 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
430 {
431         sljit_ins *inst = (sljit_ins *)addr;
432
433         inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
434         inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
435         inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
436         SLJIT_CACHE_FLUSH(inst, inst + 2);
437 }
438
439 static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr)
440 {
441         sljit_s32 stack_offset = 0;
442         sljit_s32 arg_count = 0;
443         sljit_s32 float_arg_count = 0;
444         sljit_s32 word_arg_count = 0;
445         sljit_s32 types = 0;
446         sljit_s32 arg_count_save, types_save;
447         sljit_ins prev_ins = NOP;
448         sljit_ins ins = NOP;
449         sljit_u8 offsets[4];
450
451         SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
452
453         arg_types >>= SLJIT_DEF_SHIFT;
454
455         while (arg_types) {
456                 types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
457
458                 switch (arg_types & SLJIT_DEF_MASK) {
459                 case SLJIT_ARG_TYPE_F32:
460                         offsets[arg_count] = (sljit_u8)stack_offset;
461
462                         if (word_arg_count == 0 && arg_count <= 1)
463                                 offsets[arg_count] = 254 + arg_count;
464
465                         stack_offset += sizeof(sljit_f32);
466                         arg_count++;
467                         float_arg_count++;
468                         break;
469                 case SLJIT_ARG_TYPE_F64:
470                         if (stack_offset & 0x7)
471                                 stack_offset += sizeof(sljit_sw);
472                         offsets[arg_count] = (sljit_u8)stack_offset;
473
474                         if (word_arg_count == 0 && arg_count <= 1)
475                                 offsets[arg_count] = 254 + arg_count;
476
477                         stack_offset += sizeof(sljit_f64);
478                         arg_count++;
479                         float_arg_count++;
480                         break;
481                 default:
482                         offsets[arg_count] = (sljit_u8)stack_offset;
483                         stack_offset += sizeof(sljit_sw);
484                         arg_count++;
485                         word_arg_count++;
486                         break;
487                 }
488
489                 arg_types >>= SLJIT_DEF_SHIFT;
490         }
491
492         /* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
493         if (stack_offset > 16)
494                 FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-16), DR(SLJIT_SP)));
495
496         types_save = types;
497         arg_count_save = arg_count;
498
499         while (types) {
500                 switch (types & SLJIT_DEF_MASK) {
501                 case SLJIT_ARG_TYPE_F32:
502                         arg_count--;
503                         if (offsets[arg_count] < 254)
504                                 ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(offsets[arg_count]);
505                         float_arg_count--;
506                         break;
507                 case SLJIT_ARG_TYPE_F64:
508                         arg_count--;
509                         if (offsets[arg_count] < 254)
510                                 ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(offsets[arg_count]);
511                         float_arg_count--;
512                         break;
513                 default:
514                         if (offsets[arg_count - 1] >= 16)
515                                 ins = SW | S(SLJIT_SP) | T(word_arg_count) | IMM(offsets[arg_count - 1]);
516                         else if (arg_count != word_arg_count)
517                                 ins = ADDU | S(word_arg_count) | TA(0) | DA(4 + (offsets[arg_count - 1] >> 2));
518                         else if (arg_count == 1)
519                                 ins = ADDU | S(SLJIT_R0) | TA(0) | DA(4);
520
521                         arg_count--;
522                         word_arg_count--;
523                         break;
524                 }
525
526                 if (ins != NOP) {
527                         if (prev_ins != NOP)
528                                 FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
529                         prev_ins = ins;
530                         ins = NOP;
531                 }
532
533                 types >>= SLJIT_DEF_SHIFT;
534         }
535
536         types = types_save;
537         arg_count = arg_count_save;
538
539         while (types) {
540                 switch (types & SLJIT_DEF_MASK) {
541                 case SLJIT_ARG_TYPE_F32:
542                         arg_count--;
543                         if (offsets[arg_count] == 254)
544                                 ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
545                         else if (offsets[arg_count] < 16)
546                                 ins = LW | S(SLJIT_SP) | TA(4 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count]);
547                         break;
548                 case SLJIT_ARG_TYPE_F64:
549                         arg_count--;
550                         if (offsets[arg_count] == 254)
551                                 ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
552                         else if (offsets[arg_count] < 16) {
553                                 if (prev_ins != NOP)
554                                         FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
555                                 prev_ins = LW | S(SLJIT_SP) | TA(4 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count]);
556                                 ins = LW | S(SLJIT_SP) | TA(5 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count] + sizeof(sljit_sw));
557                         }
558                         break;
559                 default:
560                         arg_count--;
561                         break;
562                 }
563
564                 if (ins != NOP) {
565                         if (prev_ins != NOP)
566                                 FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
567                         prev_ins = ins;
568                         ins = NOP;
569                 }
570
571                 types >>= SLJIT_DEF_SHIFT;
572         }
573
574         *ins_ptr = prev_ins;
575
576         return SLJIT_SUCCESS;
577 }
578
579 static sljit_s32 post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
580 {
581         sljit_s32 stack_offset = 0;
582
583         arg_types >>= SLJIT_DEF_SHIFT;
584
585         while (arg_types) {
586                 switch (arg_types & SLJIT_DEF_MASK) {
587                 case SLJIT_ARG_TYPE_F32:
588                         stack_offset += sizeof(sljit_f32);
589                         break;
590                 case SLJIT_ARG_TYPE_F64:
591                         if (stack_offset & 0x7)
592                                 stack_offset += sizeof(sljit_sw);
593                         stack_offset += sizeof(sljit_f64);
594                         break;
595                 default:
596                         stack_offset += sizeof(sljit_sw);
597                         break;
598                 }
599
600                 arg_types >>= SLJIT_DEF_SHIFT;
601         }
602
603         /* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
604         if (stack_offset > 16)
605                 return push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(16), DR(SLJIT_SP));
606
607         return SLJIT_SUCCESS;
608 }
609
610 SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
611         sljit_s32 arg_types)
612 {
613         struct sljit_jump *jump;
614         sljit_ins ins;
615
616         CHECK_ERROR_PTR();
617         CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
618
619         jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
620         PTR_FAIL_IF(!jump);
621         set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
622         type &= 0xff;
623
624         PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins));
625
626         SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
627
628         PTR_FAIL_IF(emit_const(compiler, PIC_ADDR_REG, 0));
629
630         jump->flags |= IS_JAL | IS_CALL;
631         PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
632         jump->addr = compiler->size;
633         PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
634
635         PTR_FAIL_IF(post_call_with_args(compiler, arg_types));
636
637         return jump;
638 }
639
640 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
641         sljit_s32 arg_types,
642         sljit_s32 src, sljit_sw srcw)
643 {
644         sljit_ins ins;
645
646         CHECK_ERROR();
647         CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
648
649         SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
650
651         if (src & SLJIT_IMM)
652                 FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
653         else if (FAST_IS_REG(src))
654                 FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
655         else if (src & SLJIT_MEM) {
656                 ADJUST_LOCAL_OFFSET(src, srcw);
657                 FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
658         }
659
660         FAIL_IF(call_with_args(compiler, arg_types, &ins));
661
662         /* Register input. */
663         FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
664         FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
665         return post_call_with_args(compiler, arg_types);
666 }