xref: /aosp_15_r20/external/pcre/src/sljit/sljitNativeMIPS_32.c (revision 22dc650d8ae982c6770746019a6f94af92b0f024)
1*22dc650dSSadaf Ebrahimi /*
2*22dc650dSSadaf Ebrahimi  *    Stack-less Just-In-Time compiler
3*22dc650dSSadaf Ebrahimi  *
4*22dc650dSSadaf Ebrahimi  *    Copyright Zoltan Herczeg ([email protected]). All rights reserved.
5*22dc650dSSadaf Ebrahimi  *
6*22dc650dSSadaf Ebrahimi  * Redistribution and use in source and binary forms, with or without modification, are
7*22dc650dSSadaf Ebrahimi  * permitted provided that the following conditions are met:
8*22dc650dSSadaf Ebrahimi  *
9*22dc650dSSadaf Ebrahimi  *   1. Redistributions of source code must retain the above copyright notice, this list of
10*22dc650dSSadaf Ebrahimi  *      conditions and the following disclaimer.
11*22dc650dSSadaf Ebrahimi  *
12*22dc650dSSadaf Ebrahimi  *   2. Redistributions in binary form must reproduce the above copyright notice, this list
13*22dc650dSSadaf Ebrahimi  *      of conditions and the following disclaimer in the documentation and/or other materials
14*22dc650dSSadaf Ebrahimi  *      provided with the distribution.
15*22dc650dSSadaf Ebrahimi  *
16*22dc650dSSadaf Ebrahimi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17*22dc650dSSadaf Ebrahimi  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*22dc650dSSadaf Ebrahimi  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19*22dc650dSSadaf Ebrahimi  * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*22dc650dSSadaf Ebrahimi  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21*22dc650dSSadaf Ebrahimi  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22*22dc650dSSadaf Ebrahimi  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23*22dc650dSSadaf Ebrahimi  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24*22dc650dSSadaf Ebrahimi  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*22dc650dSSadaf Ebrahimi  */
26*22dc650dSSadaf Ebrahimi 
27*22dc650dSSadaf Ebrahimi /* mips 32-bit arch dependent functions. */
28*22dc650dSSadaf Ebrahimi 
emit_copysign(struct sljit_compiler * compiler,sljit_s32 op,sljit_sw src1,sljit_sw src2,sljit_sw dst)29*22dc650dSSadaf Ebrahimi static sljit_s32 emit_copysign(struct sljit_compiler *compiler, sljit_s32 op,
30*22dc650dSSadaf Ebrahimi 		sljit_sw src1, sljit_sw src2, sljit_sw dst)
31*22dc650dSSadaf Ebrahimi {
32*22dc650dSSadaf Ebrahimi 	int is_32 = (op & SLJIT_32);
33*22dc650dSSadaf Ebrahimi 	sljit_ins mfhc = MFC1, mthc = MTC1;
34*22dc650dSSadaf Ebrahimi 	sljit_ins src1_r = FS(src1), src2_r = FS(src2), dst_r = FS(dst);
35*22dc650dSSadaf Ebrahimi 
36*22dc650dSSadaf Ebrahimi 	if (!is_32) {
37*22dc650dSSadaf Ebrahimi 		switch (cpu_feature_list & CPU_FEATURE_FR) {
38*22dc650dSSadaf Ebrahimi #if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
39*22dc650dSSadaf Ebrahimi 		case CPU_FEATURE_FR:
40*22dc650dSSadaf Ebrahimi 			mfhc = MFHC1;
41*22dc650dSSadaf Ebrahimi 			mthc = MTHC1;
42*22dc650dSSadaf Ebrahimi 			break;
43*22dc650dSSadaf Ebrahimi #endif /* SLJIT_MIPS_REV >= 2 */
44*22dc650dSSadaf Ebrahimi 		default:
45*22dc650dSSadaf Ebrahimi 			src1_r |= (1 << 11);
46*22dc650dSSadaf Ebrahimi 			src2_r |= (1 << 11);
47*22dc650dSSadaf Ebrahimi 			dst_r |= (1 << 11);
48*22dc650dSSadaf Ebrahimi 			break;
49*22dc650dSSadaf Ebrahimi 		}
50*22dc650dSSadaf Ebrahimi 	}
51*22dc650dSSadaf Ebrahimi 
52*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG1) | src1_r, DR(TMP_REG1)));
53*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG2) | src2_r, DR(TMP_REG2)));
54*22dc650dSSadaf Ebrahimi 	if (!is_32 && src1 != dst)
55*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(src1) | FD(dst), MOVABLE_INS));
56*22dc650dSSadaf Ebrahimi #if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
57*22dc650dSSadaf Ebrahimi 	else
58*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
59*22dc650dSSadaf Ebrahimi #endif /* MIPS III */
60*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, XOR | T(TMP_REG1) | D(TMP_REG2) | S(TMP_REG2), DR(TMP_REG2)));
61*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, SRL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
62*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, SLL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
63*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, XOR | T(TMP_REG2) | D(TMP_REG1) | S(TMP_REG1), DR(TMP_REG1)));
64*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, mthc | T(TMP_REG1) | dst_r, MOVABLE_INS));
65*22dc650dSSadaf Ebrahimi #if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
66*22dc650dSSadaf Ebrahimi 	if (mthc == MTC1)
67*22dc650dSSadaf Ebrahimi 		return push_inst(compiler, NOP, UNMOVABLE_INS);
68*22dc650dSSadaf Ebrahimi #endif /* MIPS III */
69*22dc650dSSadaf Ebrahimi 	return SLJIT_SUCCESS;
70*22dc650dSSadaf Ebrahimi }
71*22dc650dSSadaf Ebrahimi 
load_immediate(struct sljit_compiler * compiler,sljit_s32 dst_ar,sljit_sw imm)72*22dc650dSSadaf Ebrahimi static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
73*22dc650dSSadaf Ebrahimi {
74*22dc650dSSadaf Ebrahimi 	if (!(imm & ~0xffff))
75*22dc650dSSadaf Ebrahimi 		return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
76*22dc650dSSadaf Ebrahimi 
77*22dc650dSSadaf Ebrahimi 	if (imm < 0 && imm >= SIMM_MIN)
78*22dc650dSSadaf Ebrahimi 		return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
79*22dc650dSSadaf Ebrahimi 
80*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
81*22dc650dSSadaf Ebrahimi 	return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
82*22dc650dSSadaf Ebrahimi }
83*22dc650dSSadaf Ebrahimi 
emit_const(struct sljit_compiler * compiler,sljit_s32 dst,sljit_sw init_value)84*22dc650dSSadaf Ebrahimi static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
85*22dc650dSSadaf Ebrahimi {
86*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
87*22dc650dSSadaf Ebrahimi 	return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
88*22dc650dSSadaf Ebrahimi }
89*22dc650dSSadaf Ebrahimi 
sljit_emit_fset64(struct sljit_compiler * compiler,sljit_s32 freg,sljit_f64 value)90*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
91*22dc650dSSadaf Ebrahimi 	sljit_s32 freg, sljit_f64 value)
92*22dc650dSSadaf Ebrahimi {
93*22dc650dSSadaf Ebrahimi 	union {
94*22dc650dSSadaf Ebrahimi 		struct {
95*22dc650dSSadaf Ebrahimi #if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
96*22dc650dSSadaf Ebrahimi 			sljit_s32 lo;
97*22dc650dSSadaf Ebrahimi 			sljit_s32 hi;
98*22dc650dSSadaf Ebrahimi #else /* !SLJIT_LITTLE_ENDIAN */
99*22dc650dSSadaf Ebrahimi 			sljit_s32 hi;
100*22dc650dSSadaf Ebrahimi 			sljit_s32 lo;
101*22dc650dSSadaf Ebrahimi #endif /* SLJIT_LITTLE_ENDIAN */
102*22dc650dSSadaf Ebrahimi 		} bin;
103*22dc650dSSadaf Ebrahimi 		sljit_f64 value;
104*22dc650dSSadaf Ebrahimi 	} u;
105*22dc650dSSadaf Ebrahimi 
106*22dc650dSSadaf Ebrahimi 	CHECK_ERROR();
107*22dc650dSSadaf Ebrahimi 	CHECK(check_sljit_emit_fset64(compiler, freg, value));
108*22dc650dSSadaf Ebrahimi 
109*22dc650dSSadaf Ebrahimi 	u.value = value;
110*22dc650dSSadaf Ebrahimi 
111*22dc650dSSadaf Ebrahimi 	if (u.bin.lo != 0)
112*22dc650dSSadaf Ebrahimi 		FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.bin.lo));
113*22dc650dSSadaf Ebrahimi 	if (u.bin.hi != 0)
114*22dc650dSSadaf Ebrahimi 		FAIL_IF(load_immediate(compiler, DR(TMP_REG2), u.bin.hi));
115*22dc650dSSadaf Ebrahimi 
116*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, MTC1 | (u.bin.lo != 0 ? T(TMP_REG1) : TA(0)) | FS(freg), MOVABLE_INS));
117*22dc650dSSadaf Ebrahimi 	switch (cpu_feature_list & CPU_FEATURE_FR) {
118*22dc650dSSadaf Ebrahimi #if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
119*22dc650dSSadaf Ebrahimi 	case CPU_FEATURE_FR:
120*22dc650dSSadaf Ebrahimi 		return push_inst(compiler, MTHC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg), MOVABLE_INS);
121*22dc650dSSadaf Ebrahimi #endif /* SLJIT_MIPS_REV >= 2 */
122*22dc650dSSadaf Ebrahimi 	default:
123*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, MTC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg) | (1 << 11), MOVABLE_INS));
124*22dc650dSSadaf Ebrahimi 		break;
125*22dc650dSSadaf Ebrahimi 	}
126*22dc650dSSadaf Ebrahimi #if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
127*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
128*22dc650dSSadaf Ebrahimi #endif /* MIPS III */
129*22dc650dSSadaf Ebrahimi 	return SLJIT_SUCCESS;
130*22dc650dSSadaf Ebrahimi }
131*22dc650dSSadaf Ebrahimi 
sljit_emit_fcopy(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 freg,sljit_s32 reg)132*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
133*22dc650dSSadaf Ebrahimi 	sljit_s32 freg, sljit_s32 reg)
134*22dc650dSSadaf Ebrahimi {
135*22dc650dSSadaf Ebrahimi 	sljit_s32 reg2 = 0;
136*22dc650dSSadaf Ebrahimi 	sljit_ins inst = FS(freg);
137*22dc650dSSadaf Ebrahimi 	sljit_ins mthc = MTC1, mfhc = MFC1;
138*22dc650dSSadaf Ebrahimi 	int is_32 = (op & SLJIT_32);
139*22dc650dSSadaf Ebrahimi 
140*22dc650dSSadaf Ebrahimi 	CHECK_ERROR();
141*22dc650dSSadaf Ebrahimi 	CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
142*22dc650dSSadaf Ebrahimi 
143*22dc650dSSadaf Ebrahimi 	op = GET_OPCODE(op);
144*22dc650dSSadaf Ebrahimi 	if (reg & REG_PAIR_MASK) {
145*22dc650dSSadaf Ebrahimi 		reg2 = REG_PAIR_SECOND(reg);
146*22dc650dSSadaf Ebrahimi 		reg = REG_PAIR_FIRST(reg);
147*22dc650dSSadaf Ebrahimi 
148*22dc650dSSadaf Ebrahimi 		inst |= T(reg2);
149*22dc650dSSadaf Ebrahimi 
150*22dc650dSSadaf Ebrahimi 		if (op == SLJIT_COPY_TO_F64)
151*22dc650dSSadaf Ebrahimi 			FAIL_IF(push_inst(compiler, MTC1 | inst, MOVABLE_INS));
152*22dc650dSSadaf Ebrahimi 		else
153*22dc650dSSadaf Ebrahimi 			FAIL_IF(push_inst(compiler, MFC1 | inst, DR(reg2)));
154*22dc650dSSadaf Ebrahimi 
155*22dc650dSSadaf Ebrahimi 		inst = FS(freg) | (1 << 11);
156*22dc650dSSadaf Ebrahimi #if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
157*22dc650dSSadaf Ebrahimi 		if (cpu_feature_list & CPU_FEATURE_FR) {
158*22dc650dSSadaf Ebrahimi 			mthc = MTHC1;
159*22dc650dSSadaf Ebrahimi 			mfhc = MFHC1;
160*22dc650dSSadaf Ebrahimi 			inst = FS(freg);
161*22dc650dSSadaf Ebrahimi 		}
162*22dc650dSSadaf Ebrahimi #endif /* SLJIT_MIPS_REV >= 2 */
163*22dc650dSSadaf Ebrahimi 	}
164*22dc650dSSadaf Ebrahimi 
165*22dc650dSSadaf Ebrahimi 	inst |= T(reg);
166*22dc650dSSadaf Ebrahimi 	if (!is_32 && !reg2) {
167*22dc650dSSadaf Ebrahimi 		switch (cpu_feature_list & CPU_FEATURE_FR) {
168*22dc650dSSadaf Ebrahimi #if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
169*22dc650dSSadaf Ebrahimi 		case CPU_FEATURE_FR:
170*22dc650dSSadaf Ebrahimi 			mthc = MTHC1;
171*22dc650dSSadaf Ebrahimi 			mfhc = MFHC1;
172*22dc650dSSadaf Ebrahimi 			break;
173*22dc650dSSadaf Ebrahimi #endif /* SLJIT_MIPS_REV >= 2 */
174*22dc650dSSadaf Ebrahimi 		default:
175*22dc650dSSadaf Ebrahimi 			inst |= (1 << 11);
176*22dc650dSSadaf Ebrahimi 			break;
177*22dc650dSSadaf Ebrahimi 		}
178*22dc650dSSadaf Ebrahimi 	}
179*22dc650dSSadaf Ebrahimi 
180*22dc650dSSadaf Ebrahimi 	if (op == SLJIT_COPY_TO_F64)
181*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, mthc | inst, MOVABLE_INS));
182*22dc650dSSadaf Ebrahimi 	else
183*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, mfhc | inst, DR(reg)));
184*22dc650dSSadaf Ebrahimi 
185*22dc650dSSadaf Ebrahimi #if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
186*22dc650dSSadaf Ebrahimi 	if (mthc == MTC1 || mfhc == MFC1)
187*22dc650dSSadaf Ebrahimi 		return push_inst(compiler, NOP, UNMOVABLE_INS);
188*22dc650dSSadaf Ebrahimi #endif /* MIPS III */
189*22dc650dSSadaf Ebrahimi 	return SLJIT_SUCCESS;
190*22dc650dSSadaf Ebrahimi }
191*22dc650dSSadaf Ebrahimi 
sljit_set_jump_addr(sljit_uw addr,sljit_uw new_target,sljit_sw executable_offset)192*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
193*22dc650dSSadaf Ebrahimi {
194*22dc650dSSadaf Ebrahimi 	sljit_ins *inst = (sljit_ins *)addr;
195*22dc650dSSadaf Ebrahimi 	SLJIT_UNUSED_ARG(executable_offset);
196*22dc650dSSadaf Ebrahimi 
197*22dc650dSSadaf Ebrahimi 	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
198*22dc650dSSadaf Ebrahimi 	SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);
199*22dc650dSSadaf Ebrahimi 	inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
200*22dc650dSSadaf Ebrahimi 	inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
201*22dc650dSSadaf Ebrahimi 	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
202*22dc650dSSadaf Ebrahimi 	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
203*22dc650dSSadaf Ebrahimi 	SLJIT_CACHE_FLUSH(inst, inst + 2);
204*22dc650dSSadaf Ebrahimi }
205*22dc650dSSadaf Ebrahimi 
sljit_set_const(sljit_uw addr,sljit_sw new_constant,sljit_sw executable_offset)206*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
207*22dc650dSSadaf Ebrahimi {
208*22dc650dSSadaf Ebrahimi 	sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
209*22dc650dSSadaf Ebrahimi }
210*22dc650dSSadaf Ebrahimi 
call_with_args(struct sljit_compiler * compiler,sljit_s32 arg_types,sljit_ins * ins_ptr,sljit_u32 * extra_space)211*22dc650dSSadaf Ebrahimi static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr, sljit_u32 *extra_space)
212*22dc650dSSadaf Ebrahimi {
213*22dc650dSSadaf Ebrahimi 	sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN;
214*22dc650dSSadaf Ebrahimi 	sljit_u32 offset = 0;
215*22dc650dSSadaf Ebrahimi 	sljit_s32 float_arg_count = 0;
216*22dc650dSSadaf Ebrahimi 	sljit_s32 word_arg_count = 0;
217*22dc650dSSadaf Ebrahimi 	sljit_s32 types = 0;
218*22dc650dSSadaf Ebrahimi 	sljit_ins prev_ins = NOP;
219*22dc650dSSadaf Ebrahimi 	sljit_ins ins = NOP;
220*22dc650dSSadaf Ebrahimi 	sljit_u8 offsets[4];
221*22dc650dSSadaf Ebrahimi 	sljit_u8 *offsets_ptr = offsets;
222*22dc650dSSadaf Ebrahimi #if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
223*22dc650dSSadaf Ebrahimi 	sljit_ins f64_hi = TA(7), f64_lo = TA(6);
224*22dc650dSSadaf Ebrahimi #else
225*22dc650dSSadaf Ebrahimi 	sljit_ins f64_hi = TA(6), f64_lo = TA(7);
226*22dc650dSSadaf Ebrahimi #endif /* SLJIT_LITTLE_ENDIAN */
227*22dc650dSSadaf Ebrahimi 
228*22dc650dSSadaf Ebrahimi 	SLJIT_ASSERT(reg_map[TMP_REG2] == 4 && freg_map[TMP_FREG1] == 12);
229*22dc650dSSadaf Ebrahimi 
230*22dc650dSSadaf Ebrahimi 	arg_types >>= SLJIT_ARG_SHIFT;
231*22dc650dSSadaf Ebrahimi 
232*22dc650dSSadaf Ebrahimi 	/* See ABI description in sljit_emit_enter. */
233*22dc650dSSadaf Ebrahimi 
234*22dc650dSSadaf Ebrahimi 	while (arg_types) {
235*22dc650dSSadaf Ebrahimi 		types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK);
236*22dc650dSSadaf Ebrahimi 		*offsets_ptr = (sljit_u8)offset;
237*22dc650dSSadaf Ebrahimi 
238*22dc650dSSadaf Ebrahimi 		switch (arg_types & SLJIT_ARG_MASK) {
239*22dc650dSSadaf Ebrahimi 		case SLJIT_ARG_TYPE_F64:
240*22dc650dSSadaf Ebrahimi 			if (offset & 0x7) {
241*22dc650dSSadaf Ebrahimi 				offset += sizeof(sljit_sw);
242*22dc650dSSadaf Ebrahimi 				*offsets_ptr = (sljit_u8)offset;
243*22dc650dSSadaf Ebrahimi 			}
244*22dc650dSSadaf Ebrahimi 
245*22dc650dSSadaf Ebrahimi 			if (word_arg_count == 0 && float_arg_count <= 1)
246*22dc650dSSadaf Ebrahimi 				*offsets_ptr = (sljit_u8)(254 + float_arg_count);
247*22dc650dSSadaf Ebrahimi 
248*22dc650dSSadaf Ebrahimi 			offset += sizeof(sljit_f64);
249*22dc650dSSadaf Ebrahimi 			float_arg_count++;
250*22dc650dSSadaf Ebrahimi 			break;
251*22dc650dSSadaf Ebrahimi 		case SLJIT_ARG_TYPE_F32:
252*22dc650dSSadaf Ebrahimi 			if (word_arg_count == 0 && float_arg_count <= 1)
253*22dc650dSSadaf Ebrahimi 				*offsets_ptr = (sljit_u8)(254 + float_arg_count);
254*22dc650dSSadaf Ebrahimi 
255*22dc650dSSadaf Ebrahimi 			offset += sizeof(sljit_f32);
256*22dc650dSSadaf Ebrahimi 			float_arg_count++;
257*22dc650dSSadaf Ebrahimi 			break;
258*22dc650dSSadaf Ebrahimi 		default:
259*22dc650dSSadaf Ebrahimi 			offset += sizeof(sljit_sw);
260*22dc650dSSadaf Ebrahimi 			word_arg_count++;
261*22dc650dSSadaf Ebrahimi 			break;
262*22dc650dSSadaf Ebrahimi 		}
263*22dc650dSSadaf Ebrahimi 
264*22dc650dSSadaf Ebrahimi 		arg_types >>= SLJIT_ARG_SHIFT;
265*22dc650dSSadaf Ebrahimi 		offsets_ptr++;
266*22dc650dSSadaf Ebrahimi 	}
267*22dc650dSSadaf Ebrahimi 
268*22dc650dSSadaf Ebrahimi 	/* Stack is aligned to 16 bytes. */
269*22dc650dSSadaf Ebrahimi 	SLJIT_ASSERT(offset <= 8 * sizeof(sljit_sw));
270*22dc650dSSadaf Ebrahimi 
271*22dc650dSSadaf Ebrahimi 	if (offset > 4 * sizeof(sljit_sw) && (!is_tail_call || offset > compiler->args_size)) {
272*22dc650dSSadaf Ebrahimi 		if (is_tail_call) {
273*22dc650dSSadaf Ebrahimi 			offset = (offset + sizeof(sljit_sw) + 15) & ~(sljit_uw)0xf;
274*22dc650dSSadaf Ebrahimi 			FAIL_IF(emit_stack_frame_release(compiler, (sljit_s32)offset, &prev_ins));
275*22dc650dSSadaf Ebrahimi 			*extra_space = offset;
276*22dc650dSSadaf Ebrahimi 		} else {
277*22dc650dSSadaf Ebrahimi 			FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-16), DR(SLJIT_SP)));
278*22dc650dSSadaf Ebrahimi 			*extra_space = 16;
279*22dc650dSSadaf Ebrahimi 		}
280*22dc650dSSadaf Ebrahimi 	} else {
281*22dc650dSSadaf Ebrahimi 		if (is_tail_call)
282*22dc650dSSadaf Ebrahimi 			FAIL_IF(emit_stack_frame_release(compiler, 0, &prev_ins));
283*22dc650dSSadaf Ebrahimi 		*extra_space = 0;
284*22dc650dSSadaf Ebrahimi 	}
285*22dc650dSSadaf Ebrahimi 
286*22dc650dSSadaf Ebrahimi 	while (types) {
287*22dc650dSSadaf Ebrahimi 		--offsets_ptr;
288*22dc650dSSadaf Ebrahimi 
289*22dc650dSSadaf Ebrahimi 		switch (types & SLJIT_ARG_MASK) {
290*22dc650dSSadaf Ebrahimi 		case SLJIT_ARG_TYPE_F64:
291*22dc650dSSadaf Ebrahimi 			if (*offsets_ptr < 4 * sizeof(sljit_sw)) {
292*22dc650dSSadaf Ebrahimi 				if (prev_ins != NOP)
293*22dc650dSSadaf Ebrahimi 					FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
294*22dc650dSSadaf Ebrahimi 
295*22dc650dSSadaf Ebrahimi 				/* Must be preceded by at least one other argument,
296*22dc650dSSadaf Ebrahimi 				 * and its starting offset must be 8 because of alignment. */
297*22dc650dSSadaf Ebrahimi 				SLJIT_ASSERT((*offsets_ptr >> 2) == 2);
298*22dc650dSSadaf Ebrahimi 				switch (cpu_feature_list & CPU_FEATURE_FR) {
299*22dc650dSSadaf Ebrahimi #if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
300*22dc650dSSadaf Ebrahimi 				case CPU_FEATURE_FR:
301*22dc650dSSadaf Ebrahimi 					prev_ins = MFHC1 | f64_hi | FS(float_arg_count);
302*22dc650dSSadaf Ebrahimi 					break;
303*22dc650dSSadaf Ebrahimi #endif /* SLJIT_MIPS_REV >= 2 */
304*22dc650dSSadaf Ebrahimi 				default:
305*22dc650dSSadaf Ebrahimi 					prev_ins = MFC1 | f64_hi | FS(float_arg_count) | (1 << 11);
306*22dc650dSSadaf Ebrahimi 					break;
307*22dc650dSSadaf Ebrahimi 				}
308*22dc650dSSadaf Ebrahimi 				ins = MFC1 | f64_lo | FS(float_arg_count);
309*22dc650dSSadaf Ebrahimi 			} else if (*offsets_ptr < 254)
310*22dc650dSSadaf Ebrahimi 				ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);
311*22dc650dSSadaf Ebrahimi 			else if (*offsets_ptr == 254)
312*22dc650dSSadaf Ebrahimi 				ins = MOV_fmt(FMT_D) | FS(SLJIT_FR0) | FD(TMP_FREG1);
313*22dc650dSSadaf Ebrahimi 
314*22dc650dSSadaf Ebrahimi 			float_arg_count--;
315*22dc650dSSadaf Ebrahimi 			break;
316*22dc650dSSadaf Ebrahimi 		case SLJIT_ARG_TYPE_F32:
317*22dc650dSSadaf Ebrahimi 			if (*offsets_ptr < 4 * sizeof (sljit_sw))
318*22dc650dSSadaf Ebrahimi 				ins = MFC1 | TA(4 + (*offsets_ptr >> 2)) | FS(float_arg_count);
319*22dc650dSSadaf Ebrahimi 			else if (*offsets_ptr < 254)
320*22dc650dSSadaf Ebrahimi 				ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);
321*22dc650dSSadaf Ebrahimi 			else if (*offsets_ptr == 254)
322*22dc650dSSadaf Ebrahimi 				ins = MOV_fmt(FMT_S) | FS(SLJIT_FR0) | FD(TMP_FREG1);
323*22dc650dSSadaf Ebrahimi 
324*22dc650dSSadaf Ebrahimi 			float_arg_count--;
325*22dc650dSSadaf Ebrahimi 			break;
326*22dc650dSSadaf Ebrahimi 		default:
327*22dc650dSSadaf Ebrahimi 			if (*offsets_ptr >= 4 * sizeof (sljit_sw))
328*22dc650dSSadaf Ebrahimi 				ins = SW | S(SLJIT_SP) | T(word_arg_count) | IMM(*offsets_ptr);
329*22dc650dSSadaf Ebrahimi 			else if ((*offsets_ptr >> 2) != word_arg_count - 1)
330*22dc650dSSadaf Ebrahimi 				ins = ADDU | S(word_arg_count) | TA(0) | DA(4 + (*offsets_ptr >> 2));
331*22dc650dSSadaf Ebrahimi 			else if (*offsets_ptr == 0)
332*22dc650dSSadaf Ebrahimi 				ins = ADDU | S(SLJIT_R0) | TA(0) | DA(4);
333*22dc650dSSadaf Ebrahimi 
334*22dc650dSSadaf Ebrahimi 			word_arg_count--;
335*22dc650dSSadaf Ebrahimi 			break;
336*22dc650dSSadaf Ebrahimi 		}
337*22dc650dSSadaf Ebrahimi 
338*22dc650dSSadaf Ebrahimi 		if (ins != NOP) {
339*22dc650dSSadaf Ebrahimi 			if (prev_ins != NOP)
340*22dc650dSSadaf Ebrahimi 				FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
341*22dc650dSSadaf Ebrahimi 			prev_ins = ins;
342*22dc650dSSadaf Ebrahimi 			ins = NOP;
343*22dc650dSSadaf Ebrahimi 		}
344*22dc650dSSadaf Ebrahimi 
345*22dc650dSSadaf Ebrahimi 		types >>= SLJIT_ARG_SHIFT;
346*22dc650dSSadaf Ebrahimi 	}
347*22dc650dSSadaf Ebrahimi 
348*22dc650dSSadaf Ebrahimi 	*ins_ptr = prev_ins;
349*22dc650dSSadaf Ebrahimi 
350*22dc650dSSadaf Ebrahimi 	return SLJIT_SUCCESS;
351*22dc650dSSadaf Ebrahimi }
352*22dc650dSSadaf Ebrahimi 
sljit_emit_call(struct sljit_compiler * compiler,sljit_s32 type,sljit_s32 arg_types)353*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
354*22dc650dSSadaf Ebrahimi 	sljit_s32 arg_types)
355*22dc650dSSadaf Ebrahimi {
356*22dc650dSSadaf Ebrahimi 	struct sljit_jump *jump;
357*22dc650dSSadaf Ebrahimi 	sljit_u32 extra_space = 0;
358*22dc650dSSadaf Ebrahimi 	sljit_ins ins = NOP;
359*22dc650dSSadaf Ebrahimi 
360*22dc650dSSadaf Ebrahimi 	CHECK_ERROR_PTR();
361*22dc650dSSadaf Ebrahimi 	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
362*22dc650dSSadaf Ebrahimi 
363*22dc650dSSadaf Ebrahimi 	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
364*22dc650dSSadaf Ebrahimi 	PTR_FAIL_IF(!jump);
365*22dc650dSSadaf Ebrahimi 	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
366*22dc650dSSadaf Ebrahimi 
367*22dc650dSSadaf Ebrahimi 	if ((type & 0xff) != SLJIT_CALL_REG_ARG) {
368*22dc650dSSadaf Ebrahimi 		extra_space = (sljit_u32)type;
369*22dc650dSSadaf Ebrahimi 		PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins, &extra_space));
370*22dc650dSSadaf Ebrahimi 	} else if (type & SLJIT_CALL_RETURN)
371*22dc650dSSadaf Ebrahimi 		PTR_FAIL_IF(emit_stack_frame_release(compiler, 0, &ins));
372*22dc650dSSadaf Ebrahimi 
373*22dc650dSSadaf Ebrahimi 	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);
374*22dc650dSSadaf Ebrahimi 
375*22dc650dSSadaf Ebrahimi 	if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS)
376*22dc650dSSadaf Ebrahimi 		jump->flags |= IS_MOVABLE;
377*22dc650dSSadaf Ebrahimi 
378*22dc650dSSadaf Ebrahimi 	if (!(type & SLJIT_CALL_RETURN) || extra_space > 0) {
379*22dc650dSSadaf Ebrahimi 		jump->flags |= IS_JAL;
380*22dc650dSSadaf Ebrahimi 
381*22dc650dSSadaf Ebrahimi 		if ((type & 0xff) != SLJIT_CALL_REG_ARG)
382*22dc650dSSadaf Ebrahimi 			jump->flags |= IS_CALL;
383*22dc650dSSadaf Ebrahimi 
384*22dc650dSSadaf Ebrahimi 		PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
385*22dc650dSSadaf Ebrahimi 	} else
386*22dc650dSSadaf Ebrahimi 		PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS));
387*22dc650dSSadaf Ebrahimi 
388*22dc650dSSadaf Ebrahimi 	jump->addr = compiler->size;
389*22dc650dSSadaf Ebrahimi 	PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
390*22dc650dSSadaf Ebrahimi 
391*22dc650dSSadaf Ebrahimi 	/* Maximum number of instructions required for generating a constant. */
392*22dc650dSSadaf Ebrahimi 	compiler->size += 2;
393*22dc650dSSadaf Ebrahimi 
394*22dc650dSSadaf Ebrahimi 	if (extra_space == 0)
395*22dc650dSSadaf Ebrahimi 		return jump;
396*22dc650dSSadaf Ebrahimi 
397*22dc650dSSadaf Ebrahimi 	if (type & SLJIT_CALL_RETURN)
398*22dc650dSSadaf Ebrahimi 		PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG,
399*22dc650dSSadaf Ebrahimi 			SLJIT_MEM1(SLJIT_SP), (sljit_sw)(extra_space - sizeof(sljit_sw))));
400*22dc650dSSadaf Ebrahimi 
401*22dc650dSSadaf Ebrahimi 	if (type & SLJIT_CALL_RETURN)
402*22dc650dSSadaf Ebrahimi 		PTR_FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS));
403*22dc650dSSadaf Ebrahimi 
404*22dc650dSSadaf Ebrahimi 	PTR_FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(extra_space),
405*22dc650dSSadaf Ebrahimi 		(type & SLJIT_CALL_RETURN) ? UNMOVABLE_INS : DR(SLJIT_SP)));
406*22dc650dSSadaf Ebrahimi 	return jump;
407*22dc650dSSadaf Ebrahimi }
408*22dc650dSSadaf Ebrahimi 
sljit_emit_icall(struct sljit_compiler * compiler,sljit_s32 type,sljit_s32 arg_types,sljit_s32 src,sljit_sw srcw)409*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
410*22dc650dSSadaf Ebrahimi 	sljit_s32 arg_types,
411*22dc650dSSadaf Ebrahimi 	sljit_s32 src, sljit_sw srcw)
412*22dc650dSSadaf Ebrahimi {
413*22dc650dSSadaf Ebrahimi 	sljit_u32 extra_space = (sljit_u32)type;
414*22dc650dSSadaf Ebrahimi 	sljit_ins ins;
415*22dc650dSSadaf Ebrahimi 
416*22dc650dSSadaf Ebrahimi 	CHECK_ERROR();
417*22dc650dSSadaf Ebrahimi 	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
418*22dc650dSSadaf Ebrahimi 
419*22dc650dSSadaf Ebrahimi 	if (src & SLJIT_MEM) {
420*22dc650dSSadaf Ebrahimi 		ADJUST_LOCAL_OFFSET(src, srcw);
421*22dc650dSSadaf Ebrahimi 		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
422*22dc650dSSadaf Ebrahimi 		src = PIC_ADDR_REG;
423*22dc650dSSadaf Ebrahimi 		srcw = 0;
424*22dc650dSSadaf Ebrahimi 	}
425*22dc650dSSadaf Ebrahimi 
426*22dc650dSSadaf Ebrahimi 	if ((type & 0xff) == SLJIT_CALL_REG_ARG) {
427*22dc650dSSadaf Ebrahimi 		if (type & SLJIT_CALL_RETURN) {
428*22dc650dSSadaf Ebrahimi 			if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
429*22dc650dSSadaf Ebrahimi 				FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
430*22dc650dSSadaf Ebrahimi 				src = PIC_ADDR_REG;
431*22dc650dSSadaf Ebrahimi 				srcw = 0;
432*22dc650dSSadaf Ebrahimi 			}
433*22dc650dSSadaf Ebrahimi 
434*22dc650dSSadaf Ebrahimi 			FAIL_IF(emit_stack_frame_release(compiler, 0, &ins));
435*22dc650dSSadaf Ebrahimi 
436*22dc650dSSadaf Ebrahimi 			if (ins != NOP)
437*22dc650dSSadaf Ebrahimi 				FAIL_IF(push_inst(compiler, ins, MOVABLE_INS));
438*22dc650dSSadaf Ebrahimi 		}
439*22dc650dSSadaf Ebrahimi 
440*22dc650dSSadaf Ebrahimi 		SLJIT_SKIP_CHECKS(compiler);
441*22dc650dSSadaf Ebrahimi 		return sljit_emit_ijump(compiler, type, src, srcw);
442*22dc650dSSadaf Ebrahimi 	}
443*22dc650dSSadaf Ebrahimi 
444*22dc650dSSadaf Ebrahimi 	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);
445*22dc650dSSadaf Ebrahimi 
446*22dc650dSSadaf Ebrahimi 	if (src == SLJIT_IMM)
447*22dc650dSSadaf Ebrahimi 		FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
448*22dc650dSSadaf Ebrahimi 	else if (src != PIC_ADDR_REG)
449*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
450*22dc650dSSadaf Ebrahimi 
451*22dc650dSSadaf Ebrahimi 	FAIL_IF(call_with_args(compiler, arg_types, &ins, &extra_space));
452*22dc650dSSadaf Ebrahimi 
453*22dc650dSSadaf Ebrahimi 	/* Register input. */
454*22dc650dSSadaf Ebrahimi 	if (!(type & SLJIT_CALL_RETURN) || extra_space > 0)
455*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
456*22dc650dSSadaf Ebrahimi 	else
457*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS));
458*22dc650dSSadaf Ebrahimi 	FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
459*22dc650dSSadaf Ebrahimi 
460*22dc650dSSadaf Ebrahimi 	if (extra_space == 0)
461*22dc650dSSadaf Ebrahimi 		return SLJIT_SUCCESS;
462*22dc650dSSadaf Ebrahimi 
463*22dc650dSSadaf Ebrahimi 	if (type & SLJIT_CALL_RETURN)
464*22dc650dSSadaf Ebrahimi 		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG,
465*22dc650dSSadaf Ebrahimi 			SLJIT_MEM1(SLJIT_SP), (sljit_sw)(extra_space - sizeof(sljit_sw))));
466*22dc650dSSadaf Ebrahimi 
467*22dc650dSSadaf Ebrahimi 	if (type & SLJIT_CALL_RETURN)
468*22dc650dSSadaf Ebrahimi 		FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS));
469*22dc650dSSadaf Ebrahimi 
470*22dc650dSSadaf Ebrahimi 	return push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(extra_space),
471*22dc650dSSadaf Ebrahimi 		(type & SLJIT_CALL_RETURN) ? UNMOVABLE_INS : DR(SLJIT_SP));
472*22dc650dSSadaf Ebrahimi }
473