1/*
2 *    Stack-less Just-In-Time compiler
3 *
4 *    Copyright 2009-2012 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
29static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w 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(ZERO_REG) | 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#define INS_CLEAR_LEFT(dst, src, from) \
42	(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
43
44static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags,
45	int dst, int src1, int src2)
46{
47	switch (op) {
48	case SLJIT_ADD:
49		if (flags & ALT_FORM1) {
50			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
51			SLJIT_ASSERT(src2 == TMP_REG2);
52			return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
53		}
54		if (flags & ALT_FORM2) {
55			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
56			SLJIT_ASSERT(src2 == TMP_REG2);
57			return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
58		}
59		if (flags & ALT_FORM3) {
60			SLJIT_ASSERT(src2 == TMP_REG2);
61			return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
62		}
63		if (flags & ALT_FORM4) {
64			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
65			FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
66			return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
67		}
68		if (!(flags & ALT_SET_FLAGS))
69			return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
70		return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
71
72	case SLJIT_ADDC:
73		if (flags & ALT_FORM1) {
74			FAIL_IF(push_inst(compiler, MFXER | S(0)));
75			FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
76			return push_inst(compiler, MTXER | S(0));
77		}
78		return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
79
80	case SLJIT_SUB:
81		if (flags & ALT_FORM1) {
82			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
83			SLJIT_ASSERT(src2 == TMP_REG2);
84			return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
85		}
86		if (flags & (ALT_FORM2 | ALT_FORM3)) {
87			SLJIT_ASSERT(src2 == TMP_REG2);
88			if (flags & ALT_FORM2)
89				FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm));
90			if (flags & ALT_FORM3)
91				return push_inst(compiler, CMPLI | CRD(4) | A(src1) | compiler->imm);
92			return SLJIT_SUCCESS;
93		}
94		if (flags & (ALT_FORM4 | ALT_FORM5)) {
95			if (flags & ALT_FORM4)
96				FAIL_IF(push_inst(compiler, CMPL | CRD(4) | A(src1) | B(src2)));
97			if (flags & ALT_FORM5)
98				FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2)));
99			return SLJIT_SUCCESS;
100		}
101		if (!(flags & ALT_SET_FLAGS))
102			return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
103		if (flags & ALT_FORM6)
104			FAIL_IF(push_inst(compiler, CMPL | CRD(4) | A(src1) | B(src2)));
105		return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
106
107	case SLJIT_SUBC:
108		if (flags & ALT_FORM1) {
109			FAIL_IF(push_inst(compiler, MFXER | S(0)));
110			FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
111			return push_inst(compiler, MTXER | S(0));
112		}
113		return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
114
115	case SLJIT_MUL:
116		if (flags & ALT_FORM1) {
117			SLJIT_ASSERT(src2 == TMP_REG2);
118			return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
119		}
120		return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
121
122	case SLJIT_AND:
123		if (flags & ALT_FORM1) {
124			SLJIT_ASSERT(src2 == TMP_REG2);
125			return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
126		}
127		if (flags & ALT_FORM2) {
128			SLJIT_ASSERT(src2 == TMP_REG2);
129			return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
130		}
131		return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
132
133	case SLJIT_OR:
134		if (flags & ALT_FORM1) {
135			SLJIT_ASSERT(src2 == TMP_REG2);
136			return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
137		}
138		if (flags & ALT_FORM2) {
139			SLJIT_ASSERT(src2 == TMP_REG2);
140			return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
141		}
142		if (flags & ALT_FORM3) {
143			SLJIT_ASSERT(src2 == TMP_REG2);
144			FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
145			return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
146		}
147		return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
148
149	case SLJIT_XOR:
150		if (flags & ALT_FORM1) {
151			SLJIT_ASSERT(src2 == TMP_REG2);
152			return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
153		}
154		if (flags & ALT_FORM2) {
155			SLJIT_ASSERT(src2 == TMP_REG2);
156			return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
157		}
158		if (flags & ALT_FORM3) {
159			SLJIT_ASSERT(src2 == TMP_REG2);
160			FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
161			return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
162		}
163		return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
164
165	case SLJIT_SHL:
166		if (flags & ALT_FORM1) {
167			SLJIT_ASSERT(src2 == TMP_REG2);
168			compiler->imm &= 0x1f;
169			return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
170		}
171		return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
172
173	case SLJIT_LSHR:
174		if (flags & ALT_FORM1) {
175			SLJIT_ASSERT(src2 == TMP_REG2);
176			compiler->imm &= 0x1f;
177			return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
178		}
179		return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
180
181	case SLJIT_ASHR:
182		if (flags & ALT_FORM1) {
183			SLJIT_ASSERT(src2 == TMP_REG2);
184			compiler->imm &= 0x1f;
185			return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
186		}
187		return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
188
189	case SLJIT_MOV:
190	case SLJIT_MOV_UI:
191	case SLJIT_MOV_SI:
192		SLJIT_ASSERT(src1 == TMP_REG1);
193		if (dst != src2)
194			return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
195		return SLJIT_SUCCESS;
196
197	case SLJIT_MOV_UB:
198	case SLJIT_MOV_SB:
199		SLJIT_ASSERT(src1 == TMP_REG1);
200		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
201			if (op == SLJIT_MOV_SB)
202				return push_inst(compiler, EXTSB | S(src2) | A(dst));
203			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
204		}
205		else if ((flags & REG_DEST) && op == SLJIT_MOV_SB)
206			return push_inst(compiler, EXTSB | S(src2) | A(dst));
207		else if (dst != src2)
208			SLJIT_ASSERT_STOP();
209		return SLJIT_SUCCESS;
210
211	case SLJIT_MOV_UH:
212	case SLJIT_MOV_SH:
213		SLJIT_ASSERT(src1 == TMP_REG1);
214		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
215			if (op == SLJIT_MOV_SH)
216				return push_inst(compiler, EXTSH | S(src2) | A(dst));
217			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
218		}
219		else if (dst != src2)
220			SLJIT_ASSERT_STOP();
221		return SLJIT_SUCCESS;
222
223	case SLJIT_NOT:
224		SLJIT_ASSERT(src1 == TMP_REG1);
225		return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
226
227	case SLJIT_NEG:
228		SLJIT_ASSERT(src1 == TMP_REG1);
229		return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
230
231	case SLJIT_CLZ:
232		SLJIT_ASSERT(src1 == TMP_REG1);
233		return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
234	}
235
236	SLJIT_ASSERT_STOP();
237	return SLJIT_SUCCESS;
238}
239
240static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int reg, sljit_w init_value)
241{
242	FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
243	return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
244}
245
246SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
247{
248	sljit_ins *inst = (sljit_ins*)addr;
249
250	inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
251	inst[1] = (inst[1] & 0xffff0000) | (new_addr & 0xffff);
252	SLJIT_CACHE_FLUSH(inst, inst + 2);
253}
254
255SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant)
256{
257	sljit_ins *inst = (sljit_ins*)addr;
258
259	inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
260	inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
261	SLJIT_CACHE_FLUSH(inst, inst + 2);
262}
263