2 * Stack-less Just-In-Time compiler
4 * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
6 * Redistribution and use in source and binary forms, with or without modification, are
7 * permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice, this list of
10 * conditions and the following disclaimer.
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.
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.
27 /* ppc 64-bit arch dependent functions. */
29 #if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
30 #define ASM_SLJIT_CLZ(src, dst) \
31 __asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) )
32 #elif defined(__xlc__)
33 #error "Please enable GCC syntax for inline assembly statements"
35 #error "Must implement count leading zeroes"
38 #define RLDI(dst, src, sh, mb, type) \
39 (HI(30) | S(src) | A(dst) | ((type) << 2) | (((sh) & 0x1f) << 11) | (((sh) & 0x20) >> 4) | (((mb) & 0x1f) << 6) | ((mb) & 0x20))
41 #define PUSH_RLDICR(reg, shift) \
42 push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
44 static sljit_s32
load_immediate(struct sljit_compiler
*compiler
, sljit_s32 reg
, sljit_sw imm
)
51 if (imm
<= SIMM_MAX
&& imm
>= SIMM_MIN
)
52 return push_inst(compiler
, ADDI
| D(reg
) | A(0) | IMM(imm
));
55 return push_inst(compiler
, ORI
| S(TMP_ZERO
) | A(reg
) | IMM(imm
));
57 if (imm
<= 0x7fffffffl
&& imm
>= -0x80000000l
) {
58 FAIL_IF(push_inst(compiler
, ADDIS
| D(reg
) | A(0) | IMM(imm
>> 16)));
59 return (imm
& 0xffff) ? push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(imm
)) : SLJIT_SUCCESS
;
62 /* Count leading zeroes. */
63 tmp
= (imm
>= 0) ? imm
: ~imm
;
64 ASM_SLJIT_CLZ(tmp
, shift
);
65 SLJIT_ASSERT(shift
> 0);
69 if ((tmp
& ~0xffff000000000000ul
) == 0) {
70 FAIL_IF(push_inst(compiler
, ADDI
| D(reg
) | A(0) | IMM(tmp
>> 48)));
72 return PUSH_RLDICR(reg
, shift
);
75 if ((tmp
& ~0xffffffff00000000ul
) == 0) {
76 FAIL_IF(push_inst(compiler
, ADDIS
| D(reg
) | A(0) | IMM(tmp
>> 48)));
77 FAIL_IF(push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(tmp
>> 32)));
79 return PUSH_RLDICR(reg
, shift
);
82 /* Cut out the 16 bit from immediate. */
84 tmp2
= imm
& ((1ul << (63 - shift
)) - 1);
87 FAIL_IF(push_inst(compiler
, ADDI
| D(reg
) | A(0) | IMM(tmp
>> 48)));
88 FAIL_IF(PUSH_RLDICR(reg
, shift
));
89 return push_inst(compiler
, ORI
| S(reg
) | A(reg
) | tmp2
);
92 if (tmp2
<= 0xffffffff) {
93 FAIL_IF(push_inst(compiler
, ADDI
| D(reg
) | A(0) | IMM(tmp
>> 48)));
94 FAIL_IF(PUSH_RLDICR(reg
, shift
));
95 FAIL_IF(push_inst(compiler
, ORIS
| S(reg
) | A(reg
) | (tmp2
>> 16)));
96 return (imm
& 0xffff) ? push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(tmp2
)) : SLJIT_SUCCESS
;
99 ASM_SLJIT_CLZ(tmp2
, shift2
);
102 if ((tmp2
& ~0xffff000000000000ul
) == 0) {
103 FAIL_IF(push_inst(compiler
, ADDI
| D(reg
) | A(0) | IMM(tmp
>> 48)));
105 shift
+= (63 - shift2
);
106 FAIL_IF(PUSH_RLDICR(reg
, shift
));
107 FAIL_IF(push_inst(compiler
, ORI
| S(reg
) | A(reg
) | (tmp2
>> 48)));
108 return PUSH_RLDICR(reg
, shift2
);
111 /* The general version. */
112 FAIL_IF(push_inst(compiler
, ADDIS
| D(reg
) | A(0) | IMM(imm
>> 48)));
113 FAIL_IF(push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(imm
>> 32)));
114 FAIL_IF(PUSH_RLDICR(reg
, 31));
115 FAIL_IF(push_inst(compiler
, ORIS
| S(reg
) | A(reg
) | IMM(imm
>> 16)));
116 return push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(imm
));
119 /* Simplified mnemonics: clrldi. */
120 #define INS_CLEAR_LEFT(dst, src, from) \
121 (RLDICL | S(src) | A(dst) | ((from) << 6) | (1 << 5))
123 /* Sign extension for integer operations. */
125 if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \
126 FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
131 if (flags & ALT_SIGN_EXT) { \
132 if (flags & REG1_SOURCE) { \
133 FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
136 if (flags & REG2_SOURCE) { \
137 FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
142 #define BIN_IMM_EXTS() \
143 if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \
144 FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
148 static SLJIT_INLINE sljit_s32
emit_single_op(struct sljit_compiler
*compiler
, sljit_s32 op
, sljit_s32 flags
,
149 sljit_s32 dst
, sljit_s32 src1
, sljit_s32 src2
)
154 SLJIT_ASSERT(src1
== TMP_REG1
);
156 return push_inst(compiler
, OR
| S(src2
) | A(dst
) | B(src2
));
157 return SLJIT_SUCCESS
;
161 SLJIT_ASSERT(src1
== TMP_REG1
);
162 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
163 if (op
== SLJIT_MOV_S32
)
164 return push_inst(compiler
, EXTSW
| S(src2
) | A(dst
));
165 return push_inst(compiler
, INS_CLEAR_LEFT(dst
, src2
, 0));
168 SLJIT_ASSERT(dst
== src2
);
170 return SLJIT_SUCCESS
;
174 SLJIT_ASSERT(src1
== TMP_REG1
);
175 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
176 if (op
== SLJIT_MOV_S8
)
177 return push_inst(compiler
, EXTSB
| S(src2
) | A(dst
));
178 return push_inst(compiler
, INS_CLEAR_LEFT(dst
, src2
, 24));
180 else if ((flags
& REG_DEST
) && op
== SLJIT_MOV_S8
)
181 return push_inst(compiler
, EXTSB
| S(src2
) | A(dst
));
183 SLJIT_ASSERT(dst
== src2
);
185 return SLJIT_SUCCESS
;
189 SLJIT_ASSERT(src1
== TMP_REG1
);
190 if ((flags
& (REG_DEST
| REG2_SOURCE
)) == (REG_DEST
| REG2_SOURCE
)) {
191 if (op
== SLJIT_MOV_S16
)
192 return push_inst(compiler
, EXTSH
| S(src2
) | A(dst
));
193 return push_inst(compiler
, INS_CLEAR_LEFT(dst
, src2
, 16));
196 SLJIT_ASSERT(dst
== src2
);
198 return SLJIT_SUCCESS
;
201 SLJIT_ASSERT(src1
== TMP_REG1
);
203 return push_inst(compiler
, NOR
| RC(flags
) | S(src2
) | A(dst
) | B(src2
));
206 SLJIT_ASSERT(src1
== TMP_REG1
);
208 if ((flags
& (ALT_FORM1
| ALT_SIGN_EXT
)) == (ALT_FORM1
| ALT_SIGN_EXT
)) {
209 FAIL_IF(push_inst(compiler
, RLDI(TMP_REG2
, src2
, 32, 31, 1)));
210 FAIL_IF(push_inst(compiler
, NEG
| OE(ALT_SET_FLAGS
) | RC(ALT_SET_FLAGS
) | D(dst
) | A(TMP_REG2
)));
211 return push_inst(compiler
, RLDI(dst
, dst
, 32, 32, 0));
215 /* Setting XER SO is not enough, CR SO is also needed. */
216 return push_inst(compiler
, NEG
| OE((flags
& ALT_FORM1
) ? ALT_SET_FLAGS
: 0) | RC(flags
) | D(dst
) | A(src2
));
219 SLJIT_ASSERT(src1
== TMP_REG1
);
220 if (flags
& ALT_FORM1
)
221 return push_inst(compiler
, CNTLZW
| S(src2
) | A(dst
));
222 return push_inst(compiler
, CNTLZD
| S(src2
) | A(dst
));
225 if (flags
& ALT_FORM1
) {
226 if (flags
& ALT_SIGN_EXT
) {
227 FAIL_IF(push_inst(compiler
, RLDI(TMP_REG1
, src1
, 32, 31, 1)));
229 FAIL_IF(push_inst(compiler
, RLDI(TMP_REG2
, src2
, 32, 31, 1)));
232 /* Setting XER SO is not enough, CR SO is also needed. */
233 FAIL_IF(push_inst(compiler
, ADD
| OE(ALT_SET_FLAGS
) | RC(ALT_SET_FLAGS
) | D(dst
) | A(src1
) | B(src2
)));
234 if (flags
& ALT_SIGN_EXT
)
235 return push_inst(compiler
, RLDI(dst
, dst
, 32, 32, 0));
236 return SLJIT_SUCCESS
;
239 if (flags
& ALT_FORM2
) {
240 /* Flags does not set: BIN_IMM_EXTS unnecessary. */
241 SLJIT_ASSERT(src2
== TMP_REG2
);
243 if (flags
& ALT_FORM3
)
244 return push_inst(compiler
, ADDIS
| D(dst
) | A(src1
) | compiler
->imm
);
246 if (flags
& ALT_FORM4
) {
247 FAIL_IF(push_inst(compiler
, ADDIS
| D(dst
) | A(src1
) | (((compiler
->imm
>> 16) & 0xffff) + ((compiler
->imm
>> 15) & 0x1))));
251 return push_inst(compiler
, ADDI
| D(dst
) | A(src1
) | (compiler
->imm
& 0xffff));
253 if (flags
& ALT_FORM3
) {
254 SLJIT_ASSERT(src2
== TMP_REG2
);
256 return push_inst(compiler
, ADDIC
| D(dst
) | A(src1
) | compiler
->imm
);
258 if (!(flags
& ALT_SET_FLAGS
))
259 return push_inst(compiler
, ADD
| D(dst
) | A(src1
) | B(src2
));
261 if (flags
& ALT_FORM4
)
262 return push_inst(compiler
, ADDC
| RC(ALT_SET_FLAGS
) | D(dst
) | A(src1
) | B(src2
));
263 return push_inst(compiler
, ADD
| RC(flags
) | D(dst
) | A(src1
) | B(src2
));
267 return push_inst(compiler
, ADDE
| D(dst
) | A(src1
) | B(src2
));
270 if (flags
& ALT_FORM1
) {
271 if (flags
& ALT_FORM2
) {
272 FAIL_IF(push_inst(compiler
, CMPLI
| CRD(0 | ((flags
& ALT_SIGN_EXT
) ? 0 : 1)) | A(src1
) | compiler
->imm
));
273 if (!(flags
& ALT_FORM3
))
274 return SLJIT_SUCCESS
;
275 return push_inst(compiler
, ADDI
| D(dst
) | A(src1
) | (-compiler
->imm
& 0xffff));
277 FAIL_IF(push_inst(compiler
, CMPL
| CRD(0 | ((flags
& ALT_SIGN_EXT
) ? 0 : 1)) | A(src1
) | B(src2
)));
278 if (!(flags
& ALT_FORM3
))
279 return SLJIT_SUCCESS
;
280 return push_inst(compiler
, SUBF
| D(dst
) | A(src2
) | B(src1
));
283 if (flags
& ALT_FORM2
) {
284 if (flags
& ALT_SIGN_EXT
) {
285 FAIL_IF(push_inst(compiler
, RLDI(TMP_REG1
, src1
, 32, 31, 1)));
287 FAIL_IF(push_inst(compiler
, RLDI(TMP_REG2
, src2
, 32, 31, 1)));
290 /* Setting XER SO is not enough, CR SO is also needed. */
291 FAIL_IF(push_inst(compiler
, SUBF
| OE(ALT_SET_FLAGS
) | RC(ALT_SET_FLAGS
) | D(dst
) | A(src2
) | B(src1
)));
292 if (flags
& ALT_SIGN_EXT
)
293 return push_inst(compiler
, RLDI(dst
, dst
, 32, 32, 0));
294 return SLJIT_SUCCESS
;
297 if (flags
& ALT_FORM3
) {
298 /* Flags does not set: BIN_IMM_EXTS unnecessary. */
299 SLJIT_ASSERT(src2
== TMP_REG2
);
300 return push_inst(compiler
, SUBFIC
| D(dst
) | A(src1
) | compiler
->imm
);
303 if (flags
& ALT_FORM4
) {
304 if (flags
& ALT_FORM5
) {
305 SLJIT_ASSERT(src2
== TMP_REG2
);
306 return push_inst(compiler
, CMPI
| CRD(0 | ((flags
& ALT_SIGN_EXT
) ? 0 : 1)) | A(src1
) | compiler
->imm
);
308 return push_inst(compiler
, CMP
| CRD(0 | ((flags
& ALT_SIGN_EXT
) ? 0 : 1)) | A(src1
) | B(src2
));
311 if (!(flags
& ALT_SET_FLAGS
))
312 return push_inst(compiler
, SUBF
| D(dst
) | A(src2
) | B(src1
));
314 if (flags
& ALT_FORM5
)
315 return push_inst(compiler
, SUBFC
| RC(ALT_SET_FLAGS
) | D(dst
) | A(src2
) | B(src1
));
316 return push_inst(compiler
, SUBF
| RC(flags
) | D(dst
) | A(src2
) | B(src1
));
320 return push_inst(compiler
, SUBFE
| D(dst
) | A(src2
) | B(src1
));
323 if (flags
& ALT_FORM1
) {
324 SLJIT_ASSERT(src2
== TMP_REG2
);
325 return push_inst(compiler
, MULLI
| D(dst
) | A(src1
) | compiler
->imm
);
328 if (flags
& ALT_FORM2
)
329 return push_inst(compiler
, MULLW
| OE(flags
) | RC(flags
) | D(dst
) | A(src2
) | B(src1
));
330 return push_inst(compiler
, MULLD
| OE(flags
) | RC(flags
) | D(dst
) | A(src2
) | B(src1
));
333 if (flags
& ALT_FORM1
) {
334 SLJIT_ASSERT(src2
== TMP_REG2
);
335 return push_inst(compiler
, ANDI
| S(src1
) | A(dst
) | compiler
->imm
);
337 if (flags
& ALT_FORM2
) {
338 SLJIT_ASSERT(src2
== TMP_REG2
);
339 return push_inst(compiler
, ANDIS
| S(src1
) | A(dst
) | compiler
->imm
);
341 return push_inst(compiler
, AND
| RC(flags
) | S(src1
) | A(dst
) | B(src2
));
344 if (flags
& ALT_FORM1
) {
345 SLJIT_ASSERT(src2
== TMP_REG2
);
346 return push_inst(compiler
, ORI
| S(src1
) | A(dst
) | compiler
->imm
);
348 if (flags
& ALT_FORM2
) {
349 SLJIT_ASSERT(src2
== TMP_REG2
);
350 return push_inst(compiler
, ORIS
| S(src1
) | A(dst
) | compiler
->imm
);
352 if (flags
& ALT_FORM3
) {
353 SLJIT_ASSERT(src2
== TMP_REG2
);
354 FAIL_IF(push_inst(compiler
, ORI
| S(src1
) | A(dst
) | IMM(compiler
->imm
)));
355 return push_inst(compiler
, ORIS
| S(dst
) | A(dst
) | IMM(compiler
->imm
>> 16));
357 return push_inst(compiler
, OR
| RC(flags
) | S(src1
) | A(dst
) | B(src2
));
360 if (flags
& ALT_FORM1
) {
361 SLJIT_ASSERT(src2
== TMP_REG2
);
362 return push_inst(compiler
, XORI
| S(src1
) | A(dst
) | compiler
->imm
);
364 if (flags
& ALT_FORM2
) {
365 SLJIT_ASSERT(src2
== TMP_REG2
);
366 return push_inst(compiler
, XORIS
| S(src1
) | A(dst
) | compiler
->imm
);
368 if (flags
& ALT_FORM3
) {
369 SLJIT_ASSERT(src2
== TMP_REG2
);
370 FAIL_IF(push_inst(compiler
, XORI
| S(src1
) | A(dst
) | IMM(compiler
->imm
)));
371 return push_inst(compiler
, XORIS
| S(dst
) | A(dst
) | IMM(compiler
->imm
>> 16));
373 return push_inst(compiler
, XOR
| RC(flags
) | S(src1
) | A(dst
) | B(src2
));
376 if (flags
& ALT_FORM1
) {
377 SLJIT_ASSERT(src2
== TMP_REG2
);
378 if (flags
& ALT_FORM2
) {
379 compiler
->imm
&= 0x1f;
380 return push_inst(compiler
, RLWINM
| RC(flags
) | S(src1
) | A(dst
) | (compiler
->imm
<< 11) | ((31 - compiler
->imm
) << 1));
382 compiler
->imm
&= 0x3f;
383 return push_inst(compiler
, RLDI(dst
, src1
, compiler
->imm
, 63 - compiler
->imm
, 1) | RC(flags
));
385 return push_inst(compiler
, ((flags
& ALT_FORM2
) ? SLW
: SLD
) | RC(flags
) | S(src1
) | A(dst
) | B(src2
));
388 if (flags
& ALT_FORM1
) {
389 SLJIT_ASSERT(src2
== TMP_REG2
);
390 if (flags
& ALT_FORM2
) {
391 compiler
->imm
&= 0x1f;
392 return push_inst(compiler
, RLWINM
| RC(flags
) | S(src1
) | A(dst
) | (((32 - compiler
->imm
) & 0x1f) << 11) | (compiler
->imm
<< 6) | (31 << 1));
394 compiler
->imm
&= 0x3f;
395 return push_inst(compiler
, RLDI(dst
, src1
, 64 - compiler
->imm
, compiler
->imm
, 0) | RC(flags
));
397 return push_inst(compiler
, ((flags
& ALT_FORM2
) ? SRW
: SRD
) | RC(flags
) | S(src1
) | A(dst
) | B(src2
));
400 if (flags
& ALT_FORM1
) {
401 SLJIT_ASSERT(src2
== TMP_REG2
);
402 if (flags
& ALT_FORM2
) {
403 compiler
->imm
&= 0x1f;
404 return push_inst(compiler
, SRAWI
| RC(flags
) | S(src1
) | A(dst
) | (compiler
->imm
<< 11));
406 compiler
->imm
&= 0x3f;
407 return push_inst(compiler
, SRADI
| RC(flags
) | S(src1
) | A(dst
) | ((compiler
->imm
& 0x1f) << 11) | ((compiler
->imm
& 0x20) >> 4));
409 return push_inst(compiler
, ((flags
& ALT_FORM2
) ? SRAW
: SRAD
) | RC(flags
) | S(src1
) | A(dst
) | B(src2
));
413 return SLJIT_SUCCESS
;
416 static SLJIT_INLINE sljit_s32
emit_const(struct sljit_compiler
*compiler
, sljit_s32 reg
, sljit_sw init_value
)
418 FAIL_IF(push_inst(compiler
, ADDIS
| D(reg
) | A(0) | IMM(init_value
>> 48)));
419 FAIL_IF(push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(init_value
>> 32)));
420 FAIL_IF(PUSH_RLDICR(reg
, 31));
421 FAIL_IF(push_inst(compiler
, ORIS
| S(reg
) | A(reg
) | IMM(init_value
>> 16)));
422 return push_inst(compiler
, ORI
| S(reg
) | A(reg
) | IMM(init_value
));
425 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_jump_addr(sljit_uw addr
, sljit_uw new_target
, sljit_sw executable_offset
)
427 sljit_ins
*inst
= (sljit_ins
*)addr
;
429 inst
[0] = (inst
[0] & 0xffff0000) | ((new_target
>> 48) & 0xffff);
430 inst
[1] = (inst
[1] & 0xffff0000) | ((new_target
>> 32) & 0xffff);
431 inst
[3] = (inst
[3] & 0xffff0000) | ((new_target
>> 16) & 0xffff);
432 inst
[4] = (inst
[4] & 0xffff0000) | (new_target
& 0xffff);
433 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
434 SLJIT_CACHE_FLUSH(inst
, inst
+ 5);
437 SLJIT_API_FUNC_ATTRIBUTE
void sljit_set_const(sljit_uw addr
, sljit_sw new_constant
, sljit_sw executable_offset
)
439 sljit_ins
*inst
= (sljit_ins
*)addr
;
441 inst
[0] = (inst
[0] & 0xffff0000) | ((new_constant
>> 48) & 0xffff);
442 inst
[1] = (inst
[1] & 0xffff0000) | ((new_constant
>> 32) & 0xffff);
443 inst
[3] = (inst
[3] & 0xffff0000) | ((new_constant
>> 16) & 0xffff);
444 inst
[4] = (inst
[4] & 0xffff0000) | (new_constant
& 0xffff);
445 inst
= (sljit_ins
*)SLJIT_ADD_EXEC_OFFSET(inst
, executable_offset
);
446 SLJIT_CACHE_FLUSH(inst
, inst
+ 5);