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