xref: /netbsd-src/sys/external/bsd/sljit/dist/sljit_src/sljitNativeMIPS_32.c (revision e35f55c6f088a9d849ac9e2c68755800c96229c2)
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