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