1 /*
2 * Stack-less Just-In-Time compiler
3 *
4 * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without modification, are
7 * permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice, this list of
10 * conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 * of conditions and the following disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /* ppc 32-bit arch dependent functions. */
28
load_immediate(struct sljit_compiler * compiler,sljit_s32 reg,sljit_sw imm)29 static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
30 {
31 if (imm <= SIMM_MAX && imm >= SIMM_MIN)
32 return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
33
34 if (!(imm & ~0xffff))
35 return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
36
37 FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
38 return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
39 }
40
41 /* Simplified mnemonics: clrlwi. */
42 #define INS_CLEAR_LEFT(dst, src, from) \
43 (RLWINM | S(src) | A(dst) | RLWI_MBE(from, 31))
44
emit_single_op(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 flags,sljit_s32 dst,sljit_s32 src1,sljit_s32 src2)45 static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
46 sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
47 {
48 sljit_u32 imm;
49
50 switch (op) {
51 case SLJIT_MOV:
52 case SLJIT_MOV_U32:
53 case SLJIT_MOV_S32:
54 case SLJIT_MOV_P:
55 SLJIT_ASSERT(src1 == TMP_REG1);
56 if (dst != src2)
57 return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
58 return SLJIT_SUCCESS;
59
60 case SLJIT_MOV_U8:
61 case SLJIT_MOV_S8:
62 SLJIT_ASSERT(src1 == TMP_REG1);
63 if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
64 if (op == SLJIT_MOV_S8)
65 return push_inst(compiler, EXTSB | S(src2) | A(dst));
66 return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
67 }
68 else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
69 return push_inst(compiler, EXTSB | S(src2) | A(dst));
70 else {
71 SLJIT_ASSERT(dst == src2);
72 }
73 return SLJIT_SUCCESS;
74
75 case SLJIT_MOV_U16:
76 case SLJIT_MOV_S16:
77 SLJIT_ASSERT(src1 == TMP_REG1);
78 if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
79 if (op == SLJIT_MOV_S16)
80 return push_inst(compiler, EXTSH | S(src2) | A(dst));
81 return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
82 }
83 else {
84 SLJIT_ASSERT(dst == src2);
85 }
86 return SLJIT_SUCCESS;
87
88 case SLJIT_CLZ:
89 SLJIT_ASSERT(src1 == TMP_REG1);
90 return push_inst(compiler, CNTLZW | S(src2) | A(dst));
91
92 case SLJIT_CTZ:
93 SLJIT_ASSERT(src1 == TMP_REG1);
94 FAIL_IF(push_inst(compiler, NEG | D(TMP_REG1) | A(src2)));
95 FAIL_IF(push_inst(compiler, AND | S(src2) | A(dst) | B(TMP_REG1)));
96 FAIL_IF(push_inst(compiler, CNTLZW | S(dst) | A(dst)));
97 FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG1) | A(dst) | IMM(-32)));
98 /* The highest bits are set, if dst < 32, zero otherwise. */
99 FAIL_IF(push_inst(compiler, SRWI(27) | S(TMP_REG1) | A(TMP_REG1)));
100 return push_inst(compiler, XOR | S(dst) | A(dst) | B(TMP_REG1));
101
102 case SLJIT_ADD:
103 if (flags & ALT_FORM1) {
104 /* Setting XER SO is not enough, CR SO is also needed. */
105 return push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
106 }
107
108 if (flags & ALT_FORM2) {
109 /* Flags does not set: BIN_IMM_EXTS unnecessary. */
110 SLJIT_ASSERT(src2 == TMP_REG2);
111
112 if (flags & ALT_FORM3)
113 return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
114
115 imm = compiler->imm;
116
117 if (flags & ALT_FORM4) {
118 FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((imm >> 16) & 0xffff) + ((imm >> 15) & 0x1))));
119 src1 = dst;
120 }
121
122 return push_inst(compiler, ADDI | D(dst) | A(src1) | (imm & 0xffff));
123 }
124 if (flags & ALT_FORM3) {
125 SLJIT_ASSERT(src2 == TMP_REG2);
126 return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
127 }
128 SLJIT_ASSERT(!(flags & ALT_FORM4));
129 if (!(flags & ALT_SET_FLAGS))
130 return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
131 if (flags & ALT_FORM5)
132 return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
133 return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
134
135 case SLJIT_ADDC:
136 return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
137
138 case SLJIT_SUB:
139 if (flags & ALT_FORM1) {
140 if (flags & ALT_FORM2) {
141 FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm));
142 if (!(flags & ALT_FORM3))
143 return SLJIT_SUCCESS;
144 return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
145 }
146 FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2)));
147 if (!(flags & ALT_FORM3))
148 return SLJIT_SUCCESS;
149 return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
150 }
151
152 if (flags & ALT_FORM2) {
153 if (flags & ALT_FORM3) {
154 FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm));
155 if (!(flags & ALT_FORM4))
156 return SLJIT_SUCCESS;
157 return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
158 }
159 FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2)));
160 if (!(flags & ALT_FORM4))
161 return SLJIT_SUCCESS;
162 return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
163 }
164
165 if (flags & ALT_FORM3) {
166 /* Setting XER SO is not enough, CR SO is also needed. */
167 if (src1 != TMP_ZERO)
168 return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
169 return push_inst(compiler, NEG | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2));
170 }
171
172 if (flags & ALT_FORM4) {
173 /* Flags does not set: BIN_IMM_EXTS unnecessary. */
174 SLJIT_ASSERT(src2 == TMP_REG2);
175 return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
176 }
177
178 if (!(flags & ALT_SET_FLAGS)) {
179 SLJIT_ASSERT(src1 != TMP_ZERO);
180 return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
181 }
182
183 if (flags & ALT_FORM5)
184 return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
185
186 if (src1 != TMP_ZERO)
187 return push_inst(compiler, SUBF | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
188 return push_inst(compiler, NEG | RC(ALT_SET_FLAGS) | D(dst) | A(src2));
189
190 case SLJIT_SUBC:
191 return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
192
193 case SLJIT_MUL:
194 if (flags & ALT_FORM1) {
195 SLJIT_ASSERT(src2 == TMP_REG2);
196 return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
197 }
198 return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
199
200 case SLJIT_AND:
201 if (flags & ALT_FORM1) {
202 SLJIT_ASSERT(src2 == TMP_REG2);
203 return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
204 }
205 if (flags & ALT_FORM2) {
206 SLJIT_ASSERT(src2 == TMP_REG2);
207 return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
208 }
209 return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
210
211 case SLJIT_OR:
212 if (flags & ALT_FORM1) {
213 SLJIT_ASSERT(src2 == TMP_REG2);
214 return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
215 }
216 if (flags & ALT_FORM2) {
217 SLJIT_ASSERT(src2 == TMP_REG2);
218 return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
219 }
220 if (flags & ALT_FORM3) {
221 SLJIT_ASSERT(src2 == TMP_REG2);
222 imm = compiler->imm;
223
224 FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(imm)));
225 return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(imm >> 16));
226 }
227 return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
228
229 case SLJIT_XOR:
230 if (flags & ALT_FORM1) {
231 SLJIT_ASSERT(src2 == TMP_REG2);
232 return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
233 }
234 if (flags & ALT_FORM2) {
235 SLJIT_ASSERT(src2 == TMP_REG2);
236 return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
237 }
238 if (flags & ALT_FORM3) {
239 SLJIT_ASSERT(src2 == TMP_REG2);
240 imm = compiler->imm;
241
242 FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm)));
243 return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16));
244 }
245 if (flags & ALT_FORM4) {
246 SLJIT_ASSERT(src1 == TMP_REG1);
247 return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
248 }
249 return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
250
251 case SLJIT_SHL:
252 case SLJIT_MSHL:
253 if (flags & ALT_FORM1) {
254 SLJIT_ASSERT(src2 == TMP_REG2);
255 imm = compiler->imm & 0x1f;
256 return push_inst(compiler, SLWI(imm) | RC(flags) | S(src1) | A(dst));
257 }
258
259 if (op == SLJIT_MSHL) {
260 FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f));
261 src2 = TMP_REG2;
262 }
263
264 return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
265
266 case SLJIT_LSHR:
267 case SLJIT_MLSHR:
268 if (flags & ALT_FORM1) {
269 SLJIT_ASSERT(src2 == TMP_REG2);
270 imm = compiler->imm & 0x1f;
271 /* Since imm can be 0, SRWI() cannot be used. */
272 return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | RLWI_SH((32 - imm) & 0x1f) | RLWI_MBE(imm, 31));
273 }
274
275 if (op == SLJIT_MLSHR) {
276 FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f));
277 src2 = TMP_REG2;
278 }
279
280 return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
281
282 case SLJIT_ASHR:
283 case SLJIT_MASHR:
284 if (flags & ALT_FORM1) {
285 SLJIT_ASSERT(src2 == TMP_REG2);
286 imm = compiler->imm & 0x1f;
287 return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (imm << 11));
288 }
289
290 if (op == SLJIT_MASHR) {
291 FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f));
292 src2 = TMP_REG2;
293 }
294
295 return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
296
297 case SLJIT_ROTL:
298 case SLJIT_ROTR:
299 if (flags & ALT_FORM1) {
300 SLJIT_ASSERT(src2 == TMP_REG2);
301 imm = compiler->imm;
302
303 if (op == SLJIT_ROTR)
304 imm = (sljit_u32)(-(sljit_s32)imm);
305
306 imm &= 0x1f;
307 return push_inst(compiler, RLWINM | S(src1) | A(dst) | RLWI_SH(imm) | RLWI_MBE(0, 31));
308 }
309
310 if (op == SLJIT_ROTR) {
311 FAIL_IF(push_inst(compiler, SUBFIC | D(TMP_REG2) | A(src2) | 0));
312 src2 = TMP_REG2;
313 }
314
315 return push_inst(compiler, RLWNM | S(src1) | A(dst) | B(src2) | RLWI_MBE(0, 31));
316 }
317
318 SLJIT_UNREACHABLE();
319 return SLJIT_SUCCESS;
320 }
321
emit_const(struct sljit_compiler * compiler,sljit_s32 reg,sljit_sw init_value)322 static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
323 {
324 FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
325 return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
326 }
327
sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw)328 static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
329 sljit_s32 dst, sljit_sw dstw,
330 sljit_s32 src, sljit_sw srcw)
331 {
332 sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
333 sljit_s32 invert_sign = 1;
334
335 if (src == SLJIT_IMM) {
336 FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ (sljit_sw)0x80000000));
337 src = TMP_REG1;
338 invert_sign = 0;
339 } else if (!FAST_IS_REG(src)) {
340 FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
341 src = TMP_REG1;
342 }
343
344 /* First, a special double precision floating point value is constructed:
345 (2^53 + (src xor (2^31)))
346 The upper 32 bits of this number is a constant, and the lower 32 bits
347 is simply the value of the source argument. The xor 2^31 operation adds
348 0x80000000 to the source argument, which moves it into the 0 - 0xffffffff
349 range. Finally we substract 2^53 + 2^31 to get the converted value. */
350 FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
351 if (invert_sign)
352 FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
353 FAIL_IF(push_inst(compiler, STW | S(TMP_REG2) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
354 FAIL_IF(push_inst(compiler, STW | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
355 FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
356 FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
357 FAIL_IF(push_inst(compiler, STW | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
358 FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
359
360 FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
361
362 if (op & SLJIT_32)
363 FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
364
365 if (dst & SLJIT_MEM)
366 return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
367 return SLJIT_SUCCESS;
368 }
369
sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw)370 static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
371 sljit_s32 dst, sljit_sw dstw,
372 sljit_s32 src, sljit_sw srcw)
373 {
374 sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
375
376 if (src == SLJIT_IMM) {
377 FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
378 src = TMP_REG1;
379 } else if (!FAST_IS_REG(src)) {
380 FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
381 src = TMP_REG1;
382 }
383
384 /* First, a special double precision floating point value is constructed:
385 (2^53 + src)
386 The upper 32 bits of this number is a constant, and the lower 32 bits
387 is simply the value of the source argument. Finally we substract 2^53
388 to get the converted value. */
389 FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
390 FAIL_IF(push_inst(compiler, STW | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
391 FAIL_IF(push_inst(compiler, STW | S(TMP_REG2) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
392
393 FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
394 FAIL_IF(push_inst(compiler, STW | S(TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
395 FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
396
397 FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
398
399 if (op & SLJIT_32)
400 FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
401
402 if (dst & SLJIT_MEM)
403 return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
404 return SLJIT_SUCCESS;
405 }
406
sljit_emit_fset64(struct sljit_compiler * compiler,sljit_s32 freg,sljit_f64 value)407 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
408 sljit_s32 freg, sljit_f64 value)
409 {
410 union {
411 sljit_s32 imm[2];
412 sljit_f64 value;
413 } u;
414
415 CHECK_ERROR();
416 CHECK(check_sljit_emit_fset64(compiler, freg, value));
417
418 u.value = value;
419
420 if (u.imm[0] != 0)
421 FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0]));
422 if (u.imm[1] != 0)
423 FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1]));
424
425 /* Saved in the same endianness. */
426 FAIL_IF(push_inst(compiler, STW | S(u.imm[0] != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));
427 FAIL_IF(push_inst(compiler, STW | S(u.imm[1] != 0 ? TMP_REG2 : TMP_ZERO) | A(SLJIT_SP) | (TMP_MEM_OFFSET + sizeof(sljit_s32))));
428 return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
429 }
430
sljit_emit_fcopy(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 freg,sljit_s32 reg)431 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
432 sljit_s32 freg, sljit_s32 reg)
433 {
434 sljit_s32 reg2 = 0;
435
436 CHECK_ERROR();
437 CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
438
439 if (op & SLJIT_32) {
440 if (op == SLJIT_COPY32_TO_F32) {
441 FAIL_IF(push_inst(compiler, STW | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
442 return push_inst(compiler, LFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
443 }
444
445 FAIL_IF(push_inst(compiler, STFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
446 return push_inst(compiler, LWZ | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
447 }
448
449 if (reg & REG_PAIR_MASK) {
450 reg2 = REG_PAIR_SECOND(reg);
451 reg = REG_PAIR_FIRST(reg);
452 }
453
454 if (op == SLJIT_COPY_TO_F64) {
455 FAIL_IF(push_inst(compiler, STW | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
456
457 if (reg2 != 0)
458 FAIL_IF(push_inst(compiler, STW | S(reg2) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
459 else
460 FAIL_IF(push_inst(compiler, STFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
461
462 return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
463 }
464
465 FAIL_IF(push_inst(compiler, STFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
466
467 if (reg2 != 0)
468 FAIL_IF(push_inst(compiler, LWZ | S(reg2) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
469
470 return push_inst(compiler, LWZ | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI);
471 }
472
sljit_set_jump_addr(sljit_uw addr,sljit_uw new_target,sljit_sw executable_offset)473 SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
474 {
475 sljit_ins *inst = (sljit_ins *)addr;
476 SLJIT_UNUSED_ARG(executable_offset);
477
478 SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
479 SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI);
480 inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
481 inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
482 SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
483 inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
484 SLJIT_CACHE_FLUSH(inst, inst + 2);
485 }
486